如何象杀毒软件那样实时监控文件的删除、拷贝,修改等操作? ( 积分: 200 )

  • 主题发起人 主题发起人 wh77
  • 开始时间 开始时间
W

wh77

Unregistered / Unconfirmed
GUEST, unregistred user!
如何象杀毒软件那样实时监控文件的删除、拷贝,修改等操作并且能够在能够记录这些操作的同时控制其程序的删除、拷贝,修改等操作(在进行这些操作的前能够询问用户是否进行这些操作用户许可后在进行这些操作)
实现这些功能是不是要钩子操作还是要WINDOWSAPI还是要文件过滤驱动程序
有没有这方面的资料,例子,源程序

谢谢
 
帮顶,共同学习!
 
//我来赚这200分
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,shlobj,Activex;

const
SHCNE_RENAMEITEM = $1;
SHCNE_CREATE = $2;
SHCNE_DELETE = $4;
SHCNE_MKDIR = $8;
SHCNE_RMDIR = $10;
SHCNE_MEDIAINSERTED = $20;
SHCNE_MEDIAREMOVED = $40;
SHCNE_DRIVEREMOVED = $80;
SHCNE_DRIVEADD = $100;
SHCNE_NETSHARE = $200;
SHCNE_NETUNSHARE = $400;
SHCNE_ATTRIBUTES = $800;
SHCNE_UPDATEDIR = $1000;
SHCNE_UPDATEITEM = $2000;
SHCNE_SERVERDISCONNECT = $4000;
SHCNE_UPDATEIMAGE = $8000;
SHCNE_DRIVEADDGUI = $10000;
SHCNE_RENAMEFOLDER = $20000;
SHCNE_FREESPACE = $40000;
SHCNE_ASSOCCHANGED = $8000000;
SHCNE_DISKEVENTS = $2381F;
SHCNE_GLOBALEVENTS = $C0581E0;
SHCNE_ALLEVENTS = $7FFFFFFF;
SHCNE_INTERRUPT = $80000000;

SHCNF_IDLIST = 0; // LPITEMIDLIST
SHCNF_PATHA = $1; // path name
SHCNF_PRINTERA = $2; // printer friendly name
SHCNF_DWORD = $3; // DWORD
SHCNF_PATHW = $5; // path name
SHCNF_PRINTERW = $6; // printer friendly name
SHCNF_TYPE = $FF;

SHCNF_FLUSH = $1000;

SHCNF_FLUSHNOWAIT = $2000;
SHCNF_PATH = SHCNF_PATHW;
SHCNF_PRINTER = SHCNF_PRINTERW;

WM_SHNOTIFY = $401;
NOERROR = 0;

type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure WMShellReg(var Message:TMessage);message WM_SHNOTIFY;
public
{ Public declarations }
end;

type PSHNOTIFYSTRUCT=^SHNOTIFYSTRUCT;
SHNOTIFYSTRUCT = record
dwItem1 : PItemIDList;
dwItem2 : PItemIDList;
end;

Type PSHFileInfoByte=^SHFileInfoByte;
_SHFileInfoByte = record
hIcon :Integer;
iIcon :Integer;
dwAttributes : Integer;
szDisplayName : array [0..259] of char;
szTypeName : array [0..79] of char;
end;
SHFileInfoByte=_SHFileInfoByte;

Type PIDLSTRUCT = ^IDLSTRUCT;
_IDLSTRUCT = record
pidl : PItemIDList;
bWatchSubFolders : Integer;
end;
IDLSTRUCT =_IDLSTRUCT;


function SHNotify_Register(hWnd : Integer) : Bool;
function SHNotify_UnRegister:Bool;
function SHEventName(strPath1,strPath2:string;lParam:Integer):string;

Function SHChangeNotifyDeregister(hNotify:integer):integer;stdcall;
external 'Shell32.dll' index 4;
Function SHChangeNotifyRegister(hWnd,uFlags,dwEventID,uMSG,cItems:LongWord;
lpps:PIDLSTRUCT):integer;stdcall;external 'Shell32.dll' index 2;
Function SHGetFileInfoPidl(pidl : PItemIDList;
dwFileAttributes : Integer;
psfib : PSHFILEINFOBYTE;
cbFileInfo : Integer;
uFlags : Integer):Integer;stdcall;
external 'Shell32.dll' name 'SHGetFileInfoA';

