驱动开发:Win10内核枚举SSDT表基址( 二 )

如上代码中所提及的步骤我想不需要再做解释了,这段代码运行后即可输出SSDT表的基址 。

驱动开发:Win10内核枚举SSDT表基址

文章插图
如上通过调用GetLySharkCOMKeServiceDescriptorTable()得到SSDT地址以后我们就需要对该地址进行解密操作 。
得到ServiceTableBase的地址后,就能得到每个服务函数的地址 。但这个表存放的并不是SSDT函数的完整地址,而是其相对于ServiceTableBase[Index]>>4的数据,每个数据占四个字节,所以计算指定Index函数完整地址的公式是;
  • 在x86平台上: FuncAddress = KeServiceDescriptorTable + 4 * Index
  • 在x64平台上:FuncAddress = [KeServiceDescriptorTable+4*Index]>>4 + KeServiceDescriptorTable
如下汇编代码就是一段解密代码,代码中rcx寄存器传入SSDT的下标,而rdx寄存器则是传入SSDT表基址 。
48:8BC1| mov rax,rcx|rcx=index4C:8D12| lea r10,qword ptr ds:[rdx]|rdx=ssdt8BF8| mov edi,eax|C1EF 07| shr edi,7|83E7 20| and edi,20|4E:8B1417| mov r10,qword ptr ds:[rdi+r10]|4D:631C82| movsxd r11,dword ptr ds:[r10+rax*4]|49:8BC3| mov rax,r11|49:C1FB 04| sar r11,4|4D:03D3| add r10,r11|49:8BC2| mov rax,r10|C3| ret|有了解密公式以后代码的编写就变得很容易,如下是读取SSDT的完整代码 。
// 署名权// right to sign one's name on a piece of work// PowerBy: LyShark// Email: me@lyshark.com#include <ntifs.h>#pragma intrinsic(__readmsr)typedef struct _SYSTEM_SERVICE_TABLE{ PVOIDServiceTableBase; PVOIDServiceCounterTableBase; ULONGLONGNumberOfServices; PVOIDParamTableBase;} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;ULONGLONG ssdt_base_aadress;PSYSTEM_SERVICE_TABLE KeServiceDescriptorTable;typedef UINT64(__fastcall *SCFN)(UINT64, UINT64);SCFN scfn;// 解密算法VOID DecodeSSDT(){ UCHAR strShellCode[36] = "\x48\x8B\xC1\x4C\x8D\x12\x8B\xF8\xC1\xEF\x07\x83\xE7\x20\x4E\x8B\x14\x17\x4D\x63\x1C\x82\x49\x8B\xC3\x49\xC1\xFB\x04\x4D\x03\xD3\x49\x8B\xC2\xC3"; /* 48:8BC1| mov rax,rcx|rcx=index 4C:8D12| lea r10,qword ptr ds:[rdx]|rdx=ssdt 8BF8| mov edi,eax| C1EF 07| shr edi,7| 83E7 20| and edi,20| 4E:8B1417| mov r10,qword ptr ds:[rdi+r10]| 4D:631C82| movsxd r11,dword ptr ds:[r10+rax*4]| 49:8BC3| mov rax,r11| 49:C1FB 04| sar r11,4| 4D:03D3| add r10,r11| 49:8BC2| mov rax,r10| C3| ret| */ scfn = ExAllocatePool(NonPagedPool, 36); memcpy(scfn, strShellCode, 36);}// 获取 KeServiceDescriptorTable 首地址ULONGLONG GetKeServiceDescriptorTable(){ // 设置起始位置 PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1806FE; // 设置结束位置 PUCHAR EndSearchAddress = StartSearchAddress + 0x8192; DbgPrint("扫描起始地址: %p --> 扫描结束地址: %p \n", StartSearchAddress, EndSearchAddress); PUCHAR ByteCode = NULL; UCHAR OpCodeA = 0, OpCodeB = 0, OpCodeC = 0; ULONGLONG addr = 0; ULONG templong = 0; for (ByteCode = StartSearchAddress; ByteCode < EndSearchAddress; ByteCode++) {// 使用MmIsAddressValid()函数检查地址是否有页面错误if (MmIsAddressValid(ByteCode) && MmIsAddressValid(ByteCode + 1) && MmIsAddressValid(ByteCode + 2)){OpCodeA = *ByteCode;OpCodeB = *(ByteCode + 1);OpCodeC = *(ByteCode + 2);// 对比特征值 寻找 nt!KeServiceDescriptorTable 函数地址// LyShark.com// 4c 8d 15 e5 9e 3b 00lea r10,[nt!KeServiceDescriptorTable (fffff802`64da4880)]// 4c 8d 1d de 20 3a 00lea r11,[nt!KeServiceDescriptorTableShadow (fffff802`64d8ca80)]if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x15){// 获取高位地址fffff802memcpy(&templong, ByteCode + 3, 4);// 与低位64da4880地址相加得到完整地址addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7;return addr;}} } return0;}// 得到函数相对偏移地址ULONG GetOffsetAddress(ULONGLONG FuncAddr){ ULONG dwtmp = 0; PULONG ServiceTableBase = NULL; if (KeServiceDescriptorTable == NULL) {KeServiceDescriptorTable = (PSYSTEM_SERVICE_TABLE)GetKeServiceDescriptorTable(); } ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase; dwtmp = (ULONG)(FuncAddr - (ULONGLONG)ServiceTableBase); return dwtmp << 4;}// 根据序号得到函数地址ULONGLONG GetSSDTFunctionAddress(ULONGLONG NtApiIndex){ ULONGLONG ret = 0; if (ssdt_base_aadress == 0) {// 得到ssdt基地址ssdt_base_aadress = GetKeServiceDescriptorTable(); } if (scfn == NULL) {DecodeSSDT(); } ret = scfn(NtApiIndex, ssdt_base_aadress); return ret;}VOID UnDriver(PDRIVER_OBJECT driver){ DbgPrint(("驱动程序卸载成功! \n"));}NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath){ DbgPrint("hello lyshark.com \n"); ULONGLONG ssdt_address = GetKeServiceDescriptorTable(); DbgPrint("SSDT基地址 = %p \n", ssdt_address); // 根据序号得到函数地址 ULONGLONG address = GetSSDTFunctionAddress(51); DbgPrint("[LyShark] NtOpenFile地址 = %p \n", address); // 得到相对SSDT的偏移量 DbgPrint("函数相对偏移地址 = %p \n", GetOffsetAddress(address)); DriverObject->DriverUnload = UnDriver; return STATUS_SUCCESS;}

经验总结扩展阅读