原理:
调用ntdll的一个导出函数ZwQuerySystemInformation可以获取一些重要信息,函数定义如下:
1 NTSTATUS WINAPI ZwQuerySystemInformation( 2 _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, 3 _Inout_ PVOID SystemInformation, 4 _In_ ULONG SystemInformationLength, 5 _Out_opt_ PULONG ReturnLength 6 );
不过msdn上说该函数在win8下已经不能使用了,用到的时候再说。
重点关注该函数的第一个参数SYSTEM_INFORMATION_CLASS是一个结构体,具体定义如下:
typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 Y N SystemProcessorInformation, // 1 Y N SystemPerformanceInformation, // 2 Y N SystemTimeOfDayInformation, // 3 Y N SystemNotImplemented1, // 4 Y N SystemProcessesAndThreadsInformation, // 5 Y N SystemCallCounts, // 6 Y N SystemConfigurationInformation, // 7 Y N SystemProcessorTimes, // 8 Y N SystemGlobalFlag, // 9 Y Y SystemNotImplemented2, // 10 Y N SystemModuleInformation, // 11 Y N SystemLockInformation, // 12 Y N SystemNotImplemented3, // 13 Y N SystemNotImplemented4, // 14 Y N SystemNotImplemented5, // 15 Y N SystemHandleInformation, // 16 Y N SystemObjectInformation, // 17 Y N SystemPagefileInformation, // 18 Y N SystemInstructionEmulationCounts, // 19 Y N SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 Y Y SystemPoolTagInformation, // 22 Y N SystemProcessorStatistics, // 23 Y N SystemDpcInformation, // 24 Y Y SystemNotImplemented6, // 25 Y N SystemLoadImage, // 26 N Y SystemUnloadImage, // 27 N Y SystemTimeAdjustment, // 28 Y Y SystemNotImplemented7, // 29 Y N SystemNotImplemented8, // 30 Y N SystemNotImplemented9, // 31 Y N SystemCrashDumpInformation, // 32 Y N SystemExceptionInformation, // 33 Y N SystemCrashDumpStateInformation, // 34 Y Y/N SystemKernelDebuggerInformation, // 35 Y N SystemContextSwitchInformation, // 36 Y N SystemRegistryQuotaInformation, // 37 Y Y SystemLoadAndCallImage, // 38 N Y SystemPrioritySeparation, // 39 N Y SystemNotImplemented10, // 40 Y N SystemNotImplemented11, // 41 Y N SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 Y N SystemLookasideInformation, // 45 Y N SystemSetTimeSlipEvent, // 46 N Y SystemCreateSession, // 47 N Y SystemDeleteSession, // 48 N Y SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 Y N SystemVerifierInformation, // 51 Y Y SystemAddVerifier, // 52 N Y SystemSessionProcessesInformation // 53 Y N } SYSTEM_INFORMATION_CLASS;
16号SystemHandleInformation即可获得系统句柄信息。
获取所以进程句柄后并不能直接操作这些句柄,因为每个进程的句柄都是独立存在的,所以需要调用DuplicateHandle将需要的进程句柄Dump到当前进程然后再进行操作,
BOOL WINAPI DuplicateHandle(
_In_ HANDLE hSourceProcessHandle,
_In_ HANDLE hSourceHandle,
_In_ HANDLE hTargetProcessHandle,
_Out_ LPHANDLE lpTargetHandle,
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwOptions
);
得到的lpTargetHandle保存着目标进程的句柄。然后调用NtQueryObject可以获取句柄的类型(mutex、File、Section等),以及句柄名称等等。
NTSTATUS NtQueryObject(
_In_opt_ HANDLE Handle,
_In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
_Out_opt_ PVOID ObjectInformation,
_In_ ULONG ObjectInformationLength,
_Out_opt_ PULONG ReturnLength
);
说了一大堆了,开始写代码吧,由于这里需要很多结构信息,因此我写了一个头文件来定义这些结构:
objEnum.h:
1 #include "ntsecapi.h" 2 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 3 typedef NTSTATUS (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD); 4 typedef enum _OBJECT_INFORMATION_CLASS { 5 ObjectBasicInformation, 6 ObjectNameInformation, 7 ObjectTypeInformation, 8 ObjectAllInformation, 9 ObjectDataInformation, 10 } OBJECT_INFORMATION_CLASS; 11 typedef NTSTATUS (NTAPI *NTQUERYOBJECT)( 12 HANDLE Handle, 13 OBJECT_INFORMATION_CLASS ObjectInformationClass, 14 PVOID ObjectInformation, 15 ULONG ObjectInformationLength, 16 PULONG ReturnLength 17 ); 18 typedef struct _OBJECT_NAME_INFORMATION { 19 UNICODE_STRING Name; 20 } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; 21 typedef struct _SYSTEM_HANDLE_INFORMATION 22 { 23 ULONG ProcessId; 24 UCHAR ObjectTypeNumber; 25 UCHAR Flags; 26 USHORT Handle; 27 PVOID Object; 28 ACCESS_MASK GrantedAccess; 29 }SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; 30 31 typedef struct _SYSTEM_HANDLE_INFORMATION_EX 32 { 33 ULONG NumberOfHandles; 34 SYSTEM_HANDLE_INFORMATION Information[1]; 35 }SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; 36 #define SystemHandleInformation 0x10 // 16
然后是两个函数:
1、GetSystemProcessHandeleInfo()可以获取当前系统的所有内核对象句柄信息并返回。
1 LPVOID GetSystemProcessHandleInfo() 2 { 3 ULONG cbBuffer = 0x4000; 4 LPVOID pBuffer = NULL; 5 NTSTATUS sts; 6 do 7 { 8 pBuffer = malloc(cbBuffer); 9 if(pBuffer == NULL) 10 { 11 cout<<"error alloc memory:"<<GetLastError()<<endl; 12 return NULL; 13 } 14 memset(pBuffer,0,cbBuffer); 15 16 sts = ZwQuerySystemInformation(SystemHandleInformation, pBuffer, cbBuffer, NULL); 17 if(sts == STATUS_INFO_LENGTH_MISMATCH) 18 { 19 free(pBuffer); 20 pBuffer = NULL; 21 cbBuffer = cbBuffer +0x4000; // 初始分配的空间不足+4000h 22 } 23 }while(sts == STATUS_INFO_LENGTH_MISMATCH); 24 return pBuffer; 25 }
2.EnumObjInfo()获取从返回的内核对象句柄信息中取出指定pid,指定句柄类型的内核对象,并打印:
void EnumObjInfo(LPVOID pBuffer,DWORD pid) { char szType[128] = {0}; char szName[512] = {0}; DWORD dwFlags = 0; POBJECT_NAME_INFORMATION pNameInfo; POBJECT_NAME_INFORMATION pNameType; PSYSTEM_HANDLE_INFORMATION_EX pInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer; ULONG OldPID = 0; for(DWORD i = 0; i < pInfo->NumberOfHandles; i++) { if(OldPID != pInfo->Information[i].ProcessId) { if(pInfo->Information[i].ProcessId==pid) { HANDLE newHandle; DuplicateHandle(OpenProcess(PROCESS_ALL_ACCESS,FALSE,pInfo->Information[i].ProcessId),(HANDLE)pInfo->Information[i].Handle,GetCurrentProcess(),&newHandle,DUPLICATE_SAME_ACCESS,FALSE,DUPLICATE_SAME_ACCESS); NTSTATUS status1=NtQueryObject(newHandle, ObjectNameInformation, szName, 512, &dwFlags); NTSTATUS status2=NtQueryObject(newHandle, ObjectTypeInformation, szType, 128, &dwFlags); if(strcmp(szName,"")&&strcmp(szType,"")&&status1!=0xc0000008&&status2!=0xc0000008) { pNameInfo = (POBJECT_NAME_INFORMATION)szName;
pNameType = (POBJECT_NAME_INFORMATION)szType; printf("%wZ ",pNameType); printf("%wZ ",pNameInfo); } } } }
}