var
Form1: TForm1;
m_hSHNotify:Integer;
m_pidlDesktop : PItemIDList;

implementation

{$R *.DFM}

function SHEventName(strPath1,strPath2:string;lParam:Integer):string;
var
sEvent:String;
begin
case lParam of //根据参数设置提示消息
SHCNE_RENAMEITEM: sEvent := '重命名文件'+strPath1+'为'+strpath2;
SHCNE_CREATE: sEvent := '建立文件 文件名:'+strPath1;
SHCNE_DELETE: sEvent := '删除文件 文件名:'+strPath1;
SHCNE_MKDIR: sEvent := '新建目录 目录名:'+strPath1;
SHCNE_RMDIR: sEvent := '删除目录 目录名:'+strPath1;
SHCNE_MEDIAINSERTED: sEvent := strPath1+'中插入可移动存储介质';
SHCNE_MEDIAREMOVED: sEvent := strPath1+'中移去可移动存储介质'+strPath1+' '+strpath2;
SHCNE_DRIVEREMOVED: sEvent := '移去驱动器'+strPath1;
SHCNE_DRIVEADD: sEvent := '添加驱动器'+strPath1;
SHCNE_NETSHARE: sEvent := '改变目录'+strPath1+'的共享属性';

SHCNE_ATTRIBUTES: sEvent := '改变文件目录属性 文件名'+strPath1;
SHCNE_UPDATEDIR: sEvent := '更新目录'+strPath1;
SHCNE_UPDATEITEM: sEvent := '更新文件 文件名:'+strPath1;
SHCNE_SERVERDISCONNECT: sEvent := '断开与服务器的连接'+strPath1+' '+strpath2;
SHCNE_UPDATEIMAGE: sEvent := 'SHCNE_UPDATEIMAGE';
SHCNE_DRIVEADDGUI: sEvent := 'SHCNE_DRIVEADDGUI';
SHCNE_RENAMEFOLDER: sEvent := '重命名文件夹'+strPath1+'为'+strpath2;
SHCNE_FREESPACE: sEvent := '磁盘空间大小改变';
SHCNE_ASSOCCHANGED: sEvent := '改变文件关联';
else
sEvent:='未知操作'+IntToStr(lParam);
end;
Result:=sEvent;
end;

function SHNotify_Register(hWnd : Integer) : Bool;
var
ps:PIDLSTRUCT;
begin
{$R-}
Result:=False;
If m_hSHNotify = 0 then begin
if SHGetSpecialFolderLocation(0, CSIDL_DESKTOP,
m_pidlDesktop)<> NOERROR then
Form1.close;
if Boolean(m_pidlDesktop) then begin
new(ps);
ps.bWatchSubFolders := 1;
ps.pidl := m_pidlDesktop;

// 利用SHChangeNotifyRegister函数注册系统消息处理
m_hSHNotify := SHChangeNotifyRegister(hWnd, (SHCNF_TYPE Or SHCNF_IDLIST),
(SHCNE_ALLEVENTS Or SHCNE_INTERRUPT),
WM_SHNOTIFY, 1, ps);
Result := Boolean(m_hSHNotify);
end
Else
// 如果出现错误就使用 CoTaskMemFree函数来释放句柄
CoTaskMemFree(m_pidlDesktop);
End;
{$R+}
end;

function SHNotify_UnRegister:Bool;
begin
Result:=False;
If Boolean(m_hSHNotify) Then
//取消系统消息监视,同时释放桌面的Pidl
If Boolean(SHChangeNotifyDeregister(m_hSHNotify)) Then begin
{$R-}
m_hSHNotify := 0;
CoTaskMemFree(m_pidlDesktop);
Result := True;
{$R-}
End;
end;

procedure TForm1.WMShellReg(var Message:TMessage); //系统消息处理函数
var
strPath1,strPath2:String;
charPath:array[0..259]of char;
pidlItem:PSHNOTIFYSTRUCT;
begin
pidlItem:=PSHNOTIFYSTRUCT(Message.wParam);
//获得系统消息相关得路径
SHGetPathFromIDList(pidlItem.dwItem1,charPath);
strPath1:=charPath;
SHGetPathFromIDList(pidlItem.dwItem2,charPath);
strPath2:=charPath;

