Jump to content


Photo

GetFilePathByHandle, como encontrar el nombre de un fichero conociendo su Handle


  • Please log in to reply
5 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 07 June 2014 - 12:21 PM

No es un tema de uso frecuente, pero me surgió la necesidad de conocer el nombre de un archivo sabiendo su handle abierto, en concreto para ser usado en un Hook a la API ZwWriteFile.

Desde Vista, Microsoft tiene prevista la API GetFinalPathNameByHandle pero en WinXP no existe ninguna API con esa funcionalidad salvo este ejemplo con una técnica no funcionante en el entorno que yo necesitaba. Decidí investiguar APIs indocumentadas y conseguí mi propósito.

La función GetFilePathByHandle recibe como parámetro un Handle de archivo y devuelve un WideString con el nombre completo del archivo. Comparto con vosotros el código:


delphi
  1. uses
  2.   Windows;
  3.  
  4. type
  5. NTSTATUS = DWORD;
  6.  
  7. OBJECT_INFORMATION_CLASS = (ObjectNameInformation = 1);
  8. FILE_INFORMATION_CLASS = (FileNameInformation = 9);
  9.  
  10. FILE_NAME_INFORMATION = record
  11.   FileNameLength: ULONG;
  12.   FileName: array [0..0] of WCHAR;
  13. end;
  14. PFILE_NAME_INFORMATION = ^FILE_NAME_INFORMATION;
  15.  
  16. IO_STATUS_BLOCK = record
  17.   Dummy: Pointer;
  18.   Information: int64;
  19. end;
  20. PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
  21.  
  22. UNICODE_STRING = record
  23.   Length: WORD;
  24.   MaximumLength: WORD;
  25.   Buffer: PWCHAR;
  26. end;
  27. PUNICODE_STRING = ^UNICODE_STRING;
  28.  
  29. MOUNTMGR_TARGET_NAME = record
  30.   DeviceNameLength: WORD;
  31.   DeviceName: array [0..0] of WCHAR;
  32. end;
  33. PMOUNTMGR_TARGET_NAME = ^MOUNTMGR_TARGET_NAME;
  34.  
  35. MOUNTMGR_VOLUME_PATHS = record
  36.   MultiSzLength: ULONG;
  37.   MultiSz: array [0..0] of WCHAR;
  38. end;
  39. PMOUNTMGR_VOLUME_PATHS = ^MOUNTMGR_VOLUME_PATHS;
  40.  
  41. WBuffer = array [0..511] of WCHAR;
  42.  
  43. const
  44. IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH = $6d0030;
  45.  
  46. function NtQueryObject(Handle: THANDLE; ObjectInformationClass: OBJECT_INFORMATION_CLASS; ObjectInformation: Pointer; ObjectInformationLength: ULONG; ReturnLength: PULONG): NTSTATUS ;stdcall; external 'ntdll.dll';
  47. function NtQueryInformationFile(Handle: THANDLE; IoStatusBlock: PIO_STATUS_BLOCK; FileInformation: Pointer; Length: ULONG; FileInformationClass: FILE_INFORMATION_CLASS): NTSTATUS; stdcall; external 'ntdll.dll';
  48.  
  49. implementation
  50.  
  51. //------------------------------------------------------------------------------
  52. function GetFilePathByHandle(hFile: THANDLE): WideString;
  53. var
  54.   returnedLength: ULONG;
  55.   iosb: IO_STATUS_BLOCK;
  56.   PFullName, PRelName, PPathName: WBuffer;
  57.   FullName: PUNICODE_STRING;
  58.   RelName:  PFILE_NAME_INFORMATION;
  59.   PathName: PMOUNTMGR_TARGET_NAME;
  60.   hMount: THANDLE;
  61.   bytesReturned: DWORD;
  62. begin
  63.   Result:= '';
  64.   // Preparando los buffer
  65.   FullName:= PUNICODE_STRING(@PFullName[0]);
  66.   RelName:=  PFILE_NAME_INFORMATION(@PRelName[0]);
  67.   PathName:= PMOUNTMGR_TARGET_NAME(@PPathName[0]);
  68.  
  69.   // Encontrando el nombre completo del archivo
  70.   if 0 = NtQueryObject(hFile, ObjectNameInformation, FullName, sizeof(PFullName), @returnedLength) then
  71.   begin
  72.     // El nombre relativo
  73.     if 0 = NtQueryInformationFile(hFile, @iosb, RelName, sizeof(PRelName), FileNameInformation) then
  74.     begin
  75.       if FullName.Length >= RelName.FileNameLength then
  76.       begin
  77.         // Aseguro que las cadenas termine en 0
  78.         FullName.Buffer[FullName.Length div sizeof(WCHAR)]:= WCHAR(0);
  79.         RelName.FileName[RelName.FileNameLength div sizeof(WCHAR)]:= WCHAR(0);
  80.  
  81.         // Preparo PathName con el nombre del dispositivo
  82.         PathName.DeviceNameLength:= WORD(FullName.Length - RelName.FileNameLength);
  83.         lstrcpyW(PathName.DeviceName, FullName.Buffer);
  84.  
  85.         // Buscando el nombre de unidad a partir del diapositivo
  86.         hMount:= CreateFile('\\.\MountPointManager', 0, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, 0, 0);
  87.         try
  88.           if DeviceIoControl(hMount, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, PathName,
  89.                             sizeof(WBuffer), PathName, sizeof(WBuffer), bytesReturned, nil) then
  90.           begin
  91.             if PMOUNTMGR_VOLUME_PATHS(PathName).MultiSzLength > 0 then
  92.             begin
  93.               lstrcpyW(FullName.Buffer, PMOUNTMGR_VOLUME_PATHS(PathName).MultiSz);
  94.               lstrcatW(FullName.Buffer, RelName.FileName);
  95.               Result:= FullName.Buffer;
  96.             end;
  97.           end;
  98.         finally CloseHandle(hMount);
  99.         end;
  100.       end;
  101.     end;
  102.   end;
  103. end;



