在前面的博文《驱动开发:Win10内核枚举SSDT表基址》
中已经教大家如何寻找SSDT
表基地址了,找到后我们可根据序号获取到指定SSDT
函数的原始地址,而如果需要输出所有SSDT
表信息,则可以定义字符串列表,以此循环调用GetSSDTFunctionAddress()
函数得到,当然在此之间也可以调用系统提供的MmGetSystemRoutineAddress()
函数顺便把当前地址拿到,并通过循环方式得到完整的SSDT列表。
调用MmGetSystemRoutineAddress()
得到当前地址很容易实现,只需要将函数名字符串通过RtlInitUnicodeString()
格式化一下即可。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("驱动程序卸载成功! \n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark.com \n");
// 获取SSDT起源地址
UNICODE_STRING uncode;
RtlInitUnicodeString(&uncode, L"NtOpenFile");
PULONGLONG source_address = MmGetSystemRoutineAddress(&uncode);
DbgPrint("[LyShark] NtOpenFile起源地址 = %p \n", source_address);
DriverObject->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
代码获得NtOpenFile
这个函数的内存地址,输出效果如下所示:
根据上一章节的内容扩展,枚举完整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
{
PVOID ServiceTableBase;
PVOID ServiceCounterTableBase;
ULONGLONG NumberOfServices;
PVOID ParamTableBase;
} 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 00 lea r10,[nt!KeServiceDescriptorTable (fffff802`64da4880)]
// 4c 8d 1d de 20 3a 00 lea r11,[nt!KeServiceDescriptorTableShadow (fffff802`64d8ca80)]
if (OpCodeA == 0x4c && OpCodeB == 0x8d &&