————————————————————————————————————————————————————————
篇开始进行真枪实弹的调试,本文的最后会附上完整的源码包,方便各位在自己的机器上演练。
如果安装了 Windows Driver Kits,在 “开始” -> “所有程序” 中选择类似 “WDK 7600.16385.1” 的项目。
具体的数字取决于你安装的 WDK 开发环境版本而定。然后选择 “Build Environments” 下面的操作系统版本,
亦即你编译出来的驱动要运行其上的 OS 版本,接着选择硬件平台体系结构与构建类型,比如 “x86 Checked Build
Environment” 是用于 32 位平台,且附带生成包含调试符号文件的构建环境。
调试符号文件有助于调试器显示驱动二进制文件中的函数,变量,常量名称等信息,生成人性化的输出。
这样会创建一个特殊的 cmd.exe 进程,它的环境变量预配置好了各种构建相关的参数,比如头文件,库文件的位置;编译器,汇编
器,链接器程序所在路径。。。等等。
我们在该 cmd 窗口中切换到源码包的解压目录,然后执行如下命令:
这些指定的参数让你能查看详细的构建过程,比如预处理器解析头文件的嵌套包含过程,给出可能的警告或错误提示。
下面是一个样例输出,对于排除过程中出现的问题很有用:
我在 Part I 中说过,可以忽略源码中 157 行造成的警告——rootkit 的实际效果不受该警告影响。
把编译出来的 UseMdlMappingSSDT.sys 拷贝到虚拟机或另一台真实机器上(交叉编译的目标平台假设是 widnows 7
或 Windows Server 2008),使用 sc.exe 加载该驱动进入内核空间,如果一切正常,宿主机上应该会触发首个断点,位
于 MapMdl() 中,如下图,注意,DbgPrint() 与 DBG_TRACE 宏的输出信息除了可以在目标机器上用 DbgView.exe 查看外,也
会直接输出到宿主机上调试器的控制台。
我们只关心获取到的 KiServiceTable 地址: 83CABF7C ;分配出来的一个 nt!_MDL 结构地址:86A838A8 ;
由于之前选择了 “Checked Build” 构建环境,现在调试器能够根据 “UseMdlMappingSSDT.pdb” 符号文件显示诸如 MapMdl()
之类的函数名称:
结合源码可知,首个断点位于 IoAllocateMdl() 调用后不远处,我们的意图是检查该调用后的一个 nt!_MDL 对象内容,前面通
过 mdl_pointer 保存的地址派上用场:
如你所见,IoAllocateMdl() 分配出来的一个 MDL 总大小(头部加上其后的 PFN 数组)为 36 字节;当前的标志取值 10 进制
的 8,参见 Part II 可知,它只对应 MDL_ALLOCATED_FIXED_SIZE;还记得吗,我在
Part II
指出:
仅当 _MDL 的 MdlFlags 字段内设置了 MDL_MAPPED_TO_SYSTEM_VA 或 MDL_SOURCE_IS_NONPAGED_POOL 比特位,
MappedSystemVa 字段才是有效的,因此上图中的 MappedSystemVa 字段值 0x8059d950 没有意义。
你还看到, StartVa 字段值为 0x83cab000,这就是 KiServiceTable(从 0x83CABF7C 开始)所在的虚拟页起始地址,注意这个
地址是对齐在 4 KB 边界上的,因为虚拟页和物理页大小正情况下均为 4 KB。
ByteOffset 字段值为 0xf7c,亦即 KiServiceTable 的页内偏移量—— 0x83CABF7C - 0x83cab000 = 0xf7c
ByteCount 字段值为 0x644,亦即整张 KiServiceTable 调用表(一片缓冲区)的大小—— 1064 字节。
按 “g” 继续执行目标系统至第二个软件断点处,再次转储这个 nt!_MDL 对象内容:
MdlFlags 字段值变成了 138(0x8A),对照相关的宏定义可知,这是 MDL_WRITE_OPERATION(0x80)加
上 MDL_PAGES_LOCKED(0x02)加上 MDL_ALLOCATED_FIXED_SIZE(0x08)的组合,表明 MmProbeAndLockPages() 例程
把该 MDL 锁在物理内存中,且具有了写访问权限。
继续按 “g” 执行目标系统至第三个软件断点处,再次转储这个 nt!_MDL 对象内容,谨记在心,此刻代表
MmGetSystemAddressForMdlSafe() 例程执行后的状态:
首先,MdlFlags 字段值变成了 139(0x8B),这表明追加了一个 MDL_MAPPED_TO_SYSTEM_VA 标志,从而使得
MappedSystemVa 字段值:0x805fbf7c 为有效,它代表把 KiServiceTable 映射到的新内核缓冲区起始地址,这与 eax 寄存器
(普遍用来存放函数调用的返回值,在此场景中由 MmGetSystemAddressForMdlSafe() 返回 )的值相符!
细心的你可能已经发现了,“旧” 缓冲与新缓冲地址的后 12 位都是 “f7c”,这当然不是巧合,事实上,虚拟地址的后 12 位(页
内偏移)在地址转译阶段被原封不动地与高 20 位的物理页框号结合产生物理地址!这暗示它们都映射到相同的物理地址。
那么通过它们应该访问到同一个 KiServiceTable,如下所示,记住,当前断点是尚未 hook KiServiceTable,因此 0x39 号系统服
务还是原来的那一个—— nt!NtCompleteConnectPort() :
你可以看到,我们的 rootkit “UseMdlMappingSSDT” 被加载到 9ff55000——9ff5c000 这片内核空间,占用 28 KB 左右的内
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2018-4-23 17:07
被shayi编辑
,原因: