用Windows Native API枚舉全部句柄及查找文件句柄對應文件名的方法

枚舉全部句柄的方法

因爲windows並無給出枚舉全部句柄所用到的API,和進程所擁有的句柄相關的只有GetProcessHandleCount這個函數,然而這個函數只能獲取到和進程相關的句柄數,不能獲取到實際的句柄,要得到句柄,咱們必須使用未公開的Native API才能夠。
 
PS:網上有不少關於這類的方法,但幾乎都是抄來抄去,不少連編譯都過不了就直接放上去了(囧)。我整理了一下方法,實測在win10和win7均可以用。
NTSTATUS WINAPI NtQuerySystemInformation(
  _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_   PVOID                    SystemInformation,
  _In_      ULONG                    SystemInformationLength,
  _Out_opt_ PULONG                   ReturnLength
);
枚舉的關鍵是使用NtQuerySystemInformation(舊版本是ZwQuerySystemInformation)這個方法
 
但MSDN上並無把這個函數的第一個參數的枚舉值給全,並且Windows API所定義的枚舉值也是MSDN上面列的幾個而已,以下:
typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45, SystemPolicyInformation = 134, } SYSTEM_INFORMATION_CLASS;
這幾個值的定義在MSDN上都有,具體能夠在上面給的連接的文檔查到,這裏就不列了。這些枚舉值都是能夠拿來指定NtQuerySystemInformation所查詢的內容
 
然而所給到的枚舉值並無咱們想要的枚舉句柄的功能,這個時候只能求助於強大的搜索引擎了,咱們能夠查到比較完整的SYSTEM_INFORMATION_CLASS的定義是下面的列表
typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemPathInformation, SystemProcessInformation, SystemCallCountInformation, SystemDeviceInformation, SystemProcessorPerformanceInformation, SystemFlagsInformation, SystemCallTimeInformation, SystemModuleInformation, SystemLocksInformation, SystemStackTraceInformation, SystemPagedPoolInformation, SystemNonPagedPoolInformation, SystemHandleInformation, SystemObjectInformation, SystemPageFileInformation, SystemVdmInstemulInformation, SystemVdmBopInformation, SystemFileCacheInformation, SystemPoolTagInformation, SystemInterruptInformation, SystemDpcBehaviorInformation, SystemFullMemoryInformation, SystemLoadGdiDriverInformation, SystemUnloadGdiDriverInformation, SystemTimeAdjustmentInformation, SystemSummaryMemoryInformation, SystemMirrorMemoryInformation, SystemPerformanceTraceInformation, SystemObsolete0, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemExtendServiceTableInformation, SystemPrioritySeperation, SystemVerifierAddDriverInformation, SystemVerifierRemoveDriverInformation, SystemProcessorIdleInformation, SystemLegacyDriverInformation, SystemCurrentTimeZoneInformation, SystemLookasideInformation, SystemTimeSlipNotification, SystemSessionCreate, SystemSessionDetach, SystemSessionInformation, SystemRangeStartInformation, SystemVerifierInformation, SystemVerifierThunkExtend, SystemSessionProcessInformation, SystemLoadGdiDriverInSystemSpace, SystemNumaProcessorMap, SystemPrefetcherInformation, SystemExtendedProcessInformation, SystemRecommendedSharedDataAlignment, SystemComPlusPackage, SystemNumaAvailableMemory, SystemProcessorPowerInformation, SystemEmulationBasicInformation, SystemEmulationProcessorInformation, SystemExtendedHandleInformation, SystemLostDelayedWriteInformation, SystemBigPoolInformation, SystemSessionPoolTagInformation, SystemSessionMappedViewInformation, SystemHotpatchInformation, SystemObjectSecurityMode, SystemWatchdogTimerHandler, SystemWatchdogTimerInformation, SystemLogicalProcessorInformation, SystemWow64SharedInformation, SystemRegisterFirmwareTableInformationHandler, SystemFirmwareTableInformation, SystemModuleInformationEx, SystemVerifierTriageInformation, SystemSuperfetchInformation, SystemMemoryListInformation, SystemFileCacheInformationEx, MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum
} SYSTEM_INFORMATION_CLASS;
注意看到第17項(枚舉值16)的SystemHandleInformation,這就是咱們想要的東西,經過這個值傳入NtQuerySystemInformation,而後在NtQuerySystemInformation的函數的第二項放入緩存空間長度,第三項放入緩存空間的指針便可。
 
