在网上搜索此类问题,搜索到有用的内容相当少,可能是因为比较少人发表这种文章,也不排除比较少人使用内核模式的办法。今晚通过在网上看到的一点资料,结合自己近期研究的课题,使用NtQueryInformationFile实现了根据文件的Handle获取文件路径,程序在VC2008下调试通过,源代码如下:
#include "stdafx.h" #include <windows.h> #include <tchar.h> typedef long NTSTATUS; #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) // Define the base asynchronous I/O argument types typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef enum _FILE_INFORMATION_CLASS { // end_wdm FileDirectoryInformation = 1, FileFullDirectoryInformation, // 2 FileBothDirectoryInformation, // 3 FileBasicInformation, // 4 wdm FileStandardInformation, // 5 wdm FileInternalInformation, // 6 FileEaInformation, // 7 FileAccessInformation, // 8 FileNameInformation, // 9 FileRenameInformation, // 10 FileLinkInformation, // 11 FileNamesInformation, // 12 FileDispositionInformation, // 13 FilePositionInformation, // 14 wdm FileFullEaInformation, // 15 FileModeInformation, // 16 FileAlignmentInformation, // 17 FileAllInformation, // 18 FileAllocationInformation, // 19 FileEndOfFileInformation, // 20 wdm FileAlternateNameInformation, // 21 FileStreamInformation, // 22 FilePipeInformation, // 23 FilePipeLocalInformation, // 24 FilePipeRemoteInformation, // 25 FileMailslotQueryInformation, // 26 FileMailslotSetInformation, // 27 FileCompressionInformation, // 28 FileObjectIdInformation, // 29 FileCompletionInformation, // 30 FileMoveClusterInformation, // 31 FileQuotaInformation, // 32 FileReparsePointInformation, // 33 FileNetworkOpenInformation, // 34 FileAttributeTagInformation, // 35 FileTrackingInformation, // 36 FileIdBothDirectoryInformation, // 37 FileIdFullDirectoryInformation, // 38 FileValidDataLengthInformation, // 39 FileShortNameInformation, // 40 FileMaximumInformation // begin_wdm } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; #ifdef MIDL_PASS [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; #else // MIDL_PASS PWSTR Buffer; #endif // MIDL_PASS } UNICODE_STRING, *PUNICODE_STRING; typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONFILE)( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN DWORD Length, IN FILE_INFORMATION_CLASS FileInformationClass ); NTQUERYINFORMATIONFILE NtQueryInformationFile = NULL; void _tmain(int argc, _TCHAR* argv[]) { _tsetlocale(0, _T("chs")); NTSTATUS status = -1; HMODULE hNtdll = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK IoStatus = {0}; POBJECT_NAME_INFORMATION pfni = NULL; size_t allocSize = 0; hNtdll = LoadLibrary(_T("ntdll.dll")); NtQueryInformationFile = (NTQUERYINFORMATIONFILE)GetProcAddress(hNtdll, "NtQueryInformationFile"); hFile = CreateFile(_T("E://test//Debug//test.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { allocSize = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); pfni = (POBJECT_NAME_INFORMATION)malloc(allocSize); if (pfni != NULL) { RtlZeroMemory(pfni, allocSize); status = NtQueryInformationFile(hFile, &IoStatus, pfni, allocSize, FileNameInformation); if (NT_SUCCESS(status)) wprintf(L"文件名: %s/n", pfni->Name.Buffer); free(pfni); } CloseHandle(hFile); } FreeLibrary(hNtdll); }
虽然没有使用编写驱动程序,但使用的API跟内核模式的一样的,使用ntdll.dll里的API。类型定义全部从DDK 2003 SP1中摘出来的。
对于NtQueryInformationFile获取到的文件路径,是不带盘符的,如“/test/Debug/test.txt”。还有一个内核API可以根据文件的Handle获取文件路径,就是NtQueryObject,使用它获取的路径是MS-DOS设备路径,如“/Device/HarddiskVolume3/test/Debug/test.txt”。