驅動開發:內核枚舉DpcTimer定時器( 二 )

如上匯編代碼KiSetTimerEx中就是DPC加密細節,如果需要解密只需要逆操作即可,此處我就具體分析下加密細節,分析這個東西我建議你使用記事本帶著色的 。
分析思路是這樣的,首先這里要傳入待加密的DPC數據,然后經過KiWaitNeverKiWaitAlways對數據進行xor,ror,bswap等操作 。

驅動開發:內核枚舉DpcTimer定時器

文章插圖
將解密流程通過代碼的方式實現 。
#include <ntddk.h>#include <ntstrsafe.h>// 解密DPCvoid DPC_Print(PKTIMER ptrTimer){ULONG_PTR ptrDpc = (ULONG_PTR)ptrTimer->Dpc;KDPC* DecDpc = NULL;DWORD nShift = (p2dq(ptrKiWaitNever) & 0xFF);// _RSI->Dpc = (_KDPC *)v19;// _RSI = Timer;ptrDpc ^= p2dq(ptrKiWaitNever);// v19 = KiWaitNever ^ v18;ptrDpc = _rotl64(ptrDpc, nShift);// v18 = __ROR8__((unsigned __int64)Timer ^ _RBX, KiWaitNever);ptrDpc ^= (ULONG_PTR)ptrTimer;ptrDpc = _byteswap_uint64(ptrDpc);// __asm { bswaprbx }ptrDpc ^= p2dq(ptrKiWaitAlways);// _RBX = (unsigned __int64)DPC ^ KiWaitAlways;// real DPCif (MmIsAddressValid((PVOID)ptrDpc)){DecDpc = (KDPC*)ptrDpc;DbgPrint("DPC = %p | routine = %p \n", DecDpc, DecDpc->DeferredRoutine);}}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("卸載完成... \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("hello lyshark.com");PKTIMER ptrTimer = NULL;DPC_Print(ptrTimer);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}接著將這些功能通過代碼實現 , 首先得到我們需要的函數地址,這些地址包括 。
ULONG_PTR ptrKiProcessorBlock = 0xfffff80770a32cc0;ULONG_PTR ptrOffsetKTimerTable = 0x3680;ULONG_PTR ptrKiWaitNever = 0xfffff80770a316f8;ULONG_PTR ptrKiWaitAlways = 0xfffff80770a318e8;此處我把它分為三步走,第一步找到KiProcessorBlock函數地址 , 第二步找到KeSetTimer并從里面尋找KeSetTimerEx , 第三步根據KiSetTimerEx地址 , 搜索到KiWaitNever(),KiWaitAlways()這兩個函數內存地址,最終循環鏈表并解密DPC隊列 。
第一步: 找到KiProcessorBlock函數地址,該地址可通過__readmsr()寄存器相加偏移得到 。
在WinDBG中可以輸入rdmsr c0000082得到MSR地址 。
驅動開發:內核枚舉DpcTimer定時器

文章插圖
MSR寄存器使用代碼獲取也是很容易,只要找到MSR地址在加上0x20即可得到KiProcessorBlock的地址了 。
/*lyshark.com 0: kd> dp !KiProcessorBlockfffff807`70a32cc0fffff807`6f77c180 ffffbe81`3cee0180fffff807`70a32cd000000000`00000000 00000000`00000000fffff807`70a32ce000000000`00000000 00000000`00000000fffff807`70a32cf000000000`00000000 00000000`00000000fffff807`70a32d0000000000`00000000 00000000`00000000fffff807`70a32d1000000000`00000000 00000000`00000000fffff807`70a32d2000000000`00000000 00000000`00000000fffff807`70a32d3000000000`00000000 00000000`00000000*/#include <ntddk.h>#include <ntstrsafe.h>// 得到KiProcessorBlock地址ULONG64 GetKiProcessorBlock(){ULONG64 PrcbAddress = 0;PrcbAddress = (ULONG64)__readmsr(0xC0000101) + 0x20;if (PrcbAddress != 0){// PrcbAddress 是一個地址 這個地址存放了某個 CPU 的 _KPRCB 的地址return *(ULONG_PTR*)PrcbAddress;}return 0;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("卸載完成... \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("hello lyshark.com \n");ULONG64 address = GetKiProcessorBlock();if (address != 0){DbgPrint("KiProcessorBlock = %p \n", address);}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}運行后即可得到輸出效果如下:
驅動開發:內核枚舉DpcTimer定時器

文章插圖
第二步: 找到KeSetTimer從里面搜索特征得到call KeSetTimerEx函數地址,還記得《驅動開發:內核枚舉IoTimer定時器》中我們采用的特征碼定位方式嗎,沒錯本次還要使用這個方法,我們此處需要搜索到e80c000000這段特征 。
/*lyshark.com 0: kd> uf KeSetTimernt!KeSetTimer:fffff807`70520a30 4883ec38subrsp,38hfffff807`70520a34 4c89442420movqword ptr [rsp+20h],r8fffff807`70520a39 4533c9xorr9d,r9dfffff807`70520a3c 4533c0xorr8d,r8dfffff807`70520a3f e80c000000callnt!KiSetTimerEx (fffff807`70520a50)fffff807`70520a44 4883c438addrsp,38hfffff807`70520a48 c3ret*/#include <ntddk.h>#include <ntstrsafe.h>// 得到KiProcessorBlock地址ULONG64 GetKeSetTimerEx(){// 獲取 KeSetTimer 地址ULONG64 ul_KeSetTimer = 0;UNICODE_STRINGuc_KeSetTimer = { 0 };RtlInitUnicodeString(&uc_KeSetTimer, L"KeSetTimer");ul_KeSetTimer = (ULONG64)MmGetSystemRoutineAddress(&uc_KeSetTimer);if (ul_KeSetTimer == 0){return 0;}// 前 30 字節找 call 指令BOOLEAN b_e8 = FALSE;ULONG64 ul_e8Addr = 0;for (INT i = 0; i < 30; i++){// 驗證地址是否可讀寫if (!MmIsAddressValid((PVOID64)ul_KeSetTimer)){continue;}// e8 0c 00 00 00 call nt!KiSetTimerEx (fffff807`70520a50)if (*(PUCHAR)(ul_KeSetTimer + i) == 0xe8){b_e8 = TRUE;ul_e8Addr = ul_KeSetTimer + i;break;}}// 找到 call 則解析目的地址if (b_e8 == TRUE){if (!MmIsAddressValid((PVOID64)ul_e8Addr)){return 0;}INT ul_callCode = *(INT*)(ul_e8Addr + 1);ULONG64 ul_KiSetTimerEx = ul_e8Addr + ul_callCode + 5;return ul_KiSetTimerEx;}return 0;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("卸載完成... \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("hello lyshark.com \n");ULONG64 address = GetKeSetTimerEx();if (address != 0){DbgPrint("KeSetTimerEx = %p \n", address);}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

推薦閱讀