本帖最后由 msx2009 于 2014-11-28 20:42 编辑
win32下KeSystemDescriptorTable的地址已经由ntoskrnl.exe导出,直接 extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable 即可获取SSDT的地址。 在win64下,KeSystemDescriptorTable的地址没有被导出,不能通过win32下的方法获取地址。 Win64下,我们可以通过msr寄存器获取 KiSystemCall64函数的地址,在这个函数开始地址向下搜索0x150字节左右,在通过特征码4c8d15,就能获取KeServiceDescriptorTable的地址。 Windgb下看一下 uf KiSystemCall64
kd> uf KiSystemCall64 Flow analysis was incomplete, some code may be missing nt!KiSystemCall64: fffff800`03ecfbc0 0f01f8 swapgs fffff800`03ecfbc3 654889242510000000 mov qword ptr gs:[10h],rsp fffff800`03ecfbcc 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h] fffff800`03ecfbd5 6a2b push 2Bh fffff800`03ecfbd7 65ff342510000000 push qword ptr gs:[10h] fffff800`03ecfbdf 4153 push r11 …… nt!KiSystemServiceRepeat: fffff800`03ecfcf2 4c8d15478c2300 lea r10,[nt!KeServiceDescriptorTable (fffff800`04108940)] fffff800`03ecfcf9 4c8d1d808c2300 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`04108980)] fffff800`03ecfd00 f7830001000080000000 test dword ptr [rbx+100h],80h fffff800`03ecfd0a 4d0f45d3 cmovne r10,r11 fffff800`03ecfd0e 423b441710 cmp eax,dword ptr [rdi+r10+10h] fffff800`03ecfd13 0f83e9020000 jae nt!KiSystemServiceExit+0x1a7 (fffff800`03ed0002)
注意蓝色字节内容, KiSystemCall64的开始地址是fffff800`03ecfbc0 , 第二个蓝色标记处发现了KeServiceDescriptorTable,这条指令地址是fffff800`03ecfcf2,对应的字节为4c8d15478c2300,Lea的对应字节为4c8d15,所以后边的字节478c2300为偏移地址,注意地址是反过来的,真正偏移地址是 00238c47,偏移地址是针对这条指令最后一个字节的地址的偏移,所以需要在加7字节,由此可得KeServiceDescriptorTable地址为: fffff800`03ecfcf2 +00238c47 + 7 = fffff800`04108940。
我们可以dd KeServiceDescriptorTable看一下地址 kd> dd KeServiceDescriptorTable fffff800`04108940 03ed1800 fffff800 00000000 00000000 fffff800`04108950 00000191 00000000 03ed248c fffff800 可以看出上述计算是正确的。
编程实现以下,主要代码如下(引用别人的代码): //获取SSDT地址 ULONGLONG MyGetKeServiceDescriptorTable() { PUCHAR StartSearchAddress =(PUCHAR)__readmsr(0xC0000082); PUCHAR EndSearchAddress = StartSearchAddress + 0x500; PUCHAR i = NULL; UCHAR b1=0,b2=0,b3=0; ULONG templong=0; ULONGLONG addr=0;
for(i=StartSearchAddress;i<EndSearchAddress;i++) { if(MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+1)) { b1=*i; b2=*(i+1); b3=*(i+2); if(b1==0x4c && b2==0x8d && b3==0x15) //4c8d15 { memcpy(&templong,i+3,4); addr = (ULONGLONG)templong + (ULONGLONG)i +7; return addr; } } } return 0; }
可以在驱动入口打印出地址 DbgPrint("[method 1]SSDT: %llx",MyGetKeServiceDescriptorTable())
|