Memo1.Lines.Add(SHEvEntName(strPath1,strPath2,Message.lParam)+chr(13)+chr(10));
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//在程序退出的同时删除监视
if Boolean(m_pidlDesktop) then
SHNotify_Unregister;
end;

procedure TForm1.Button1Click(Sender: TObject); //Button1的Click消息
begin
m_hSHNotify:=0;
if SHNotify_Register(Form1.Handle) then begin //注册Shell监视
ShowMessage('Shell监视程序成功注册');
Button1.Enabled := False;
end
else
ShowMessage('Shell监视程序注册失败');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption := '打开监视';
end;

end.
 
哈哈,网中戏大哥,受教了,好快啊
我这有个C的,贴上吧
FileSystemWatcher.cpp
////////////////////////////////////////////
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include "FileSystemWatcher.h"

using namespace std;

void __stdcall MyDeal( ACTION act, std::string filename1, std::string filename2 )
{
switch( act )
{
case ADDED:
cout << "Added - " << filename1 << endl;
break;
case REMOVED:
cout << "Removed - " << filename1 << endl;
break;
case MODIFIED:
cout << "Modified - " << filename1 << endl;
break;
case RENAMED:
cout << "Rename - " << filename1 << " " << filename2 << endl;
break;
}
}

void main()
{
FileSystemWatcher a;
a.Run( "D://", MyDeal );

cout << "Watch D://" << endl;
cout << "Press <q> to quit." << endl;
while(getch()!='q');

a.Close();
}


/////////////////////////////////////
FileSystemWatcher.H
/////////////////////////////////////
#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <string>
#include <cassert>

enum ACTION { ADDED=1, REMOVED=2, MODIFIED=3, RENAMED=4 };
class FileSystemWatcher
{
public:
typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, std::string filename1, std::string filename2 );

bool Run( std::string path, LPDEALFUNCTION dealfun )
{
WatchedDir = path;
DealFun = dealfun;

DWORD ThreadId;
hThread=CreateThread( NULL,0,Routine,this,0,&ThreadId );
return NULL!=hThread;
}
void Close()
{
if( NULL != hThread )
{
TerminateThread( hThread, 0 );
hThread = NULL;
}
if( INVALID_HANDLE_VALUE != hDir )
{
CloseHandle( hDir );
hDir = INVALID_HANDLE_VALUE;
}
}
FileSystemWatcher() : DealFun(NULL), hThread(NULL), hDir(INVALID_HANDLE_VALUE)
{
}
~FileSystemWatcher()
{
Close();
}

private:
std::string WatchedDir;
LPDEALFUNCTION DealFun;
HANDLE hThread;
HANDLE hDir;
private:
FileSystemWatcher( const FileSystemWatcher& );
FileSystemWatcher operator=( const FileSystemWatcher );
private:
static DWORD WINAPI Routine( LPVOID lParam )
{
FileSystemWatcher* obj = (FileSystemWatcher*)lParam;

obj->hDir = CreateFile(
obj->WatchedDir.c_str(),
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if( INVALID_HANDLE_VALUE == obj->hDir ) return false;

char buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH) ];
FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
DWORD BytesReturned;
while(true)
{
if( ReadDirectoryChangesW( obj->hDir,
pNotify,
sizeof(buf),
true,
FILE_NOTIFY_CHANGE_FILE_NAME|
FILE_NOTIFY_CHANGE_DIR_NAME|
FILE_NOTIFY_CHANGE_ATTRIBUTES|
FILE_NOTIFY_CHANGE_SIZE|
FILE_NOTIFY_CHANGE_LAST_WRITE|
FILE_NOTIFY_CHANGE_LAST_ACCESS|
FILE_NOTIFY_CHANGE_CREATION|
FILE_NOTIFY_CHANGE_SECURITY,
&BytesReturned,
NULL,
NULL ) )
{
char tmp[MAX_PATH], str1[MAX_PATH], str2[MAX_PATH];
memset( tmp, 0, sizeof(tmp) );
WideCharToMultiByte( CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL );
strcpy( str1, tmp );

if( 0 != pNotify->NextEntryOffset )
{
PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
memset( tmp, 0, sizeof(tmp) );
WideCharToMultiByte( CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL );
strcpy( str2, tmp );
}

obj->DealFun( (ACTION)pNotify->Action, str1, str2 );
}
else
{
break;
}
}

