最近在学习64位驱动,涉及到了SSDT的知识,结果发现64位下的SSDT和32位下的SSDT有所不同。
开始发现64位下的KeServiceDescriptorTable是未导出的函数。首先要找到KeServiceDescriptorTable的地址。
方法1:
读取c0000082寄存器
- kd> rdmsr c0000082
- msr[c0000082] = fffff800`03e82640
它记录了KiSystemCall64,
之后反汇编KiSystemCall64。
如下:
- kd> uf KiSystemCall64
- nt!KiSystemCall64:
- fffff800`03e82640 0f01f8 swapgs
- fffff800`03e82643 654889242510000000 mov qword ptr gs:[10h],rsp
- fffff800`03e8264c 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h]
- fffff800`03e82655 6a2b push 2Bh
- fffff800`03e82657 65ff342510000000 push qword ptr gs:[10h]
- fffff800`03e8265f 4153 push r11
- fffff800`03e82661 6a33 push 33h
- fffff800`03e82663 51 push rcx
- fffff800`03e82664 498bca mov rcx,r10
- fffff800`03e82667 4883ec08 sub rsp,8
- fffff800`03e8266b 55 push rbp
- fffff800`03e8266c 4881ec58010000 sub rsp,158h
- fffff800`03e82673 488dac2480000000 lea rbp,[rsp+80h]
- fffff800`03e8267b 48899dc0000000 mov qword ptr [rbp+0C0h],rbx
- fffff800`03e82682 4889bdc8000000 mov qword ptr [rbp+0C8h],rdi
- fffff800`03e82689 4889b5d0000000 mov qword ptr [rbp+0D0h],rsi
- fffff800`03e82690 c645ab02 mov byte ptr [rbp-55h],2
- fffff800`03e82694 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
- fffff800`03e8269d 0f0d8bd8010000 prefetchw [rbx+1D8h]
- fffff800`03e826a4 0fae5dac stmxcsr dword ptr [rbp-54h]
- fffff800`03e826a8 650fae142580010000 ldmxcsr dword ptr gs:[180h]
- fffff800`03e826b1 807b0300 cmp byte ptr [rbx+3],0
- fffff800`03e826b5 66c785800000000000 mov word ptr [rbp+80h],0
- fffff800`03e826be 0f848c000000 je nt!KiSystemCall64+0x110 (fffff800`03e82750)
- ---------------------------------------省略若干代码----------------------------------------------
- nt!KiSystemCall64+0x110:
- fffff800`03e82750 fb sti
- fffff800`03e82751 48898be0010000 mov qword ptr [rbx+1E0h],rcx
- fffff800`03e82758 8983f8010000 mov dword ptr [rbx+1F8h],eax
- fffff800`03e8275e 4889a3d8010000 mov qword ptr [rbx+1D8h],rsp
- fffff800`03e82765 8bf8 mov edi,eax
- fffff800`03e82767 c1ef07 shr edi,7
- fffff800`03e8276a 83e720 and edi,20h
- fffff800`03e8276d 25ff0f0000 and eax,0FFFh
- nt!KiSystemServiceRepeat:
- fffff800`03e82772 4c8d15c7202300 lea r10,[nt!KeServiceDescriptorTable (fffff800`040b4840)]
- fffff800`03e82779 4c8d1d00212300 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`040b4880)]
- fffff800`03e82780 f7830001000080000000 test dword ptr [rbx+100h],80h
- fffff800`03e8278a 4d0f45d3 cmovne r10,r11
- fffff800`03e8278e 423b441710 cmp eax,dword ptr [rdi+r10+10h]
- fffff800`03e82793 0f83e9020000 jae nt!KiSystemServiceExit+0x1a7 (fffff800`03e82a82)
如上红色代码。在KiSystemServiceRepeat里面找到了KeServiceDescriptorTable
方法2:
打开WinDbg
- kd> u nt!zwclose l10
- nt!ZwClose:
- fffff800`03e7bdc0 488bc4 mov rax,rsp
- fffff800`03e7bdc3 fa cli
- fffff800`03e7bdc4 4883ec10 sub rsp,10h
- fffff800`03e7bdc8 50 push rax
- fffff800`03e7bdc9 9c pushfq
- fffff800`03e7bdca 6a10 push 10h
- fffff800`03e7bdcc 488d059d300000 lea rax,[nt!KiServiceLinkage (fffff800`03e7ee70)]
- fffff800`03e7bdd3 50 push rax
- fffff800`03e7bdd4 b80c000000 mov eax,0Ch
- fffff800`03e7bdd9 e9e2670000 jmp nt!KiServiceInternal (fffff800`03e825c0)
- fffff800`03e7bdde 6690 xchg ax,ax
跟踪nt!KiServiceInternal
- kd> u KiServiceInternal l20
- nt!KiServiceInternal:
- fffff800`03e825c0 4883ec08 sub rsp,8
- fffff800`03e825c4 55 push rbp
- fffff800`03e825c5 4881ec58010000 sub rsp,158h
- fffff800`03e825cc 488dac2480000000 lea rbp,[rsp+80h]
- fffff800`03e825d4 48899dc0000000 mov qword ptr [rbp+0C0h],rbx
- fffff800`03e825db 4889bdc8000000 mov qword ptr [rbp+0C8h],rdi
- fffff800`03e825e2 4889b5d0000000 mov qword ptr [rbp+0D0h],rsi
- fffff800`03e825e9 fb sti
- fffff800`03e825ea 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
- fffff800`03e825f3 0f0d8bd8010000 prefetchw [rbx+1D8h]
- fffff800`03e825fa 0fb6bbf6010000 movzx edi,byte ptr [rbx+1F6h]
- fffff800`03e82601 40887da8 mov byte ptr [rbp-58h],dil
- fffff800`03e82605 c683f601000000 mov byte ptr [rbx+1F6h],0
- fffff800`03e8260c 4c8b93d8010000 mov r10,qword ptr [rbx+1D8h]
- fffff800`03e82613 4c8995b8000000 mov qword ptr [rbp+0B8h],r10
- fffff800`03e8261a 4c8d1d3d010000 lea r11,[nt!KiSystemServiceStart (fffff800`03e8275e)]
- fffff800`03e82621 41ffe3 jmp r11
- fffff800`03e82624 666666666666660f1f840000000000 nop word ptr [rax+rax]
- fffff800`03e82633 66666666660f1f840000000000 nop word ptr [rax+rax]
- nt!KiSystemCall64:
- fffff800`03e82640 0f01f8 swapgs
- fffff800`03e82643 654889242510000000 mov qword ptr gs:[10h],rsp
- fffff800`03e8264c 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h]
- fffff800`03e82655 6a2b push 2Bh
- fffff800`03e82657 65ff342510000000 push qword ptr gs:[10h]
- fffff800`03e8265f 4153 push r11
- fffff800`03e82661 6a33 push 33h
- fffff800`03e82663 51 push rcx
- fffff800`03e82664 498bca mov rcx,r10
- fffff800`03e82667 4883ec08 sub rsp,8
- fffff800`03e8266b 55 push rbp
- fffff800`03e8266c 4881ec58010000 sub rsp,158h
- fffff800`03e82673 488dac2480000000 lea rbp,[rsp+80h]
继续跟踪nt!KiSystemServiceStart
- kd> u KiSystemServiceStart
- nt!KiSystemServiceStart:
- fffff800`03e8275e 4889a3d8010000 mov qword ptr [rbx+1D8h],rsp
- fffff800`03e82765 8bf8 mov edi,eax
- fffff800`03e82767 c1ef07 shr edi,7
- fffff800`03e8276a 83e720 and edi,20h
- fffff800`03e8276d 25ff0f0000 and eax,0FFFh
- nt!KiSystemServiceRepeat:
- fffff800`03e82772 4c8d15c7202300 lea r10,[nt!KeServiceDescriptorTable (fffff800`040b4840)]
- fffff800`03e82779 4c8d1d00212300 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`040b4880)]
- fffff800`03e82780 f7830001000080000000 test dword ptr [rbx+100h],80h
同样找到了KeServiceDescriptorTable 的踪影。
之后我们看一下KeServiceDescriptorTable:
- kd> dq KeServiceDescriptorTable
- fffff800`040b4840 fffff800`03e84300 00000000`00000000
- fffff800`040b4850 00000000`00000191 fffff800`03e84f8c
- fffff800`040b4860 00000000`00000000 00000000`00000000
- fffff800`040b4870 00000000`00000000 00000000`00000000
- fffff800`040b4880 fffff800`03e84300 00000000`00000000
- fffff800`040b4890 00000000`00000191 fffff800`03e84f8c
- fffff800`040b48a0 fffff960`001b1f00 00000000`00000000
- fffff800`040b48b0 00000000`0000033b fffff960`001b3c1c
因为根据公式:
newAddress-oldAddress-7(指令长度)=bytearray
SSDT = fffff800`03e82772 + 237847 + 7 = fffff800`040b4840
所以KeServiceDescriptorTable基地址:fffff800`040b4840
我们编写程序的时候可以匹配一下4c8d15c7202300 这个特种就可以找到KeServiceDescriptorTable了。
接下来就演示算出SSDT表中第一个函数(也就是INDEX=0)的地址(这里为NtMapUserPhysicalPagesScatter),之后的以此类推就可以了。
64位和32位算法有所不同,64位需要得到 **KeServiceDescriptorTable = 040d9a00
下面红色标记。
- kd> dd fffff800`03e84300
- fffff800`03e84300 040d9a00 02f55c00 fff6ea00 02e87805
- fffff800`03e84310 031a4a06 03116a05 02bb9901 02b4f200
- fffff800`03e84320 0312cc40 03dd7400 02c84700 02e7d100
- fffff800`03e84330 02f68100 02e02301 02dd0601 02d96100
- fffff800`03e84340 02df4602 02f18600 02ad0500 02cefe01
- fffff800`03e84350 02d01d02 02f69902 03101101 0323ca01
- fffff800`03e84360 0455c305 02ed29c0 02b2e703 ffec1d00
- fffff800`03e84370 043c2800 02f51040 02c52c01 03126c00
公式:ServiceTableBase[Index] >> 4 + ServiceTableBase
ServiceTableBase[Index] = ServiceTableBase + Index * 4
即:
040d9a00 >> 4 = 40D9A0 + *KeServiceDescriptorTable = FFFFF80004291CA0
如下:
- kd> u FFFFF80004291CA0
- nt!NtMapUserPhysicalPagesScatter:
- fffff800`04291ca0 48895c2408 mov qword ptr [rsp+8],rbx
- fffff800`04291ca5 4c89442418 mov qword ptr [rsp+18h],r8
- fffff800`04291caa 55 push rbp
- fffff800`04291cab 56 push rsi
- fffff800`04291cac 57 push rdi
- fffff800`04291cad 4154 push r12
- fffff800`04291caf 4155 push r13
- fffff800`04291cb1 4156 push r14
对比XT:
结果正确。
接下来用C实现以下找SSDT基址:
- VOID GetSSDTBaseAddr()
- {
- 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+2))
- {
- b1 = *(i);
- b2 = *(i+1);
- b3 = *(i+2);
- if (b1==0x4c && b2==0x8d && b3==0x15)
- {
- memcpy(&templong,i+3,4);
- //核心部分
- //kd> db fffff800`03e8b772
- //fffff800`03e8b772 4c 8d 15 c7 20 23 00 4c-8d 1d 00 21 23 00 f7 83 L... #.L...!#...
- //templong = 002320c7 ,i = 03e8b772, 7为指令长度
- addr = (ULONGLONG)templong + (ULONGLONG)i + 7;
- break;
- }
- }
- }
- DbgPrint("b1 = %0x\n",b1);
- DbgPrint("b2 = %0x\n",b2);
- DbgPrint("b3 = %0x",b3);
- DbgPrint("templong = %0x\n",templong);
- DbgPrint("addr = %0x\n",addr);
- }