Win64 驱动内核编程-8.内核里的其他常用
內核里的其他常用
1.遍歷鏈表。內核里有很多數據結構,但它們并不是孤立的,內核使用雙向鏈表把它們像糖
葫蘆一樣給串了起來。所以遍歷雙向鏈表能獲得很多重要的內核數據。舉個簡單的例子,驅
動對象?DriverObject?就是使用雙向鏈表給串起來的,遍歷這個鏈表就可以枚舉內核里所有的驅動。示例代碼如下
//傳入驅動自身的 DriverObject VOID EnumDriver(PDRIVER_OBJECT pDriverObject) { PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; PKLDR_DATA_TABLE_ENTRY firstentry; ULONG64 pDrvBase = 0; KIRQL OldIrql; firstentry = entry; //當發現又找到自己時跳出循環,否則成了死循環。 while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry) { DbgPrint("BASE=%p\tPATH=%wZ", entry->DllBase, entry->FullDllName); entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink; } }2.等待。這個等于?RING3?的?Sleep?函數了。
#define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000) VOID MySleep(LONG msec) { LARGE_INTEGER my_interval; my_interval.QuadPart = DELAY_ONE_MILLISECOND; my_interval.QuadPart *= msec; KeDelayExecutionThread(KernelMode, 0, &my_interval); }3.同步。這個可以理解成是“條件等待”。常用的是?KeWaitForSingleObject、KeInitializeEvent、
KeSetEvent?這幾個函數。為了方便講解,這個的示例代碼與“內核線程”放在一起。先把這
幾個函數的原型貼出來。
NTSTATUS KeWaitForSingleObject ( _In_ PVOID Object, _In_ KWAIT_REASON WaitReason, _In_ KPROCESSOR_MODE WaitMode, _In_ BOOLEAN Alertable, _In_opt_ PLARGE_INTEGER Timeout ); VOID KeInitializeEvent ( _Out_ PRKEVENT Event, _In_ EVENT_TYPE Type, _In_ BOOLEAN State ); LONG KeSetEvent ( _Inout_ PRKEVENT Event, _In_ KPRIORITY Increment, _In_ BOOLEAN Wait );4.獲得系統版本號。內核編程難免使用硬編碼,以及使用一些高版本系統才出現的函數。為
了使得驅動能在低版本的系統上正常運行,就需要根據不同系統做不同處理了。
VOID GetVersion() { ULONG NtBuildNumber; RTL_OSVERSIONINFOW osi; osi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); RtlFillMemory(&osi, sizeof(RTL_OSVERSIONINFOW), 0); RtlGetVersion(&osi); NtBuildNumber = osi.dwBuildNumber; DbgPrint("NtBuildNumber: %ld\n", NtBuildNumber); return NtBuildNumber; }5.獲得系統時間。在內核里獲得系統時間的是標準時間(GMT+0),轉換成本地時間還需要進
行轉換。此功能在發布測試版軟件的時候特別有用,限制人們只能在指定時間之前使用。
VOID MyGetCurrentTime() { LARGE_INTEGER CurrentTime; LARGE_INTEGER LocalTime; TIME_FIELDS TimeFiled; // 這里得到的其實是格林威治時間 KeQuerySystemTime(&CurrentTime); // 轉換成本地時間 ExSystemTimeToLocalTime(&CurrentTime, &LocalTime); // 把時間轉換為容易理解的形式 RtlTimeToTimeFields(&LocalTime, &TimeFiled); DbgPrint("[TimeTest] NowTime : %4d-%2d-%2d %2d:%2d:%2d", TimeFiled.Year, TimeFiled.Month, TimeFiled.Day, TimeFiled.Hour, TimeFiled.Minute, TimeFiled.Second); }6.內核線程。內核線程就是名義上屬于?SYSTEM?進程的線程。比如說你要做壞事,卻讓?SYSTEM
進程背黑鍋,是一件很爽的事情。內核線程還有幾個特點:1.?PreviousMode?是?KernelMode,
可以直接調用?Nt?開頭的內核函數(Nt?開頭的內核函數會檢查?PreviousMode,如果
PreviousMode?不是?KernelMode,就會拒絕服務。有些人喜歡直接修改?ETHREAD?里的這個值,
但我個人覺得這么改不妥當)。2.內核線程不會自己結束,必須調用?PsTerminateSystemThread
才能被動結束。以下是例子,?同時演示了?等待?、同步和內核線程的使用。
KEVENT kEvent; //事件//線程函數 VOID MyThreadFunc(IN PVOID context) { PUNICODE_STRING str = (PUNICODE_STRING)context; DbgPrint("Kernel thread running: %wZ\n", str); DbgPrint("Wait 3s!\n"); MySleep(3000); DbgPrint("Kernel thread exit!\n"); KeSetEvent(&kEvent, 0, TRUE); PsTerminateSystemThread(STATUS_SUCCESS); } //創建線程的函數 VOID CreateThreadTest() { HANDLE hThread; UNICODE_STRING ustrTest = RTL_CONSTANT_STRING(L"This is a string for test!"); NTSTATUS status; // 初始化事件 KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE); status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, MyThreadFunc, (PVOID)&ustrTest); if (!NT_SUCCESS(status)) { DbgPrint("PsCreateSystemThread failed!"); return; } ZwClose(hThread); // 等待事件 KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL); DbgPrint("CreateThreadTest OVER!\n"); }7.強制重啟計算機。在內核里直接使用?OUT?指令就能強制重啟計算機而不可能被任何鉤子
攔截。此代碼可以用在反調試里。
VOID ForceReboot() { typedef void(__fastcall *FCRB)(void); /* mov al, 0FEh out 64h, al ret */ FCRB fcrb = NULL; UCHAR shellcode[6] = "\xB0\xFE\xE6\x64\xC3"; fcrb = ExAllocatePool(NonPagedPool, 5); memcpy(fcrb, shellcode, 5); fcrb(); }8.強制關閉計算機。在內核里直接使用?OUT?指令就能強制關閉計算機而不可能被任何鉤子
攔截。此代碼可以用在反調試里。
VOID ForceShutdown() { typedef void(__fastcall *FCRB)(void); /* mov ax,2001h mov dx,1004h out dx,ax ret */ FCRB fcrb = NULL; UCHAR shellcode[12] = "\x66\xB8\x01\x20\x66\xBA\x04\x10\x66\xEF\xC3"; fcrb = ExAllocatePool(NonPagedPool, 11); memcpy(fcrb, shellcode, 11); fcrb(); }總結
以上是生活随笔為你收集整理的Win64 驱动内核编程-8.内核里的其他常用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win64 驱动内核编程-6.内核里操作
- 下一篇: 10.PHP加密相关