从文件句柄获得文件名方法(三), 这次是用wdk函数ZwQueryInformationFile(),和GetVolumeInformation()。
通过判断取得的dwVolumeSerialNumber来确定盘符。
其他的内核函数比如说ObDereferenceObject()也可以。
参考了Adly's blog 的 通过文件句柄得到文件所在路径的一种新方法 —— 得到完整路径名
LPWSTR GetFileNameFromHandleW3(HANDLE hFile, LPWSTR lpFilePath) {
const int FileNameInformation = 9; // enum FILE_INFORMATION_CLASS; Defined in winddk.h
typedef struct _IO_STATUS_BLOCK {
union {
ULONG Status; // NTSTATUS
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; // Defined in Wdm.h
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[MAX_PATH];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
typedef LONG (CALLBACK* ZWQUERYINFORMATIONFILE)(
HANDLE FileHandle,
IO_STATUS_BLOCK *IoStatusBlock,
PVOID FileInformation,
ULONG Length,
ULONG FileInformationClass
);
lpFilePath[0] = 0x00;
HMODULE hNtDLL = LoadLibraryW(L"ntdll.dll");
if (hNtDLL == 0x00) { return 0x00; }
ZWQUERYINFORMATIONFILE ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtDLL, "ZwQueryInformationFile");
if (ZwQueryInformationFile == 0x00) { return 0x00; }
FILE_NAME_INFORMATION fni;
IO_STATUS_BLOCK isb;
if (ZwQueryInformationFile(hFile, &isb, &fni, sizeof(fni), FileNameInformation) != 0) { return 0x00; }
fni.FileName[fni.FileNameLength / sizeof(WCHAR)] = 0x00;
BY_HANDLE_FILE_INFORMATION fi;
if(!GetFileInformationByHandle(hFile, &fi) || (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { return 0x00; }
WCHAR szDrive [MAX_PATH];
WCHAR *lpDrive = szDrive;
int iPathLen;
if (GetLogicalDriveStringsW(MAX_PATH - 1, szDrive) >= MAX_PATH) { return 0x00; }
while ((iPathLen = lstrlenW(lpDrive)) != 0) {
DWORD dwVolumeSerialNumber;
if(!GetVolumeInformation(lpDrive, NULL, NULL, &dwVolumeSerialNumber,NULL, NULL, NULL, NULL)) { return 0x00; }
if (dwVolumeSerialNumber == fi.dwVolumeSerialNumber) {
lstrcpynW(lpFilePath, lpDrive, lstrlen(lpDrive));
lstrcatW(lpFilePath, fni.FileName);
break;
}
lpDrive += iPathLen + 1;
}
return lpFilePath;
}