實(shí)時(shí)偵測(cè)目錄中文件變化
發(fā)表時(shí)間:2023-08-08 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]在WIN32下用DELPHI偵測(cè)目錄變化,可用WIN32提供的文件改變通知API來完成。FindFirstChangeNotification, FindNextChangeNotification...
在WIN32下用DELPHI偵測(cè)目錄變化,可用WIN32提供的文件改變通知API來完成。FindFirstChangeNotification, FindNextChangeNotification,F(xiàn)indCloseChangeNotification。
在應(yīng)用程序中調(diào)用這些函數(shù)時(shí),產(chǎn)生一個(gè)監(jiān)控這個(gè)變化的句柄,可用WAIT函數(shù)集來等待這個(gè)變化。這樣,當(dāng)監(jiān)控程序運(yùn)行時(shí),可以達(dá)到監(jiān)控文件變化的動(dòng)作。更進(jìn)一步,可把此程序做成一個(gè)狀態(tài)區(qū)圖標(biāo)(TRAY)來完成監(jiān)控。
Windows在刪除、復(fù)制、移動(dòng)、訪問文件時(shí)并不發(fā)送消息,當(dāng)然截獲不到。要截取這些操作過程的唯一辦法就是截獲API,這又需要你編寫Vxd程序了,殺毒軟件都是這樣作的。你注意一下殺毒軟件一般都帶有一個(gè)vxd程序。光有vxd還不行,還需截獲文件API。還有另外一個(gè)辦法,就是CIH病毒采用的辦法,直接跳到系統(tǒng)零層去操作。具體辦法如下:
一、SIDT指令( 將中斷描述符表寄存器IDTR--64位寬,16~47Bit存有中斷描述符表IDT基地址--的內(nèi)容存入指定地址單元)不是特權(quán)指令,就是說我們可以在Ring3下執(zhí)行該指令,獲得IDT的基地址,從而修改IDT,增加一個(gè)中斷門安置我們的中斷服務(wù),一旦Ring3程序中產(chǎn)生此中斷,VMM就會(huì)調(diào)用此中斷服務(wù)程序,而此中斷服務(wù)程序就運(yùn)行在Ring0下了。這一點(diǎn)與在DOS下非常相似。
二、要實(shí)現(xiàn)對(duì)系統(tǒng)中所有文件I/O操作的實(shí)時(shí)監(jiān)視,還要用到另一種關(guān)鍵技-FileHooking,通過掛接一個(gè)處理函數(shù),截獲所有與文件I/O操作有關(guān)的系 統(tǒng)調(diào)用。Windows9x使用32位保護(hù)模式可安裝文件系統(tǒng)(IFS),由可安裝文件系統(tǒng)管理器(IFSManager)協(xié)調(diào)對(duì)文件系統(tǒng)和設(shè)備的訪問,它接收以Win32API函數(shù)調(diào)用形式向系統(tǒng)發(fā)出的文件I/O請(qǐng)求,再將請(qǐng)求轉(zhuǎn)給文件系統(tǒng)驅(qū)動(dòng)程序FSD,由它調(diào)用低級(jí)別的IOS系統(tǒng)實(shí)現(xiàn)最終訪問。每個(gè)文件I/OAPI調(diào)用都有一個(gè)特定的FSD函數(shù)與之對(duì)應(yīng),IFSManager負(fù)責(zé)完成由API到FSD的參數(shù)裝配工作,在完成文件I/OAPI函數(shù)參數(shù)的裝配之后轉(zhuǎn)相應(yīng)FSD執(zhí)行之前,它會(huì)調(diào)用一個(gè)稱為FileSystemApiHookFunction的Hooker函數(shù)。通過安裝自己的Hooker函數(shù),就可以截獲系統(tǒng)內(nèi)所有對(duì)文件I/O的API調(diào)用,從而實(shí)現(xiàn)實(shí)時(shí)監(jiān)控。
=========================================
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;
===========================================
下面是一個(gè)監(jiān)視的控件:
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.