驅動開發:Win10內核枚舉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;}

推薦閱讀