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 higher
	MODULES		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 higher

PLIST_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()


Posted by 울랄라베베
:

카테고리

분류 전체보기 (20)
Kernel programming (13)
User porgramming (2)
Etc... (2)