《Windows核心编程》第3章——handle复制相关实验
- 先写一个程序,用来查看进程的内核对象,这样我们就能比较子进程是否继承了父进程的某个句柄:
#include <windows.h> #include <stdio.h> #define NT_SUCCESS(x) ((x) >= 0) #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 #define SystemHandleInformation 16 #define ObjectBasicInformation 0 #define ObjectNameInformation 1 #define ObjectTypeInformation 2 typedef NTSTATUS(NTAPI *_NtQuerySystemInformation)( ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); typedef NTSTATUS(NTAPI *_NtDuplicateObject)( HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, ULONG Attributes, ULONG Options ); typedef NTSTATUS(NTAPI *_NtQueryObject)( HANDLE ObjectHandle, ULONG ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength ); typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _SYSTEM_HANDLE { ULONG ProcessId; BYTE ObjectTypeNumber; BYTE Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE, *PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG HandleCount; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef enum _POOL_TYPE { NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, NonPagedPoolCacheAligned, PagedPoolCacheAligned, NonPagedPoolCacheAlignedMustS } POOL_TYPE, *PPOOL_TYPE; typedef struct _OBJECT_TYPE_INFORMATION { UNICODE_STRING Name; ULONG TotalNumberOfObjects; ULONG TotalNumberOfHandles; ULONG TotalPagedPoolUsage; ULONG TotalNonPagedPoolUsage; ULONG TotalNamePoolUsage; ULONG TotalHandleTableUsage; ULONG HighWaterNumberOfObjects; ULONG HighWaterNumberOfHandles; ULONG HighWaterPagedPoolUsage; ULONG HighWaterNonPagedPoolUsage; ULONG HighWaterNamePoolUsage; ULONG HighWaterHandleTableUsage; ULONG InvalidAttributes; GENERIC_MAPPING GenericMapping; ULONG ValidAccess; BOOLEAN SecurityRequired; BOOLEAN MaintainHandleCount; USHORT MaintainTypeList; POOL_TYPE PoolType; ULONG PagedPoolUsage; ULONG NonPagedPoolUsage; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) { return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); } int main(int argc, WCHAR *argv[]) { NTSTATUS status; ULONG pid; HANDLE processHandle; ULONG handleInfoSize = 0x10000; PSYSTEM_HANDLE_INFORMATION handleInfo; HANDLE dupHandle = NULL; ULONG returnLength; int nCount = 0; pid = 13104;//Input which process do you want to query. _NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); if (NULL == NtQuerySystemInformation){ printf("Get address of NtQuerySystemInformation failed!\n"); return FALSE; } _NtDuplicateObject NtDuplicateObject = (_NtDuplicateObject)GetLibraryProcAddress("ntdll.dll", "NtDuplicateObject"); if (NULL == NtDuplicateObject){ printf("Get address of NtDuplicateObject failed!\n"); return FALSE; } _NtQueryObject NtQueryObject = (_NtQueryObject)GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); if (NULL == NtQueryObject){ printf("Get address of NtQueryObject failed!\n"); return FALSE; } if (!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid))){ printf("Open process failed!\n"); return FALSE; } handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); while ((status = NtQuerySystemInformation(//Query system handle information, if return STATUS_INFO_LENGTH_MISMATCH, you should realloc space. SystemHandleInformation, handleInfo, handleInfoSize, NULL )) == STATUS_INFO_LENGTH_MISMATCH){ handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);//assign new value to handleInfoSize } if (!NT_SUCCESS(status)) { return FALSE; } for (int i = 0; i < handleInfo->HandleCount; i++)//reverse all handles { SYSTEM_HANDLE handle = handleInfo->Handles[i]; POBJECT_TYPE_INFORMATION objectTypeInfo; PVOID objectNameInfo; UNICODE_STRING objectName; if (handle.ProcessId != pid) continue; if (!NT_SUCCESS(status = NtDuplicateObject(//duplicate handle information into self. processHandle, (HANDLE)handle.Handle, GetCurrentProcess(), &dupHandle, 0, 0, 0 ))) { continue; } //////////////////////////////////////////////////////////////////////////////////// //you can query objectNameInfo directly. objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); if (!NT_SUCCESS(status = NtQueryObject(//Get the object according handle. dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL ))) { printf("Query [%#x] Error:%x!\n", handle.Handle, status); CloseHandle(dupHandle); continue; } if (handle.GrantedAccess == 0x0012019f) { /* We have the type, so display that. */ printf( "[%#x] %.*S: (did not get name)\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); free(objectTypeInfo); CloseHandle(dupHandle); continue; } objectNameInfo = malloc(0x1000); if (!NT_SUCCESS(NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength ))){ objectNameInfo = realloc(objectNameInfo, returnLength); if (!NT_SUCCESS(NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, returnLength, NULL ))) { /* We have the type name, so just display that. */ printf( "[%#x] %.*S: (could not get name)\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); free(objectTypeInfo); free(objectNameInfo); CloseHandle(dupHandle); continue; } } objectName = *(PUNICODE_STRING)objectNameInfo; if (objectName.Length) { /* The object has a name. */ printf( "[%#x] %.*S: %.*S\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer, objectName.Length / 2, objectName.Buffer ); } else { /* Print something else. */ printf( "[%#x] %.*S: (unnamed)\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); } nCount++; free(objectTypeInfo); free(objectNameInfo); CloseHandle(dupHandle); } printf("Handle Count:%d\n", nCount); free(handleInfo); CloseHandle(processHandle); getchar(); }
- 然后父进程就随便写一个,主要是为了创建三个命名内核对象,然后让子进程继承其中的两个:
#include <iostream> #include <windows.h> void main(){ SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE;//if the handle can be inherited. HANDLE hMuxtex1 = CreateMutex(&sa, FALSE, "TestHandle1"); HANDLE hMuxtex2 = CreateMutex(NULL, FALSE, "TestHandle2"); HANDLE hMuxtex3 = CreateMutex(&sa, FALSE, "TestHandle3"); STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); CreateProcess(NULL, "E:\\Coding\\Cpp\\test\\Windows_Core\\P96_3\\Debug\\P96_3.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); while (TRUE); }
- 验证结果
父进程创建的三个互斥量句柄:
然后再去查看子进程:
果然之继承了其中的1和3句柄。