如今咱們要肯定緩存區的類型了。若是咱們傳入SystemHandleInformation,那麼NtQuerySystemInformation將會返回下面這個結構
typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG NumberOfHandles; SYSTEM_HANDLE_INFORMATION Information[655360];//注意655360這個值是我本身定義的,大家能夠本身定義其餘的常量值
}SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
 
其中,SYSTEM_HANDLE_INFORMATION的定義是:
typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId;//進程標識符 
    UCHAR ObjectTypeNumber;//打開的對象的類型
    UCHAR Flags;//句柄屬性標誌
    USHORT Handle;//句柄數值,在進程打開的句柄中惟一標識某個句柄
    PVOID Object;//這個就是句柄對應的EPROCESS的地址
    ACCESS_MASK GrantedAccess;//句柄對象的訪問權限
}SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
注意到這裏有個很奇怪的地方,就是Handle值的類型是USHORT的,然而HANDLE的定義是void *,在32位上是4個字節,在64位上是8個字節。這就告訴咱們,咱們只能枚舉到一個進程的0~65535個句柄值, 可是咱們從Windows Internals這本書裏面能夠知道,如今Windows每一個進程的句柄值已經能夠到16000000以上了(雖然不會用到那麼多)。
 
這樣咱們就能夠根據ProcessId來獲取咱們感興趣的進程的句柄值了,可是這裏也有一個問題,雖然ProcessId的類型是ULONG,可是也只能枚舉到16位如下的ProcessId的值,也就是枚舉到的最大ProcessId值是65535,若是咱們的程序的ProcessId大於65535,咱們就不能枚舉到這些進程所建立的句柄了。(這就是Undocument的函數不可靠的體現了)。
 
ObjectTypeNumber是咱們想要的句柄值的類型,可是我暫時還沒法找到關於這個值的詳細資料,只是在windows driver裏面查到了這個東西ObReferenceObjectByHandle,可是我如今想在ring3層把問題解決,暫時先不考慮驅動。事實上咱們能夠在Process Explorer裏面根據把句柄值一個一個對應而後找到相應類型,好比下圖:

咱們能夠看到獲知句柄值爲0x4時,對應的值是Type是Key

咱們再來看下咱們取到的Info的ObjectType是7,也就是說,咱們的Key的類型值就是7

同理咱們也能夠找到File類型的ObjectType是35
 
 
 
我沒法肯定這個值是否會跟着系統不一樣而改變,若是要使用這個方法,請必定要先測試一下。
 
接下來的事情就很好辦了,咱們只要把NtQuerySystemInformation從NtDll.dll裏面拉出來就能夠了,咱們能夠寫出這樣的代碼:
//頭文件引#include <winternl.h>
#define SystemHandleInformation 0x10 typedef DWORD(WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD); HMODULE hNtDll = LoadLibrary(L"ntdll.dll"); NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll, "NtQuerySystemInformation"); ULONG cbBuffer = sizeof(SYSTEM_HANDLE_INFORMATION_EX); LPVOID pBuffer = (LPVOID)malloc(cbBuffer); if (pBuffer) { NtQuerySystemInformation(SystemHandleInformation, pBuffer, cbBuffer, NULL); PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer; for (ULONG r = 0; r < pInfo->NumberOfHandles; r++) { //dosomething
 } free(pBuffer); } FreeModule(hNtDll);
 
Native API其餘用法舉例:查找文件句柄文件名的方法

有時候咱們想查找句柄的所對應的信息,好比我以前就遇到了一個須要查找文件句柄所對應文件名的方法,這個時候也須要Native API來完成,須要用到ZwQueryInformationFile這個方法
NTSTATUS ZwQueryInformationFile(
  _In_  HANDLE                 FileHandle,
  _Out_ PIO_STATUS_BLOCK       IoStatusBlock,
  _Out_ PVOID                  FileInformation,
  _In_  ULONG                  Length,
  _In_  FILE_INFORMATION_CLASS FileInformationClass
);
其中第一個參數是咱們要查詢的文件句柄,信息能夠存放在FileInformation指向的內存中,這個內存的長度由Length指定。
 
