在WIN32下用DELPHI偵測目錄變化,可用WIN32提供的文件改變通知API來完成。FindFirstChangeNotification, FindNextChangeNotification,FindCloseChangeNotification。 在應用程序中調用這些函數時,產生一個監控這個變化的句柄,可用WAIT函數集來等待這個變化。這樣,當監控程序運行時,可以達到監控文件變化的動作。更進一步,可把此程序做成一個狀態區圖標(TRAY)來完成監控。
Windows在刪除、復制、移動、訪問文件時并不發送消息,當然截獲不到。要截取這些操作過程的唯一辦法就是截獲API,這又需要你編寫Vxd程序了,殺毒軟件都是這樣作的。你注意一下殺毒軟件一般都帶有一個vxd程序。光有vxd還不行,還需截獲文件API。還有另外一個辦法,就是CIH病毒采用的辦法,直接跳到系統零層去操作。具體辦法如下: 一、SIDT指令( 將中斷描述符表寄存器IDTR--64位寬,16~47Bit存有中斷描述符表IDT基地址--的內容存入指定地址單元)不是特權指令,就是說我們可以在Ring3下執行該指令,獲得IDT的基地址,從而修改IDT,增加一個中斷門安置我們的中斷服務,一旦Ring3程序中產生此中斷,VMM就會調用此中斷服務程序,而此中斷服務程序就運行在Ring0下了。這一點與在DOS下非常相似。
二、要實現對系統中所有文件I/O操作的實時監視,還要用到另一種關鍵技-FileHooking,通過掛接一個處理函數,截獲所有與文件I/O操作有關的系 統調用。Windows9x使用32位保護模式可安裝文件系統(IFS),由可安裝文件系統管理器(IFSManager)協調對文件系統和設備的訪問,它接收以Win32API函數調用形式向系統發出的文件I/O請求,再將請求轉給文件系統驅動程序FSD,由它調用低級別的IOS系統實現最終訪問。每個文件I/OAPI調用都有一個特定的FSD函數與之對應,IFSManager負責完成由API到FSD的參數裝配工作,在完成文件I/OAPI函數參數的裝配之后轉相應FSD執行之前,它會調用一個稱為FileSystemApiHookFunction的Hooker函數。通過安裝自己的Hooker函數,就可以截獲系統內所有對文件I/O的API調用,從而實現實時監控。 ========================================= procedure TForm1.Button2Click(Sender: TObject); begin {establish a notification for file name changes on the selected directory} NotificationHandle := FindFirstChangeNotification(PChar(DirectoryListBox1.Directory), FALSE,FILE_NOTIFY_CHANGE_FILE_NAME); {if the notification was set up correctly, modify some UI elements...} if (NotificationHandle <> INVALID_HANDLE_VALUE) then begin Button1.Enabled := TRUE; Button2.Enabled := FALSE; end else begin {...otherwise indicate that there was an error} ShowMessage('There was an error setting the notification'); Exit; end; end;
procedure TForm1.Button1Click(Sender: TObject); var dwResult: DWORD; // holds the result of waiting on the notification Waiting: Boolean; // loop control variable begin {setup the loop control for a continuous loop} Waiting := TRUE; {indicate that the application is waiting for the change notification to fire} Button1.Enabled := FALSE; StatusBar1.SimpleText := 'Now waiting for a filename change'; Application.ProcessMessages; {enter the loop} while Waiting do begin {at this point, the application is suspended until the notification object is signaled that a filename change has occured in the selected directory (this includes file deletions)} dwResult := WaitForSingleObject(NotificationHandle,INFINITE); if (dwResult = WAIT_OBJECT_0) then
begin {indicate that the notification object was signaled} ShowMessage('The selected directory signaled a filename change');
{query the user to see if they wish to continue monitoring this directory} if Application.MessageBox('Do you wish to continue monitoring this directory?', 'Continue?', MB_ICONQUESTION or MB_YESNO) = IDYES then
{if the user wishes to continue monitoring the directory, reset the notification object and continue the loop...} FindNextChangeNotification(NotificationHandle) else {...otherwise break out of the loop} Waiting := FALSE; end; end;
{close the notification object} FindCloseChangeNotification(NotificationHandle);
{reset UI elements}
Button1.Enabled := FALSE; Button2.Enabled := TRUE; StatusBar1.SimpleText := ''; FileListBox1.Update; end; =========================================== 下面是一個監視的控件: unit dirnotify;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type EDirNotificationError = class(Exception);
TDirNotify = class; TNotifyFilter = (nfFileName, nfDirName, nfAttributes, nfSize, nfLastWrite, nfSecurity); TNotifyFilters = set of TNotifyFilter;
TNotificationThread = class(TThread) Owner: TDirNotify; procedure Execute; override; procedure DoChange; end;
TDirNotify = class(TComponent) private FEnabled: Boolean; FOnChange: TNotifyEvent; FNotificationThread: TNotificationThread; FPath: String; FWatchSubTree: Boolean; FFilter: TNotifyFilters;
procedure SetEnabled( Value: Boolean ); procedure SetOnChange( Value: TNotifyEvent ); procedure SetPath( Value: String ); procedure SetWatchSubTree( Value: Boolean ); procedure SetFilter( Value: TNotifyFilters );
procedure RecreateThread;
protected procedure Change; procedure Loaded; override;
public constructor Create(AOwner: TComponent); override; destructor Destroy; override;
published property Enabled: Boolean read FEnabled write SetEnabled default True; property OnChange: TNotifyEvent read FOnChange write SetOnChange; property Path: String read FPath write SetPath; property WatchSubTree: Boolean read FWatchSubTree write SetWatchSubTree; property Filter: TNotifyFilters read FFilter write SetFilter default [nfFileName, nfDirName, nfAttributes, nfLastWrite, nfSecurity]; end;
procedure Register;
implementation
const LASTERRORTEXTLENGTH = 500;
var LastErrorText: array [0..LASTERRORTEXTLENGTH] of char;
function GetLastErrorText: PChar; begin FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, nil, GetLastError, 0, LastErrorText, LASTERRORTEXTLENGTH, nil ); Result := LastErrorText; end;
procedure TNotificationThread.Execute; var h: THandle; nf: Longint; wst: LongBool; begin nf := 0; if (nfFileName in Owner.Filter) then nf := FILE_NOTIFY_CHANGE_FILE_NAME; if (nfDirName in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_DIR_NAME; if (nfAttributes in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_ATTRIBUTES; if (nfSize in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_SIZE; if (nfLastWrite in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_LAST_WRITE; if (nfSecurity in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_SECURITY;
// yeahh, this one is stupid but Win98 malfunctions in any other value than 0 or 1 if Owner.FWatchSubTree then wst := Longbool(1) else wst := Longbool(0);
h := FindFirstChangeNotification( Pointer(Owner.Path), wst, nf ); if (h = INVALID_HANDLE_VALUE) then raise EDirNotificationError.Create( GetLastErrorText );
repeat if (WaitForSingleObject( h, 1000 ) = WAIT_OBJECT_0) then begin Synchronize(DoChange);
if not FindNextChangeNotification( h ) then raise EDirNotificationError.Create( GetLastErrorText ); end; until Terminated; end;
procedure TNotificationThread.DoChange; begin Owner.Change; end;
constructor TDirNotify.Create(AOwner: TComponent); begin inherited Create(AOwner);
FEnabled := True; FFilter := [nfFileName]; end;
destructor TDirNotify.Destroy; begin FNotificationThread.Free; inherited Destroy; end;
procedure TDirNotify.Loaded; begin inherited;
RecreateThread; end;
procedure TDirNotify.SetEnabled(Value: Boolean); begin if Value <> FEnabled then begin FEnabled := Value;
RecreateThread; end; end;
procedure TDirNotify.SetPath( Value: String ); begin if Value <> FPath then begin FPath := Value; RecreateThread; end; end;
procedure TDirNotify.SetWatchSubTree( Value: Boolean ); begin if Value <> FWatchSubTree then begin FWatchSubTree := Value; RecreateThread; end; end;
procedure TDirNotify.SetFilter( Value: TNotifyFilters ); begin if Value <> FFilter then begin FFilter := Value; RecreateThread; end; end;
procedure TDirNotify.SetOnChange(Value: TNotifyEvent); begin FOnChange := Value; end;
procedure TDirNotify.Change; begin if Assigned(FOnChange) then FOnChange(Self); end;
procedure TDirNotify.RecreateThread; begin // destroy thread FNotificationThread.Free; FNotificationThread := nil;
if FEnabled and not(csDesigning in ComponentState) and not(csLoading in ComponentState) and (FPath <> '') then begin // create thread FNotificationThread := TNotificationThread.Create(True); FNotificationThread.Owner := self; FNotificationThread.Resume; end; end;
procedure Register; begin RegisterComponents('System', [TDirNotify]); end;
end.
|