Witam
Aplikacja x otwiera jakiś plik dbf. W jaki sposób po uchwyceniu aplikacji mogę uzyskać informacje z jakiego pliku w danej chwili aplikacja korzysta
Jeżeli aplikacja nie korzysta z obsługi DDE ani nie podaje tej nazwy w pasku tytułowym, to spróbował bym wyciągnąć to z pamięci tegoż procesu. Ewentualnie injekcja dllki lub spoofnięcie, którejś z wykorzystywanych systemowych. A w samym kodzie hook na funkcje otwierania plików przez systemowe Open dialogi o ile tak otwiera się tam pliki. Można też próbować odczytać parametry z jakimi został wywołany proces. Ale może nie być tam pełnej ścieżki do pliku. Chociaż podejrzewam, że są pewnie jakieś funkcje, może nawet WinAPI. Skoro są watchery do sprawdzania zmian w katalogu. Ewentualnie pogoogluj pytając o rozwiązania, któruch mogą używać programy unlockujące dostęp do pliku czy katalogu.
EDIT: No niestety rozwiązania w drugą stronę czyli pid na podstawie nazwy pliku znajduje się od ręki. A w drugą stronę ciężko. O ile nikt nie doradzi nic lepszego ja przeszukiwał bym jednak pamięć procesu.
Wypociłem, częściowo znalazłem w Google jak pobrać listę otwartych plików na podstawie ścieżki i nazwy procesu, kod był testowany tylko na Delphi 7 więc nie wiem jak będzie działał na nowszych z Unicode ale to na pewno łatwo będzie dostosować gdyby coś:
uses PsApi;
const
KERNEL32 = 'kernel32.dll';
NTDLL = 'NTDLL.dll';
QUERY_FULL_PROCESS_IMAGE_NAME = 'QueryFullProcessImageNameA';
NT_QUERY_SYSTEM_INFORMATION = 'NtQuerySystemInformation';
NT_QUERY_OBJECT = 'NtQueryObject';
STATUS_SUCCESS = $000000;
STATUS_BUFFER_OVERFLOW = $80000005;
STATUS_INFO_LENGTH_MISMATCH = $C0000004;
DefaultBUFFERSIZE = $100000;
SYSTEM_HANDLE_INFO = $00000010;
DUPLICATE_CLOSE_SOURCE = $00000001;
DUPLICATE_SAME_ACCESS = $00000002;
type
OBJECT_INFORMATION_CLASS = (ObjectBasicInformation,ObjectNameInformation,
ObjectTypeInformation,ObjectAllTypesInformation,ObjectHandleInformation);
SYSTEM_HANDLE = packed record
uIdProcess: ULONG;
ObjectType: UCHAR;
Flags: UCHAR;
Handle: Word;
pObject: Pointer;
GrantedAccess: ACCESS_MASK;
end;
PSYSTEM_HANDLE = ^SYSTEM_HANDLE;
SYSTEM_HANDLE_ARRAY = Array[0..0] of SYSTEM_HANDLE;
PSYSTEM_HANDLE_ARRAY = ^SYSTEM_HANDLE_ARRAY;
SYSTEM_HANDLE_INFORMATION = packed record
uCount: ULONG;
Handles: SYSTEM_HANDLE_ARRAY;
end;
PSYSTEM_HANDLE_INFORMATION = ^SYSTEM_HANDLE_INFORMATION;
UNICODE_STRING=packed record
Length :Word;
MaximumLength:Word;
Buffer :PWideChar;
end;
OBJECT_NAME_INFORMATION = UNICODE_STRING;
POBJECT_NAME_INFORMATION = ^OBJECT_NAME_INFORMATION;
function QueryFullProcessImageName(hProcess: Thandle; dwFlags: DWORD;
lpExeName: PChar; nSize: PDWORD): BOOL; stdcall; external KERNEL32
name QUERY_FULL_PROCESS_IMAGE_NAME;
function NtQuerySystemInformation(SystemInformationClass:DWORD;
SystemInformation:pointer; SystemInformationLength:DWORD;
ReturnLength:PDWORD):THandle; stdcall; external NTDLL name
NT_QUERY_SYSTEM_INFORMATION;
function NtQueryObject(ObjectHandle:cardinal;
ObjectInformationClass:OBJECT_INFORMATION_CLASS; ObjectInformation:Pointer;
Length:ULONG;ResultLength:PDWORD):THandle;stdcall; external NTDLL name
NT_QUERY_OBJECT;
procedure EnumerateDevicePaths(const ADeviceNames, ADevicePaths: TStringList);
var
drives : array[0..4095] of Char;
pdrive : PChar;
drive : String;
drive_path : array[0..4095] of Char;
sdrive_path: String;
begin
ADeviceNames.Clear;
ADevicePaths.Clear;
if GetLogicalDriveStrings(SizeOf(drives), drives) = 0 then
Exit;
pdrive := drives;
while pdrive^ <> #0 do
begin
drive := Copy(pdrive, 0, 4);
if drive <> '' then
begin
if drive[Length(drive)] = '\' then
Delete(drive, Length(drive), 1);
QueryDosDevice(PChar(drive), drive_path, SizeOf(drive_path));
sdrive_path := drive_path;
ADeviceNames.Add(drive);
ADevicePaths.Add(sdrive_path);
end;
Inc(pdrive, 4);
end;
end;
function GetProcessPathFromPID(const PID: Cardinal): string;
var
hProcess: THandle;
buff: array[0..MAX_PATH - 1] of Char;
cSize: Cardinal;
begin
result:= '';
ZeroMemory(@buff, MAX_PATH);
cSize:= SizeOf(buff);
hProcess:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if (hProcess <> INVALID_HANDLE_VALUE) then
begin
if QueryFullProcessImageName(hProcess, 0, buff, @cSize) then
result:= buff;
CloseHandle(hProcess);
end;
end;
function GetObjectInfo(hObject:cardinal; objInfoClass:OBJECT_INFORMATION_CLASS):LPWSTR;
var
pObjectInfo: POBJECT_NAME_INFORMATION;
HDummy :THandle;
dwSize :DWORD;
begin
Result:=nil;
dwSize:= sizeof(OBJECT_NAME_INFORMATION);
pObjectInfo:= AllocMem(dwSize);
HDummy:= NTQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, @dwSize);
if((HDummy = STATUS_BUFFER_OVERFLOW) or (HDummy = STATUS_INFO_LENGTH_MISMATCH)) then
begin
//ReallocMem(pObjectInfo, dwSize); //nie wiem czemu nie dziala trzeba zwolnic i od nowa alokowac :/
FreeMem(pObjectInfo);
pObjectInfo := AllocMem(dwSize);
HDummy:= NTQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, @dwSize);
end;
if((HDummy = STATUS_SUCCESS) and (pObjectInfo.Buffer <> nil)) then
begin
Result:= AllocMem(pObjectInfo.Length + sizeof(WCHAR));
CopyMemory(result, pObjectInfo.Buffer, pObjectInfo.Length);
end;
FreeMem(pObjectInfo);
end;
procedure EnumerateOpenFiles(AFullProcessPath: string; const AFilesList: TStrings);
var
pHandlesInfo: PSYSTEM_HANDLE_INFORMATION;
pHandleInfo: PSYSTEM_HANDLE;
slDeviceNames, slDevicePaths: TStringList;
hProcess, hProcessDup: THandle;
FileName: String;
ResultLength: Cardinal;
BufferSize: Cardinal;
i, j: Integer;
begin
AFilesList.Clear;
slDeviceNames:= TStringList.Create;
slDevicePaths:= TStringList.Create;
try
EnumerateDevicePaths(slDeviceNames, slDevicePaths);
BufferSize:= DefaultBUFFERSIZE;
pHandlesInfo:= AllocMem(BufferSize);
try
if NTQuerySystemInformation(Dword(SYSTEM_HANDLE_INFO), pHandlesInfo,
BufferSize, @ResultLength) = STATUS_SUCCESS then
begin
for i:=0 to pHandlesInfo^.uCount -1 do
begin
pHandleInfo:= Pointer(Integer(@pHandlesInfo^.Handles) + i * SizeOf(SYSTEM_HANDLE));
if (pHandleInfo^.ObjectType <> 28) or
(pHandleInfo^.GrantedAccess = $0012019F) or
(pHandleInfo^.GrantedAccess = $001A019F) or
(pHandleInfo^.GrantedAccess = $00120189) then
Continue;
if SameText(AFullProcessPath,
GetProcessPathFromPID(pHandlesInfo.Handles[i].uIdProcess)) then
begin
hProcess:= OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION
or PROCESS_VM_READ, False, pHandlesInfo.Handles[i].uIdProcess);
if (hProcess <> INVALID_HANDLE_VALUE) then
begin
if DuplicateHandle(hProcess, pHandlesInfo.Handles[i].Handle,
GetCurrentProcess(), @hProcessDup, STANDARD_RIGHTS_REQUIRED,
False, DUPLICATE_SAME_ACCESS) then
begin
FileName:= GetObjectInfo(hProcessDup, ObjectNameInformation);
CloseHandle(hProcessDup);
for j:= 0 to slDevicePaths.Count - 1 do
if Copy(FileName, 1, Length(slDevicePaths[j])) = slDevicePaths[j] then
begin
Delete(FileName, 1, Length(slDevicePaths[j]));
FileName:= slDeviceNames[j] + FileName;
break;
end;
if (Length(FileName) > 0) then
AFilesList.Add(FileName);;
end;
CloseHandle(hProcess);
end;
end;
end;
end;
finally
FreeMem(pHandlesInfo, BufferSize);
end;
finally
slDeviceNames.Free;
slDevicePaths.Free;
end;
end;
Przykład użycia:
EnumerateOpenFiles('c:\Program Files (x86)\VideoLAN\VLC\vlc.exe', Memo1.Lines);
Uwaga: Część aplikacji choćby głupi notatnik z Windows nie trzyma cały otwartych plików a jedynie podczas odczytu i zapisu więc nie należy się tym sugerować że niby nie działa.
PS: Kod trochę taki niedbały, brak spójności formatowania i nazywania zmiennych ale jak pisałem część jest moja a część kopiuj/wklej z Google a nie chciało mi się tego poprawiać.
A Ci którzy mają starego, poczciwego XP, zamiast:
if QueryFullProcessImageName(hProcess, 0, buff, @cSize) then
niech użyją
if GetModuleFileNameEx(hProcess, 0, buff, cSize) > 0 then