return 0;
}
};
另外在VS2005中内置了FileSystemWatcher 类。可以直接调用,详看msdn。
 
ReadDirectoryChanges只能监控到目录的变化。网中戏的自己是否试过呢?尤其是对于excel文档,一打开还没动就提示文件被修改。一个变化还会引起多次通知。你自己试过就知道的。
 
网中戏的代码我以前试过
可以是可以
不过只是Shell监控
楼上说的那种情况是没有办法监控到
那样的情况
我想可以通过 hook api来实现
比如hook createfile等等几个API 就可以监控的到
 
通过Api Hook有一定的风险,很多的杀毒软件都会把你的东西当病毒给处理掉。
 
网中戏大哥
谢谢你的回复你的代码我早已经有了而且已经编译成功但是这段代码不能能够显示文件被修改的情况而且不能实现在进行这些操作的前能够询问用户是否进行这些操作用户许可后在进行这些操作的功能
谢谢
 
在D7Samples下面有个
ShellChangeNotifier
可以去看下

不过想绝对监控不是那么简单的
有个软件FileMon可以下来看看
 
呵呵 我看了FILEMON的原代码 是VC++的驱动级的程序 有没有DELPHI的有关程序是不是DELPHI不能够编系统有关的程序,
编有关系统方面的程序只有使用VC吗.
 
可以考虑用ICopyHook接口编写Copy-hook handle
CopyCallBack方法的定义如下:
UINT CopyCallback(
HWND hwnd, file://Handle of the parent window for displaying UI objects
UINT wFunc, file://Operation to perform.
UINT wFlags, file://Flags that control the operation
LPCSTR pszSrcFile, file://Pointer to the source file
DWORD dwSrcAttribs, file://Source file attributes
LPCSTR pszDestFile, file://Pointer to the destination file
DWORD dwDestAttribs file://Destination file attributes
);
其中的参数hwnd是一个窗口句柄,Copy-hook handle以此为父窗口。参数wFunc指定要被执行的操作,其取值为下表中所列之一:
常量 取值 含义
FO_COPY $2 复制由pszSrcFile指定的文件到由pszDestFile指定的位置。
FO_DELETE $3 删除由pszSrcFile指定的文件。
FO_MOVE $1 移动由pszSrcFile指定的文件到由pszDestFile指定的位置。
FO_RENAME $4 重命名由pszSrcFile指定的文件到由pszDestFile指定的文件名。
PO_DELETE $13 删除pszSrcFile指定的打印机。
PO_PORTCHANGE $20 改变打印机端口。PszSrcFile和pszDestFile为两个以Null结尾的字符串,分别指定当前和新的打印机端口名。
PO_RENAME $14 重命名由pszSrcFile指定的打印机端口。
PO_REN_PORT $34 PO_RENAME和PO_PORTCHANGE的组合。

参数wFlags指定操作的标志;参数pszSrcFile和pszDestFile指定源文件夹和目标文件夹。参数dwSrcAttribs和dwDesAttribs指定源文件夹和目标文件夹的属性。函数返回值可以为IDYES、IDNO和IDCANCEL。分别指示Windows外壳允许操作、阻止操作,但是其他操作继续、阻止当前操作,取消为执行的操作。

详细察看 http://hack.bluebing.cn/Html/bcpd/hksj/1153120060918105828.html
里面有个源代码。
DELPHI我没有试验过
不过BCB下用过还不错。
 
顶顶顶顶顶顶顶顶顶顶顶
 
smsman
呵呵 谢谢 我试试
 
smsman
代码只是对应文件夹有效 对应文件没有效果
 
shell编程
delphi深度探索里边好像提到过,自己去看看吧
 
要有效地做到,自然就只能写驱动了。
 
也许只有作驱动编程了
 
晕...这里的好像个个都是高手啊.......学习ing...
 
后退
顶部