II. Слежение за файлами
Здесь можно применить либо тот же подход что описан выше для процессов либо воспользоваться портами завершения.
Приведем реализацию первого метода
program file_seeker;
{$APPTYPE CONSOLE}
uses
SysUtils, windows, tintlist;
type
NTStatus = cardinal; PVOID = pointer; USHORT = WORD; UCHAR = byte; PWSTR = PWideChar;
CONST //Статус константы
STATUS_SUCCESS = NTStatus($00000000); STATUS_ACCESS_DENIED = NTStatus($C0000022); STATUS_INFO_LENGTH_MISMATCH = NTStatus($C0000004); SEVERITY_ERROR = NTStatus($C0000000);
const SystemHandleInformation = 16; OB_TYPE_FILE = 28;
type
PClientID = ^TClientID; TClientID = packed record
UniqueProcess:cardinal; UniqueThread:cardinal; end;
PUnicodeString = ^TUnicodeString; TUnicodeString = packed record
Length: Word; MaximumLength: Word; Buffer: PWideChar; end;
PSYSTEM_HANDLE_INFORMATION = ^SYSTEM_HANDLE_INFORMATION; SYSTEM_HANDLE_INFORMATION = packed record
ProcessId: dword; ObjectTypeNumber: byte; Flags: byte; Handle: word; pObject: pointer; GrantedAccess: dword; end;
PSYSTEM_HANDLE_INFORMATION_EX = ^SYSTEM_HANDLE_INFORMATION_EX; SYSTEM_HANDLE_INFORMATION_EX = packed record
NumberOfHandles: dword; Information: array [0..0] of SYSTEM_HANDLE_INFORMATION; end;
Function ZwQuerySystemInformation(ASystemInformationClass: dword; ASystemInformation: Pointer; ASystemInformationLength: dword; AReturnLength:PCardinal): NTStatus; stdcall;external 'ntdll.dll';
{ Включение заданой привилегии для процесса }
function EnablePrivilegeEx(Process: dword; lpPrivilegeName: PChar):Boolean; var
hToken: dword; NameValue: Int64; tkp: TOKEN_PRIVILEGES; ReturnLength: dword;
begin
Result:=false; //Получаем токен нашего процесса
OpenProcessToken(Process, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken); //Получаем LUID привилегии
if not LookupPrivilegeValue(nil, lpPrivilegeName, NameValue) then
begin
CloseHandle(hToken); exit; end; tkp.PrivilegeCount := 1; tkp.Privileges[0].Luid := NameValue; tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; //Добавляем привилегию к процессу
AdjustTokenPrivileges(hToken, false, tkp, SizeOf(TOKEN_PRIVILEGES), tkp, ReturnLength); if GetLastError() <> ERROR_SUCCESS then
begin
CloseHandle(hToken); exit; end; Result:=true; CloseHandle(hToken); end;
{ включение заданной привилегии для текущего процесса }
function EnablePrivilege(lpPrivilegeName: PChar):Boolean; begin
Result := EnablePrivilegeEx(INVALID_HANDLE_VALUE, lpPrivilegeName);
end;
{ Включение привилегии SeDebugPrivilege для процесса }
function EnableDebugPrivilegeEx(Process: dword):Boolean; begin
Result := EnablePrivilegeEx(Process, 'SeDebugPrivilege'); end;
{ Включение привилегии SeDebugPrivilege для текущего процесса }
function EnableDebugPrivilege():Boolean; begin
Result := EnablePrivilegeEx(INVALID_HANDLE_VALUE, 'SeDebugPrivilege'); end;
{ Получение буфера с системной информацией }
Function GetInfoTable(ATableType:dword):Pointer; var
mSize: dword; mPtr: pointer; St: NTStatus; begin
Result := nil; mSize := $4000; //начальный размер буфера
repeat
mPtr := VirtualAlloc(nil, mSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE); if mPtr = nil then Exit; St := ZwQuerySystemInformation(ATableType, mPtr, mSize, nil); if St = STATUS_INFO_LENGTH_MISMATCH then
begin //надо больше памяти
VirtualFree(mPtr, 0, MEM_RELEASE); mSize := mSize * 2; end; until St <> STATUS_INFO_LENGTH_MISMATCH; if St = STATUS_SUCCESS then Result := mPtr else VirtualFree(mPtr, 0, MEM_RELEASE);
end;
var
HandlesInfo: PSYSTEM_HANDLE_INFORMATION_EX; r: integer; hProcess, tHandle: dword; file_h: tintegerlist; begin
file_h := tintegerlist.Create;
EnableDebugPrivilege(); HandlesInfo := GetInfoTable(SystemHandleInformation); for r := 0 to HandlesInfo^.NumberOfHandles do
if HandlesInfo^.Information[r].ObjectTypeNumber = OB_TYPE_FILE then
begin
file_h.Add(HandlesInfo^.Information[r].Handle); end;
VirtualFree(HandlesInfo, 0, MEM_RELEASE);
//а теперь смотрим что изменилось
while true do
begin
Sleep(200);
HandlesInfo := GetInfoTable(SystemHandleInformation); for r := 0 to HandlesInfo^.NumberOfHandles do
if HandlesInfo^.Information[r].ObjectTypeNumber = OB_TYPE_FILE then
begin
if file_h.IndexOf(HandlesInfo^.Information[r].Handle)=-1 then
begin
file_h.Add(HandlesInfo^.Information[r].Handle); writeln(HandlesInfo^.Information[r].Handle, ' - added a file handle'); end; end;
VirtualFree(HandlesInfo, 0, MEM_RELEASE); end;
readln;
end.
Вторая технология - использование ReadDirectoryChangesA(W) и портов завершения ввода/вывода, реализация несложная, исходники (не мои, откомментированные) брать здесь.
Содержание раздела