如今咱們來看下第二個參數IoStatusBlock的類型IO_STATUS_BLOCK
typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 
Pointer是個保留項,第一項就是指定IRP's I/O的返回值,這個值咱們能夠不用
 
最後一個參數是FILE_INFORMATION_CLASS類型的一個數,這個數能夠拿來指定ZwQueryInformationFile所查詢的內容(就像NtQuerySystemInformation的那一堆枚舉值也是用來指定NtQuerySystemInformation所查詢的內容同樣),這個值在MSDN有完整的定義,但在VS自帶的SDK裏面卻沒有。
typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation, FileBothDirectoryInformation, FileBasicInformation, FileStandardInformation, FileInternalInformation, FileEaInformation, FileAccessInformation, FileNameInformation, FileRenameInformation, FileLinkInformation, FileNamesInformation, FileDispositionInformation, FilePositionInformation, FileFullEaInformation, FileModeInformation, FileAlignmentInformation, FileAllInformation, FileAllocationInformation, FileEndOfFileInformation, FileAlternateNameInformation, FileStreamInformation, FilePipeInformation, FilePipeLocalInformation, FilePipeRemoteInformation, FileMailslotQueryInformation, FileMailslotSetInformation, FileCompressionInformation, FileObjectIdInformation, FileCompletionInformation, FileMoveClusterInformation, FileQuotaInformation, FileReparsePointInformation, FileNetworkOpenInformation, FileAttributeTagInformation, FileTrackingInformation, FileIdBothDirectoryInformation, FileIdFullDirectoryInformation, FileValidDataLengthInformation, FileShortNameInformation, FileIoCompletionNotificationInformation, FileIoStatusBlockRangeInformation, FileIoPriorityHintInformation, FileSfioReserveInformation, FileSfioVolumeInformation, FileHardLinkInformation, FileProcessIdsUsingFileInformation, FileNormalizedNameInformation, FileNetworkPhysicalNameInformation, FileIdGlobalTxDirectoryInformation, FileIsRemoteDeviceInformation, FileUnusedInformation, FileNumaNodeInformation, FileStandardLinkInformation, FileRemoteProtocolInformation, FileRenameInformationBypassAccessCheck, FileLinkInformationBypassAccessCheck, FileVolumeNameInformation, FileIdInformation, FileIdExtdDirectoryInformation, FileReplaceCompletionInformation, FileHardLinkFullIdInformation, FileIdExtdBothDirectoryInformation, FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
 
在咱們的例子中,咱們須要用到的枚舉值是FileNameInformation(枚舉值9)
 
具體使用也像 同樣,先從ntdll.dll裏面導出來,而後把參數往裏面填就行了,在這裏我先定義一個緩衝區:
typedef struct _NM_INFO { HANDLE hFile; FILE_NAME_INFORMATION Info; } NM_INFO, *PNM_INFO;
 
FILE_NAME_INFORMATION結構:
typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[256];//256我本身定的,能夠改爲其餘的,只要夠放位置就行
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
 
調用API:
NM_INFO nmInfo = { 0 }; nmInfo.hFile = hFile; PNM_INFO NmInfo = (PNM_INFO)lpParameter; IO_STATUS_BLOCK IoStatus; ZWQUERYINFORMATIONFILE ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtDll, "ZwQueryInformationFile"); ZwQueryInformationFile(NmInfo->hFile, &IoStatus, &NmInfo->Info, 256, FILE_INFORMATION_CLASS::FileNameInformation);
 
注意查詢出來的FileNameLength是字節數,而不是WCHAR數組的最大偏移值,在這裏WCHAR的最大偏移值應該是512,由於WCHAR是兩個字節的
 
 
例子:找出全部文件句柄,而且把對應文件名含有ABC的句柄關掉

注意我把FILE_INFORMATION_CLASS改了個名字,改爲了RFILE_INFORMATION_CLASS,這是由於SDK裏面已經有了一個FILE_INFORMATION_CLASS了,並且我還把第一個枚舉值給改了個名字,若是用之前的那個不知道爲啥VS不給編譯經過。
 
