获取Windows 系统的内核变量
转自: http://www.xfocus.net创建时间:2004-08-05
文章属性:原创
文章提交: tombkeeper (t0mbkeeper_at_hotmail.com)
获取Windows 系统的内核变量
作 者:于旸
邮 件:tombkeeper[0x40]nsfocus[0x2e]com
tombkeeper[0x40]xfocus[0x2e]org
完成于:2004.07.30
关键字:PsLoadedModuleList、PsActiveProcessHead、NtSystemDebugControl
PsNtosImageBase、KdVersionBlock、KdDebuggerDataBlock、内核变量
PsLoadedModuleList等重要内核变量并未被ntoskrnl.exe导出,也没有公开的函
数可以获取。而这些内核变量对于Rootkit、Anti-Rootkit 以及内核溢出的利用等都
是至关重要的。
下面我们以PsLoadedModuleList、PsActiveProcessHead 等为例,介绍得到这些
变量的方法。
对于Windows NT 4.0和Windows 2000,尚没有“温柔”的办法可以获取这些变量,
比较理想的办法也就是特征代码搜索,这种方法虽然暴力,但通常都很有效,一般也
不会出问题;对于Windows XP和Windows 2003,我们找到了一些更加优雅的选择。
下面首先介绍特征代码搜索的方法。
[DWORD KernelBase]
要进行特征代码搜索,首先要定位ntoskrnl.exe在内核的加载地址KernelBase。
这个地址可以通过ZwQuerySystemInformation Class 10的SystemModuleInformation
来得到。参考资源[1]中给出了相关代码。事实上,KernelBase 这个值对同一操作系
统来说非常固定,可以作为常量来用:
Windows NT: 0x80100000
Windows 2000:0x80400000
Windows XP: 0x804d1000
Windows 2003: 0x804e0000
Windows NT 4.0 ntoskrnl.exe 的OptionalHeader->ImageBase = 0x80100000,
ntldr 也会按照这个值来加载内核,但是从Windows 2000开始就不是这样了。可能基
于这个历史原因,各系统的*(DWORD *)PsNtosImageBase始终初始化为0x80100000。
另外,内核变量PsNtosImageBase、KdpNtosImageBase等也指向KernelBase:
KernelBase = *(DWORD *)PsNtosImageBase
KernelBase = *(DWORD *)KdpNtosImageBase
[LIST_ENTRY PsLoadedModuleList]
PsLoadedModuleList这个全局变量指向一个保存着所加载驱动信息的双向链表。
通过它可以枚举系统中所有的驱动模块。
虽然很多内核函数都用到了PsLoadedModuleList,但是大部分并没有被导出,而
从基址开始搜会很花时间。对于Windows 2000来说,从下面这个地方入手是个好主意:
nt!MmGetSystemRoutineAddress+0x66:
804f0ed0 8b35f0e84680 mov esi,[nt!PsLoadedModuleList (8046e8f0)]
804f0ed6 81fef0e84680 cmp esi,0x8046e8f0
流程如下:
1、ImageBase = LoadLibraryA("ntoskrnl.exe")
2、GetProcAddress(ImageBase,"MmGetSystemRoutineAddress")
3、搜索特征代码:
*(WORD *)(MmGetSystemRoutineAddress + i) = 0x358b && /
*(WORD *)(MmGetSystemRoutineAddress + i + 6) = 0xfe81
&&
*(DWORD *)(MmGetSystemRoutineAddress + i + 2) == /
*(DWORD *)(MmGetSystemRoutineAddress + i + 8)
4、定位内核中的地址:
PsLoadedModuleList = /
*(DWORD *)(MmGetSystemRoutineAddress + i + 2) + (KernelBase - ImageBase)
从SP0到SP4,i值并不相同,但是肯定不大于0x100。
对Windows NT来说,就没这么好运气了,没有理想的可用于定位的API,只能从头
开始搜索。下面这段代码至少对SP1~SP6a的来说都具有很好的稳定性和唯一性:
801CEB1C: 8B 4D 08 mov ecx,dword ptr [ebp+8]
801CEB1F