用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; }
相关文章
相关标签/搜索