#include <afx.h> #include <winternl.h> typedef DWORD(WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD); typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; }SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; #define STATUS_INFO_LENGTH_MISMATCH 0x004 typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG NumberOfHandles; SYSTEM_HANDLE_INFORMATION Information[165536]; }SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; #define SystemHandleInformation 0x10  // 16 typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[256]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; typedef struct _NM_INFO { HANDLE hFile; FILE_NAME_INFORMATION Info; } NM_INFO, *PNM_INFO; typedef enum _RFILE_INFORMATION_CLASS { FileDirectoryInformation1 = 1, FileFullDirectoryInformation, FileBothDirectoryInformation, FileBasicInformation, FileStandardInformation, FileInternalInformation, FileEaInformation, FileAccessInformation, FileNameInformation, FileRenameInformation, FileLinkInformation, FileNamesInformation, FileDispositionInformation, FilePositionInformation, FileFullEaInformation, FileModeInformation, FileAlignmentInformation, FileAllInformation, FileAllocationInformation, FileEndOfFileInformation, FileAlternateNameInformation, FileStreamInformation, FilePipeInformation, FilePipeLocalInformation, FilePipeRemoteInformation, FileMailslotQueryInformation, FileMailslotSetInformation, FileCompressionInformation, FileObjectIdInformation, FileCompletionInformation, FileMoveClusterInformation, FileQuotaInformation, FileReparsePointInformation, FileNetworkOpenInformation, FileAttributeTagInformation, FileTrackingInformation, FileIdBothDirectoryInformation, FileIdFullDirectoryInformation, FileValidDataLengthInformation, FileShortNameInformation, FileIoCompletionNotificationInformation, FileIoStatusBlockRangeInformation, FileIoPriorityHintInformation, FileSfioReserveInformation, FileSfioVolumeInformation, FileHardLinkInformation, FileProcessIdsUsingFileInformation, FileNormalizedNameInformation, FileNetworkPhysicalNameInformation, FileIdGlobalTxDirectoryInformation, FileIsRemoteDeviceInformation, FileUnusedInformation, FileNumaNodeInformation, FileStandardLinkInformation, FileRemoteProtocolInformation, FileRenameInformationBypassAccessCheck, FileLinkInformationBypassAccessCheck, FileVolumeNameInformation, FileIdInformation, FileIdExtdDirectoryInformation, FileReplaceCompletionInformation, FileHardLinkFullIdInformation, FileIdExtdBothDirectoryInformation, FileMaximumInformation } RFILE_INFORMATION_CLASS, *PRFILE_INFORMATION_CLASS; typedef NTSTATUS(WINAPI *ZWQUERYINFORMATIONFILE)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, RFILE_INFORMATION_CLASS); CString GetFileName(HMODULE hNtDll, PNM_INFO lpParameter) { PNM_INFO NmInfo = (PNM_INFO)lpParameter; IO_STATUS_BLOCK IoStatus; ZWQUERYINFORMATIONFILE ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtDll, "ZwQueryInformationFile"); ZwQueryInformationFile(NmInfo->hFile, &IoStatus, &NmInfo->Info, 256, RFILE_INFORMATION_CLASS::FileNameInformation); if (NmInfo->Info.FileNameLength != 0) { CString str; str.Append(NmInfo->Info.FileName, NmInfo->Info.FileNameLength / sizeof(WCHAR)); return str; } return CString(); } extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nShowCmd) { HMODULE hNtDll = LoadLibrary(L"ntdll.dll"); NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll, "ZwQuerySystemInformation"); ULONG cbBuffer = sizeof(SYSTEM_HANDLE_INFORMATION_EX); LPVOID pBuffer = (LPVOID)malloc(cbBuffer); auto id= GetCurrentProcessId(); if (pBuffer) { NtQuerySystemInformation(SystemHandleInformation, pBuffer, cbBuffer, NULL); PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer; for (ULONG r = 0; r < pInfo->NumberOfHandles; r++) { if (pInfo->Information[r].ObjectTypeNumber == 35) { NM_INFO nmInfo = { 0 }; nmInfo.hFile = (HANDLE)pInfo->Information[r].Handle; CString fileName = GetFileName(hNtDll, &nmInfo); if (!fileName.IsEmpty()) { if (fileName.Find(L"ABC") != -1) { CloseHandle(nmInfo.hFile); } } } } free(pBuffer); } FreeModule(hNtDll); return 0; }
相關文章
相關標籤/搜索