Un ejemplo de uso:


delphi
  1. var
  2.   hFile: THANDLE;
  3. begin
  4.   hFile:= CreateFile('C:\Windows\Notepad.exe', 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  5.   if hFile <> INVALID_HANDLE_VALUE then
  6.   begin
  7.     Label1.Caption:= GetFilePathByHandle(hFile);
  8.     CloseHandle(hFile);
  9.   end;
  10. end;



Espero que le encontréis utilidad.



Saludos.



  • 0

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 07 June 2014 - 01:48 PM

Para los amantes del C os propongo esta versión:
 

cpp
  1. #include <Windows.h>
  2.  
  3. enum OBJECT_INFORMATION_CLASS { ObjectNameInformation = 1 };
  4. enum FILE_INFORMATION_CLASS { FileNameInformation = 9 };
  5. typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
  6. typedef struct _IO_STATUS_BLOCK { PVOID Dummy; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
  7. typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING;
  8. typedef struct _MOUNTMGR_TARGET_NAME { USHORT DeviceNameLength; WCHAR DeviceName[1]; } MOUNTMGR_TARGET_NAME, *PMOUNTMGR_TARGET_NAME;
  9. typedef struct _MOUNTMGR_VOLUME_PATHS { ULONG MultiSzLength; WCHAR MultiSz[1]; } MOUNTMGR_VOLUME_PATHS, *PMOUNTMGR_VOLUME_PATHS;
  10.  
  11. typedef LONG NTSTATUS;
  12.  
  13. typedef NTSTATUS (WINAPI *PNtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength);
  14. typedef NTSTATUS (WINAPI *PNtQueryInformationFile)(HANDLE Handle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass);
  15.  
  16. #define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH 0x6d0030
  17. #define SizeBuf 1024
  18.  
  19. LPWSTR GetFilePathByHandle(HANDLE hFile, LPWSTR FileName, int Size)
  20. {
  21.   PUNICODE_STRING        FullName;
  22.   PFILE_NAME_INFORMATION RelName;
  23.   PMOUNTMGR_TARGET_NAME  PathName;
  24.   HANDLE hMount;
  25.   DWORD bytesReturned;
  26.  
  27.   if(!FileName || Size <1) return FileName;
  28.   *FileName = 0;
  29.  
  30.   BYTE PFullName[SizeBuf];
  31.   BYTE PRelName[SizeBuf];
  32.   BYTE PPathName[SizeBuf];
  33.  
  34.   // Preparando los buffer
  35.   FullName= (PUNICODE_STRING)PFullName;
  36.   RelName = (PFILE_NAME_INFORMATION)PRelName;
  37.   PathName= (PMOUNTMGR_TARGET_NAME)PPathName;
  38.  
  39.  
  40.   PNtQueryObject _NtQueryObject =(PNtQueryObject)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryObject");
  41.   PNtQueryInformationFile _NtQueryInformationFile =(PNtQueryInformationFile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationFile");
  42.   ULONG returnedLength; IO_STATUS_BLOCK iosb;
  43.  
  44.   // Encontrando el nombre completo del archivo
  45.   if(0 == _NtQueryObject(hFile, ObjectNameInformation, FullName, sizeof(PFullName), &returnedLength)){
  46.     // El nombre relativo
  47.     if(0 == _NtQueryInformationFile(hFile, &iosb, RelName, sizeof(PRelName), FileNameInformation)){
  48.       if(FullName->Length >= RelName->FileNameLength){
  49.         // Aseguro que las cadenas termine en 0
  50.         FullName->Buffer[FullName->Length / sizeof(WCHAR)] = 0;
  51.         RelName->FileName[RelName->FileNameLength / sizeof(WCHAR)] = 0;
  52.  
  53.         // Preparo PathName con el nombre del dispositivo
  54.         PathName->DeviceNameLength = WORD(FullName->Length - RelName->FileNameLength);
  55.         lstrcpyW(PathName->DeviceName, FullName->Buffer);
  56.  
  57.         // Buscando el nombre de unidad a partir del diapositivo
  58.         hMount = CreateFile("\\\\.\\MountPointManager", 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, 0, 0);
  59.         __try {
  60.           if(DeviceIoControl(hMount, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, PathName,
  61.                             SizeBuf, PathName, SizeBuf, &bytesReturned, 0)){
  62.             if(PMOUNTMGR_VOLUME_PATHS(PathName)->MultiSzLength > 0){
  63.               lstrcpyW(FullName->Buffer, PMOUNTMGR_VOLUME_PATHS(PathName)->MultiSz);
  64.               lstrcatW(FullName->Buffer, RelName->FileName);
  65.               int Len = lstrlenW(FullName->Buffer);
  66.               if(Len <= Size)
  67.                 lstrcpynW(FileName, FullName->Buffer, Len + 1);
  68.             }
  69.           }
  70.         }
  71.         __finally {CloseHandle(hMount);}
  72.       }
  73.     }
  74.   }
  75.   return FileName;
  76. }

Y un ejemplo de uso:

cpp
  1.   WCHAR FileNameW[512];
  2.   HANDLE hFile = CreateFile("C:\\Windows\\Notepad.exe"0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  3.   if(hFile != NULL && hFile != INVALID_HANDLE_VALUE){
  4.     GetFilePathByHandle(hFile, FileNameW, 512);
  5.     CloseHandle(hFile);
  6.   }


Saludos.
  • 0

#3 ELKurgan

ELKurgan

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 566 posts
  • LocationEspaña

Posted 08 June 2014 - 04:31 AM

Gracias por el aporte, maestro

(y)
  • 0

#4 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4945 posts
  • LocationMéxico

Posted 09 June 2014 - 07:52 AM

Excelente truco amigo. Muchas gracias por compartirlo. Se me acaba de ocurrir algo, ¿Es posible con este truco obtener la ubicación de un programa que se encuentre en ejecución? Si mal no recuerdo cada programa en ejecución se identifica en windows por un handle y de allí me vino la idea de con un programa residente poder mostrar la ubicación de un programa en particular con solo dar click.
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 June 2014 - 02:09 PM

¿Es posible con este truco obtener la ubicación de un programa que se encuentre en ejecución? Si mal no recuerdo cada programa en ejecución se identifica en windows por un handle y de allí me vino la idea de con un programa residente poder mostrar la ubicación de un programa en particular con solo dar click.


En Windows un Handle puede representar cosas muy distintas. No sirve para lo que propones, sin embargo dispones de esta API GetProcessImageFileName si tienes un handle al proceso, pero si dispones de su  PID, entonces puedes usar este código:



delphi
  1. function GetProcessImageFileName(PId: DWORD; ExePath: PCHAR; Size: integer): boolean;
  2. var
  3.   hSnapshot: THandle;
  4.   ModEntry:  MODULEENTRY32;
  5. begin
  6.   Result:= True;
  7.   if (PId = 0) and (Size > 0) then
  8.   begin
  9.     ExePath[0]:= #0;
  10.     exit;
  11.   end;
  12.   ModEntry.dwSize:= sizeof(MODULEENTRY32);
  13.   Result:= false;
  14.   if Size>0 then ExePath[0]:= #0;
  15.   hSnapshot:= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PId);
  16.   if hSnapshot <> THandle(-1) then
  17.   begin
  18.     if Module32First(hSnapshot, ModEntry) then
  19.     begin
  20.       Result:= true;
  21.       lstrcpyn(ExePath, ModEntry.szExePath, Size);
  22.     end;
  23.     CloseHandle(hSnapshot);
  24.   end;
  25. end;



PD/ Recordaba haber publicado algo sobre el tema, aquí está.

Saludos.
  • 0

#6 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4945 posts
  • LocationMéxico

Posted 09 June 2014 - 02:43 PM

PD/ Recordaba haber publicado algo sobre el tema, aquí está.

Saludos.


Sobra decirlo amigo, eres todo un maestro. :D  (b)  (b)
  • 0




IP.Board spam blocked by CleanTalk.