驱动开发:内核枚举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;}

推荐阅读