二探win10 x64 SSDT(驱动学习笔记六)

0x0 C0000082的通解

背景介绍

在上一篇学习笔记中,我们曾说过,在win10 x64 1809专业版上

通过C0000082 MSR寄存器,我所得到的地址并非是nt!KiSystemCall64,而是nt!KiSystemCall64Shadow。
因此,我的权宜之计是读取地址后取一个偏移量将开始进行特征码搜索的位置重新定位到合理的位置,再在其中进行搜索,当然,这显然不是一个有效的方式,待后续解决。

详见上篇文章:初探win10 x64 SSDT(驱动学习笔记五)
为此,我们在此篇文章中来解决这个问题。

寻找SSDT

  1. 首先我们还是通过c0000082找到nt!KiSystemCall64的地址,并查看其反汇编,在其中并没有直接找到SSDT的地址。
1: kd> rdmsr c0000082
msr[c0000082] = fffff804`2f7e2140
1: kd> u fffff804`2f7e2140 
nt!KiSystemCall64Shadow:
fffff804`2f7e2140 0f01f8          swapgs
fffff804`2f7e2143 654889242510700000 mov   qword ptr gs:[7010h],rsp
fffff804`2f7e214c 65488b242500700000 mov   rsp,qword ptr gs:[7000h]
fffff804`2f7e2155 650fba24251870000001 bt  dword ptr gs:[7018h],1
fffff804`2f7e215f 7203            jb      nt!KiSystemCall64Shadow+0x24 (fffff804`2f7e2164)
fffff804`2f7e2161 0f22dc          mov     cr3,rsp
fffff804`2f7e2164 65488b242508700000 mov   rsp,qword ptr gs:[7008h]
nt!KiSystemCall64ShadowCommon:
fffff804`2f7e216d 6a2b            push    2Bh
fffff804`2f7e216f 65ff342510700000 push    qword ptr gs:[7010h]
fffff804`2f7e2177 4153            push    r11
fffff804`2f7e2179 6a33            push    33h
fffff804`2f7e217b 51              push    rcx
fffff804`2f7e217c 498bca          mov     rcx,r10
fffff804`2f7e217f 4883ec08        sub     rsp,8
fffff804`2f7e2183 55              push    rbp
fffff804`2f7e2184 4881ec58010000  sub     rsp,158h
...
fffff804`2f7e236a 4883c408        add     rsp,8
fffff804`2f7e236e e8eeffffff      call    nt!KiSystemCall64ShadowCommon+0x1f4 (fffff804`2f7e2361)
fffff804`2f7e2373 4883c408        add     rsp,8
fffff804`2f7e2377 0faee8          lfence
fffff804`2f7e237a 65c604255308000000 mov   byte ptr gs:[853h],0
fffff804`2f7e2383 e9e35ce9ff      jmp     nt!KiSystemServiceUser (fffff804`2f67806b)
fffff804`2f7e2388 c3              ret
fffff804`2f7e2389 0000            add     byte ptr [rax],al
fffff804`2f7e238b 0000            add     byte ptr [rax],al
...
  1. 通过对反汇编的观察,我们发现了一个找到SSDT的途径,即我们可以通过nt!KiSystemCall64ShadowCommon中的KiSystemServiceUser找到SSDT,我们查看其反汇编如下:
1: kd> u KiSystemServiceUser
nt!KiSystemServiceUser:
fffff804`2f67806b c645ab02        mov     byte ptr [rbp-55h],2
fffff804`2f67806f 65488b1c2588010000 mov   rbx,qword ptr gs:[188h]
fffff804`2f678078 0f0d8b90000000  prefetchw [rbx+90h]
fffff804`2f67807f 0fae5dac        stmxcsr dword ptr [rbp-54h]
fffff804`2f678083 650fae142580010000 ldmxcsr dword ptr gs:[180h]
fffff804`2f67808c 807b0300        cmp     byte ptr [rbx+3],0
fffff804`2f678090 66c785800000000000 mov   word ptr [rbp+80h],0
...
fffff804`2f678154 48898b88000000  mov     qword ptr [rbx+88h],rcx
fffff804`2f67815b 898380000000    mov     dword ptr [rbx+80h],eax
fffff804`2f678161 666666666666660f1f840000000000 nop word ptr [rax+rax]
nt!KiSystemServiceStart:
fffff804`2f678170 4889a390000000  mov     qword ptr [rbx+90h],rsp
fffff804`2f678177 8bf8            mov     edi,eax
fffff804`2f678179 c1ef07          shr     edi,7
fffff804`2f67817c 83e720          and     edi,20h
fffff804`2f67817f 25ff0f0000      and     eax,0FFFh
nt!KiSystemServiceRepeat:
fffff804`2f678184 4c8d15f5663900  lea     r10,[nt!KeServiceDescriptorTable (fffff804`2fa0e880)]
fffff804`2f67818b 4c8d1deee73700  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff804`2f9f6980)]
fffff804`2f678192 f7437880000000  test    dword ptr [rbx+78h],80h
fffff804`2f678199 7413            je      nt!KiSystemServiceRepeat+0x2a (fffff804`2f6781ae)
fffff804`2f67819b f7437800002000  test    dword ptr [rbx+78h],200000h
fffff804`2f6781a2 7407            je      nt!KiSystemServiceRepeat+0x27 (fffff804`2f6781ab)
fffff804`2f6781a4 4c8d1d55e83700  lea     r11,[nt!KeServiceDescriptorTableFilter (fffff804`2f9f6a00)]
fffff804`2f6781ab 4d8bd3          mov     r10,r11
fffff804`2f6781ae 413b443a10      cmp     eax,dword ptr [r10+rdi+10h]
fffff804`2f6781b3 0f832c050000    jae     nt!KiSystemServiceExitPico+0x160 (fffff804`2f6786e5)
fffff804`2f6781b9 4d8b143a        mov     r10,qword ptr [r10+rdi]
fffff804`2f6781bd 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
fffff804`2f6781c1 498bc3          mov     rax,r11
fffff804`2f6781c4 49c1fb04        sar     r11,4
fffff804`2f6781c8 4d03d3          add     r10,r11
fffff804`2f6781cb 83ff20          cmp     edi,20h
fffff804`2f6781ce 7550            jne     nt!KiSystemServiceGdiTebAccess+0x49 (fffff804`2f678220)
fffff804`2f6781d0 4c8b9bf0000000  mov     r11,qword ptr [rbx+0F0h]
nt!KiSystemServiceGdiTebAccess:
fffff804`2f6781d7 4183bb4017000000 cmp     dword ptr [r11+1740h],0
...
  1. 由此,我们可以得到了一个获取SSDT的思路
C0000082
KiSystemCall64Shadow
KiSystemServiceUser
SSDT/SSDTShadow

代码实现

由于目前C0000082会出现两种情况,我们有必要观察下这二者的区别:
KiSystemCall64的汇编代码如下:

1: kd> u KiSystemCall64
nt!KiSystemCall64:
fffff804`2f677e40 0f01f8          swapgs
fffff804`2f677e43 654889242510000000 mov   qword ptr gs:[10h],rsp
fffff804`2f677e4c 65488b2425a8010000 mov   rsp,qword ptr gs:[1A8h]
fffff804`2f677e55 6a2b            push    2Bh
fffff804`2f677e57 65ff342510000000 push    qword ptr gs:[10h]
fffff804`2f677e5f 4153            push    r11
fffff804`2f677e61 6a33            push    33h
fffff804`2f677e63 51              push    rcx
...

KiSystemCall64Shadow的汇编代码如下

1: kd> u KiSystemCall64Shadow
nt!KiSystemCall64Shadow:
fffff804`2f7e2140 0f01f8          swapgs
fffff804`2f7e2143 654889242510700000 mov   qword ptr gs:[7010h],rsp
fffff804`2f7e214c 65488b242500700000 mov   rsp,qword ptr gs:[7000h]
fffff804`2f7e2155 650fba24251870000001 bt  dword ptr gs:[7018h],1
fffff804`2f7e215f 7203            jb      nt!KiSystemCall64Shadow+0x24 (fffff804`2f7e2164)
fffff804`2f7e2161 0f22dc          mov     cr3,rsp
fffff804`2f7e2164 65488b242508700000 mov   rsp,qword ptr gs:[7008h]
nt!KiSystemCall64ShadowCommon:
fffff804`2f7e216d 6a2b            push    2Bh
...

不难发现,这两个函数的特征区别比较明显,KiSystemCall64是将rsp放在了gs段偏移为10h的位置上,而 KiSystemCall64Shadow是将rsp放在了gs段偏移为7010h的位置,通过这个特征,我们可以很容易判断从msr寄存器上获取到的地址到底是KiSystemCall64的地址还是是KiSystemCall64Shadow的地址,核心代码如下:

PUCHAR msr = (PUCHAR)__readmsr(0xC0000082);
if (*(msr + 0x9) == 0x00)
{
	PUCHAR pKiSystemCall64 = msr;
	PUCHAR EndSearchAddress = pKiSystemCall64 + 0x500;//通常搜索范围在500字节就够了
	KeServiceDescriptorTable = SearchforKeSeriviceDescriptorTable(pKiSystemCall64, EndSearchAddress);
	return KeServiceDescriptorTable;
}
else if (*(msr + 0x9) == 0x70)
{
	PUCHAR pKiSystemCall64Shadow = msr;
	PUCHAR EndSearchAddress = pKiSystemCall64Shadow + 0x500;
	PUCHAR i = NULL;
	INT Temp = 0; 
	for (i = pKiSystemCall64Shadow; i < EndSearchAddress; i++)
	{
		//fffff804`3fb46383 e9e35ce9ff      jmp     nt!KiSystemServiceUser (fffff804`3f9dc06b)
		//fffff804`3fb46388 c3              ret
		if (MmIsAddressValid(i) && MmIsAddressValid(i + 5))
		{
			if (*i==0xe9&&*(i+5)==0xc3)
			{
				memcpy(&Temp, i + 1, 4);
				PUCHAR pKiSystemServiceUser = Temp + (i + 5); //计算pKiSystemServiceUser的地址
				PUCHAR EndSearchAddress = pKiSystemServiceUser + 0x500;
				KeServiceDescriptorTable = SearchforKeSeriviceDescriptorTable(pKiSystemServiceUser, EndSearchAddress);
				return KeServiceDescriptorTable;
			}
		}
	}
}

至此,我们完成了上一篇文章所说的相对来说较为通用的寻找SSDT的后续方案。但需要注意的是,不同版本的操作系统仍然可能存在差异,本文的方法适用于win10 1809 x64专业版,其他版本仍需测试验证。但是最重要的仍然是寻找SSDT的思路,这也是写下此片文章的初衷,欢迎大家讨论勘误,也请大神轻喷。
To be continue…

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值