NTSTATUS WINAPI NtQuerySystemInformation( __in SYSTEM_INFORMATION_CLASS SystemInformationClass, __inout PVOID SystemInformation, __in ULONG SystemInformationLength, __out_opt PULONG ReturnLength );* Kernel DLL export 드라이버내에서 위 함수를 사용시 C0000005L (STATUS_ACCESS_VIOLATION) 만을 반환하는 경우가 발생하였다.
* 인자를 잘못준것인가 한참을 헤메다가, Nt~ 함수 대신 Zw~를 호출하자 정상적으로 C00000004L 을 반환했다.
* 만약 이와 같은 경우가 생긴다면, 아래 사용된 NtQuerySystemInformation 대신에 ZwQuerySystemInformation를 사용하기 바란다.
* 프로토 타입 및 사용법은 모두 NtQuerySystemInformation와 동일하다.
예) 커널(nt)의 Base및 End(Base+Size) 얻기KernelGetModuleBase
NT 4.0 and higherMODULES module = {0, }; DWORD dwNeededSize = 0; NTSTATUS ntStatus = STATUS_SUCCESS; PVOID pDriverStart = NULL; PVOID pDriverEnd = NULL; PSYSTEM_MODULE_INFORMATION pSysModInfo = NULL; // 2번째 인자에 pSysModInfo, 3번째에 sizeof(pSysModInfo) 혹은 0을 // 넣는것이 보통이나, sizeof(MODULES)의 배수가 아닐경우 ERROR가 // 반환되는 경우가 있었음. ntStatus = NtQuerySystemInformation( SystemModuleInformation, &module, /*pSysModInfo*/ sizeof(module), /*sizeof(pSysModInfo) or 0*/ &dwNeededSize ); if (STATUS_INFO_LENGTH_MISMATCH == ntStatus) { pSysModInfo = ExAllocatePoolWithTag(NonPagedPool, dwNeededSize, 'GETK'); if (pSysModInfo) { ntStatus = NtQuerySystemInformation(SystemModuleInformation, pSysModInfo, dwNeededSize, NULL ); if (NT_SUCCESS(ntStatus)) { int i; for (i=0; i<(int)pSysModInfo->dwNumberOfModules; ++i) { StrUpr(pSysModInfo->smi[i].ImageName); // Convert characters to uppercase // [ Four retail(release) variations ] // NTOSKRNL.EXE --------- Uniprocessor // NTKRNLMP.EXE --------- Multiprocessor // Windows 2000 adds PAE(Physical address extension) // versions - must boot /PAE // NTKRNLPA.EXE ---------- Uniprocessor // NTKRPAMP.EXE ---------- Multiprocessor if (strstr(pSysModInfo->smi[i].ImageName, "\\NTOSKRNL.EXE")) { pDriverStart = pSysModInfo->smi[i].Base; pDriverEnd = (VOID *)((DWORD_PTR)pSysModInfo->smi[i].Base + (DWORD_PTR)pSysModInfo->smi[i].Size); break; } } } else { return; // 실패 } ExFreePool(pSysModInfo) pSysModInfo = NULL; } }위의 코드에서 사용된 타입 정의이다.
typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 SystemProcessorInformation, // 1 SystemPerformanceInformation, // 2 SystemTimeOfDayInformation, // 3 SystemNotImplemented1, // 4 SystemProcessesAndThreadsInformation, // 5 SystemCallCounts, // 6 SystemConfigurationInformation, // 7 SystemProcessorTimes, // 8 SystemGlobalFlag, // 9 SystemNotImplemented2, // 10 SystemModuleInformation, // 11 SystemLockInformation, // 12 SystemNotImplemented3, // 13 SystemNotImplemented4, // 14 SystemNotImplemented5, // 15 SystemHandleInformation, // 16 SystemObjectInformation, // 17 SystemPagefileInformation, // 18 SystemInstructionEmulationCounts, // 19 SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 SystemPoolTagInformation, // 22 SystemProcessorStatistics, // 23 SystemDpcInformation, // 24 SystemNotImplemented6, // 25 SystemLoadImage, // 26 SystemUnloadImage, // 27 SystemTimeAdjustment, // 28 SystemNotImplemented7, // 29 SystemNotImplemented8, // 30 SystemNotImplemented9, // 31 SystemCrashDumpInformation, // 32 SystemExceptionInformation, // 33 SystemCrashDumpStateInformation, // 34 SystemKernelDebuggerInformation, // 35 SystemContextSwitchInformation, // 36 SystemRegistryQuotaInformation, // 37 SystemLoadAndCallImage, // 38 SystemPrioritySeparation, // 39 SystemNotImplemented10, // 40 SystemNotImplemented11, // 41 SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 SystemLookasideInformation, // 45 SystemSetTimeSlipEvent, // 46 SystemCreateSession, // 47 SystemDeleteSession, // 48 SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 SystemVerifierInformation, // 51 SystemAddVerifier, // 52 SystemSessionProcessesInformation // 53 } SYSTEM_INFORMATION_CLASS; typedef struct HandleInfo{ ULONG Pid; USHORT ObjectType; USHORT HandleValue; PVOID ObjectPointer; ULONG AccessMask; } HANDLEINFO, *PHANDLEINFO; typedef struct SystemHandleInfo { ULONG nHandleEntries; HANDLEINFO HandleInfo[1]; } SYSTEMHANDLEINFO, *PSYSTEMHANDLEINFO; NTSTATUS (NTAPI *pNtQuerySystemInformation)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllTypesInformation, ObjectHandleInformation } OBJECT_INFORMATION_CLASS; typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING ObjectName; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; typedef struct _OBJECT_BASIC_INFORMATION { ULONG Unknown1; ACCESS_MASK DesiredAccess; ULONG HandleCount; ULONG ReferenceCount; ULONG PagedPoolQuota; ULONG NonPagedPoolQuota; BYTE Unknown2[32]; } OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
아래의 구조체는 x64환경과 x86환경에서 차이가 있음을 확인하고 DWORD변수를 DWORD_PTR로 수정하였다. 아래의 구조체들을 제외한, 위쪽에 정의되어 있는 구조체들은 확인하지 않았으므로 x64환경에서 호환여부는 장담할 수 없다.
#pragma pack(1) typedef struct _MODULES { DWORD_PTR Reserved[2]; // x64: 16bytes, x86: 8bytes PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; }MODULES,*PMODULES; #pragma pack() #pragma pack(1) typedef struct _SYSTEM_MODULE_INFORMATION{ DWORD_PTR dwNumberOfModules; // x64: 8bytes, x86: 4bytes MODULES smi[0]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; #pragma pack()
아래는 nt 3.51과 호환성을 가지는 '커널 베이스주소 얻기'에 대한 예제코드이다.
[이하 출처] http://alter.org.ua/docs/nt_kernel/procaddr/index3.php
typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY LoadOrder; LIST_ENTRY MemoryOrder; LIST_ENTRY InitializationOrder; PVOID ModuleBaseAddress; PVOID EntryPoint; ULONG ModuleSize; UNICODE_STRING FullModuleName; UNICODE_STRING ModuleName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY Hash; struct { PVOID SectionPointer; ULONG CheckSum; }; }; ULONG TimeStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
KernelGetModuleBase3
NT 3.51 and higherPLIST_ENTRY g_LoadOrderListHead = NULL; // Global variable PVOID KernelGetModuleBase3( PDRIVER_OBJECT DriverObject, PCHAR pModuleName ) { PVOID pModuleBase = NULL; PLIST_ENTRY Next; PLIST_ENTRY LoadOrderListHead; UNICODE_STRING uStr; PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; PLDR_DATA_TABLE_ENTRY LdrDataTableEntry0; ULONG len; BOOLEAN FreeUstr = FALSE; uStr.Buffer = NULL; __try { if(!g_LoadOrderListHead) { LdrDataTableEntry0 = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; uStr.Length = sizeof(L"NTOSKRNL.EXE") - sizeof(WCHAR); uStr.MaximumLength = sizeof(L"NTOSKRNL.EXE"); uStr.Buffer = L"NTOSKRNL.EXE"; Next = LdrDataTableEntry0->LoadOrder.Blink; while ( TRUE ) { LdrDataTableEntry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, LoadOrder ); Next = Next->Blink; if(!LdrDataTableEntry->ModuleName.Buffer) { return NULL; } if(RtlCompareUnicodeString( &LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0) { LoadOrderListHead = Next; break; } if(LdrDataTableEntry == LdrDataTableEntry0) { return NULL; } } g_LoadOrderListHead = LoadOrderListHead; } else { LoadOrderListHead = g_LoadOrderListHead; } len = strlen(pModuleName); if(!len) { return NULL; } len = (len+1) * sizeof(WCHAR); uStr.MaximumLength = (USHORT)len; uStr.Length = (USHORT)len - sizeof(WCHAR); uStr.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, len); FreeUstr = TRUE; swprintf(uStr.Buffer, L"%S", pModuleName); Next = LoadOrderListHead->Flink; while ( Next != LoadOrderListHead ) { LdrDataTableEntry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, LoadOrder ); if(RtlCompareUnicodeString( &LdrDataTableEntry->ModuleName, &uStr, TRUE) == 0) { pModuleBase = LdrDataTableEntry->ModuleBaseAddress; break; } Next = Next->Flink; } } __except(EXCEPTION_EXECUTE_HANDLER) { pModuleBase = NULL; } if(FreeUstr && uStr.Buffer) { ExFreePool(uStr.Buffer); } return pModuleBase; } // end KernelGetModuleBase3()