驅動開發:內核取ntoskrnl模塊基地址

模塊是程序加載時被動態裝載的,模塊在裝載后其存在于內存中同樣存在一個內存基址,當我們需要操作這個模塊時,通常第一步就是要得到該模塊的內存基址 , 模塊分為用戶模塊和內核模塊,這里的用戶模塊指的是應用層進程運行后加載的模塊,內核模塊指的是內核中特定模塊地址,本篇文章將實現一個獲取驅動ntoskrnl.exe的基地址以及長度 , 此功能是驅動開發中尤其是安全軟件開發中必不可少的一個功能 。
關于該程序的解釋 , 官方的解析是這樣的ntoskrnl.exeWindows操作系統的一個重要內核程序,里面存儲了大量的二進制內核代碼,用于調度系統時使用 , 也是操作系統啟動后第一個被加載的程序,通常該進程在任務管理器中顯示為System 。
使用ARK工具也可看出其代表的是第一個驅動模塊 。
【驅動開發:內核取ntoskrnl模塊基地址】

驅動開發:內核取ntoskrnl模塊基地址

文章插圖
那么如何使用代碼得到如上圖中所展示的基地址以及大小呢,實現此功能我們需要調用ZwQuerySystemInformation這個API函數,這與上一篇文章《驅動開發:判斷自身是否加載成功》所使用的NtQuerySystemInformation只是開頭部分不同,但其本質上是不同的,如下是一些參考資料;
  • 從內核模式調用NtZw系列API,其最終都會連接到nooskrnl.lib導出庫:
    • Nt系列API將直接調用對應的函數代碼,而Zw系列API則通過調用KiSystemService最終跳轉到對應的函數代碼 。
    • 重要的是兩種不同的調用對內核中previous mode的改變,如果是從用戶模式調用Native APIprevious mode是用戶態,如果從內核模式調用Native APIprevious mode是內核態 。
    • 如果previous為用戶態時Native API將對傳遞的參數進行嚴格的檢查 , 而為內核態時則不會檢查 。
調用Nt API時不會改變previous mode的狀態,調用Zw API時會將previous mode改為內核態,因此在進行Kernel Mode Driver開發時可以使用Zw系列API可以避免額外的參數列表檢查 , 提高效率 。Zw*會設置KernelMode已避免檢查,Nt*不會自動設置,如果是KernelMode當然沒問題,如果就UserMode就掛了 。
回到代碼上來,下方代碼就是獲取ntoskrnl.exe基地址以及長度的具體實現,核心代碼就是調用ZwQuerySystemInformation得到SystemModuleInformation,里面的對比部分是在比較當前獲取的地址是否超出了ntoskrnl的最大和最小范圍 。
#include <ntifs.h>static PVOID g_KernelBase = 0;static ULONG g_KernelSize = 0;#pragma pack(4)typedef struct _PEB32{ UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR BitField; ULONG Mutant; ULONG ImageBaseAddress; ULONG Ldr; ULONG ProcessParameters; ULONG SubSystemData; ULONG ProcessHeap; ULONG FastPebLock; ULONG AtlThunkSListPtr; ULONG IFEOKey; ULONG CrossProcessFlags; ULONG UserSharedInfoPtr; ULONG SystemReserved; ULONG AtlThunkSListPtr32; ULONG ApiSetMap;} PEB32, *PPEB32;typedef struct _PEB_LDR_DATA32{ ULONG Length; UCHAR Initialized; ULONG SsHandle; LIST_ENTRY32 InLoadOrderModuleList; LIST_ENTRY32 InMemoryOrderModuleList; LIST_ENTRY32 InInitializationOrderModuleList;} PEB_LDR_DATA32, *PPEB_LDR_DATA32;typedef struct _LDR_DATA_TABLE_ENTRY32{ LIST_ENTRY32 InLoadOrderLinks; LIST_ENTRY32 InMemoryOrderLinks; LIST_ENTRY32 InInitializationOrderLinks; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING32 FullDllName; UNICODE_STRING32 BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; LIST_ENTRY32 HashLinks; ULONG TimeDateStamp;} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;#pragma pack()typedef struct _RTL_PROCESS_MODULE_INFORMATION{ HANDLE Section; PVOID MappedBase; PVOID ImageBase; ULONG ImageSize; ULONG Flags; USHORT LoadOrderIndex; USHORT InitOrderIndex; USHORT LoadCount; USHORT OffsetToFileName; UCHARFullPathName[256];} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;typedef struct _RTL_PROCESS_MODULES{ ULONG NumberOfModules; RTL_PROCESS_MODULE_INFORMATION Modules[1];} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;typedef enum _SYSTEM_INFORMATION_CLASS{ SystemModuleInformation = 0xb,} SYSTEM_INFORMATION_CLASS;// 取出KernelBase基地址// By: lyshark.comPVOID UtilKernelBase(OUT PULONG pSize){ NTSTATUS status = STATUS_SUCCESS; ULONG bytes = 0; PRTL_PROCESS_MODULES pMods = 0; PVOID checkPtr = 0; UNICODE_STRING routineName; if (g_KernelBase != 0) {if (pSize)*pSize = g_KernelSize;return g_KernelBase; } RtlInitUnicodeString(&routineName, L"NtOpenFile"); checkPtr = MmGetSystemRoutineAddress(&routineName); if (checkPtr == 0)return 0; __try {status = ZwQuerySystemInformation(SystemModuleInformation, 0, bytes, &bytes);if (bytes == 0){DbgPrint("Invalid SystemModuleInformation size\n");return 0;}pMods = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPoolNx, bytes, "lyshark");RtlZeroMemory(pMods, bytes);status = ZwQuerySystemInformation(SystemModuleInformation, pMods, bytes, &bytes);if (NT_SUCCESS(status)){PRTL_PROCESS_MODULE_INFORMATION pMod = pMods->Modules;for (ULONG i = 0; i < pMods->NumberOfModules; i++){if (checkPtr >= pMod[i].ImageBase &&checkPtr < (PVOID)((PUCHAR)pMod[i].ImageBase + pMod[i].ImageSize)){g_KernelBase = pMod[i].ImageBase;g_KernelSize = pMod[i].ImageSize;if (pSize)*pSize = g_KernelSize;break;}}} } __except (EXCEPTION_EXECUTE_HANDLER) {return 0; } if (pMods)ExFreePoolWithTag(pMods, "lyshark"); return g_KernelBase;}VOID UnDriver(PDRIVER_OBJECT driver){ DbgPrint(("Uninstall Driver Is OK \n"));}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ DbgPrint(("hello lyshark \n")); PULONG ulong = 0; UtilKernelBase(ulong); DbgPrint("ntoskrnl.exe 模塊基址: 0x%p \n", g_KernelBase); DbgPrint("模塊大小: 0x%p \n", g_KernelSize); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS;}

推薦閱讀