————————————————————————————————————————————————————————————————————————————————————————

本篇开始进行真枪实弹的调试,本文的最后会附上完整的源码包,方便各位在自己的机器上演练。

如果安装了 Windows Driver Kits,在“开始”->“所有程序”中选择类似“WDK 7600.16385.1”的项目。具体的数字取决于你

安装的 WDK 开发环境版本而定。然后选择“Build Environments”下面的操作系统版本,

亦即你编译出来的驱动要运行其上的 OS 版本,接着选择硬件平台体系结构与构建类型,比如“x86 Checked Build

Environment”是用于 32 位平台,且附带生成包含调试符号文件的构建环境。

调试符号文件有助于调试器显示驱动二进制文件中的函数,变量,常量名称等信息,生成人性化的输出。

这样会创建一个特殊的 cmd.exe 进程,它的环境变量预配置好了各种构建相关的参数,比如头文件,库文件的位置;编译器,汇编

器,链接器程序所在路径。。。等等。

我们在该 cmd 窗口中切换到源码包的解压目录,然后执行如下命令:

build /D /g /b /B /e /F /S /s /$ /why /v /w /y

这些指定的参数让你能查看详细的构建过程,比如预处理器解析头文件的嵌套包含过程,给出可能的警告或错误提示。

下面是一个样例输出,对于排除过程中出现的问题很有用:

D:\kmdsource_use_mdl_mapping_ssdt>build  /D /g /b /B /e /F /S /s /$ /why /v /w /y
BUILD: Compile and Link for x86
BUILD: Loading d:\winddk\7600.16385.\build.dat...
BUILD: Computing Include file dependencies:
Scanning d:\winddk\7600.16385.\inc\api
Scanning d:\winddk\7600.16385.\inc\ddk
BUILD: Start time: Mon Jan ::
Scanning d:\kmdsource_use_mdl_mapping_ssdt
Scanning d:\winddk\7600.16385.\inc\crt
BUILD: Examining d:\kmdsource_use_mdl_mapping_ssdt directory for files to compile.
d:\kmdsource_use_mdl_mapping_ssdt
Invalidating OACR warning log for 'root:x86chk'
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c ntddk.h d:\winddk\7600.16385.\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c wdm.h d:\winddk\7600.16385.\inc\ddk
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.\inc\crt
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_supp.h d:\winddk\7600.16385.\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_strict.h d:\winddk\7600.16385.\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_undef.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c driverspecs.h d:\winddk\7600.16385.\inc\api
0x00000007-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal_supp.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_supp.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sal.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c specstrings_strict.h d:\winddk\7600.16385.\inc\api
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c sdv_driverspecs.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntdef.h d:\winddk\7600.16385.\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c ctype.h d:\winddk\7600.16385.\inc\crt
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c specstrings.h d:\winddk\7600.16385.\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c kernelspecs.h d:\winddk\7600.16385.\inc\api
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c driverspecs.h d:\winddk\7600.16385.\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c basetsd.h d:\winddk\7600.16385.\inc\api
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.\inc\api
0x00000005-0x00000001/0x00000001 usemdlmappingssdt.c string.h d:\winddk\7600.16385.\inc\crt
0x00000006-0x00000001/0x00000001 usemdlmappingssdt.c crtdefs.h d:\winddk\7600.16385.\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.\inc\crt
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c sdkddkver.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntstatus.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c bugcodes.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ntiologc.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c mce.h d:\winddk\7600.16385.\inc\ddk
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c pshpack4.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c poppack.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c pshpack1.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c string.h d:\winddk\7600.16385.\inc\crt
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c dpfilter.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c ktmtypes.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c dsfhrmports.h d:\winddk\7600.16385.\inc\ddk
Compiling - d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c evntrace.h d:\winddk\7600.16385.\inc\api
Linking Executable - d:\kmdsource_use_mdl_mapping_ssdt\objchk_win7_x86\i386\UseMdlMappingSSDT.sys
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c stdarg.h d:\winddk\7600.16385.\inc\crt
% done. TLPS Time Left: :: Files: Total LLines:
0x00000004-0x00000001/0x00000001 usemdlmappingssdt.c vadefs.h d:\winddk\7600.16385.\inc\crt 0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c evntprov.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c devpropdef.h d:\winddk\7600.16385.\inc\api
0x00000003-0x00000001/0x00000001 usemdlmappingssdt.c clfslsn.h d:\winddk\7600.16385.\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c excpt.h d:\winddk\7600.16385.\inc\crt
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntdef.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntstatus.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c bugcodes.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntiologc.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c mce.h d:\winddk\7600.16385.\inc\ddk
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c pshpack4.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c poppack.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c guiddef.h d:\winddk\7600.16385.\inc\api
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c pshpack1.h d:\winddk\7600.16385.\inc\api
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c datatype.h d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c dbgmsg.h d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c ctrlcode.h d:\kmdsource_use_mdl_mapping_ssdt
0x00000001-0x00000001/0x00000001 usemdlmappingssdt.c device.h d:\kmdsource_use_mdl_mapping_ssdt
0x00000002-0x00000001/0x00000001 usemdlmappingssdt.c ntddk.h d:\winddk\7600.16385.\inc\ddk Compiling usemdlmappingssdt.c because .. (0x00000006)
BUILD: Saving d:\winddk\7600.16385.\build.dat...
BUILD: Compiling and Linking d:\kmdsource_use_mdl_mapping_ssdt directory
Configuring OACR for 'root:x86chk' - <OACR on>
>warnings in directory d:\kmdsource_use_mdl_mapping_ssdt
alSystemServicePtr' differs in levels of indirection from 'DWORD'1>d:\kmdsource_use_mdl_mapping_ssdt\usemdlmappingssdt.c(157) : warning
BUILD: Finish time: Mon Jan ::
BUILD: Done files compiled - Warnings
executable built D:\kmdsource_use_mdl_mapping_ssdt>

我在前一篇文章中说过,可以忽略源码中 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,参见前一篇博文可知,它只对应 MDL_ALLOCATED_FIXED_SIZE;还记得吗,我在前一篇博文指出:

仅当 _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 左右的内

核内存!

而 KiServiceTable 被映射到的 805fbf7c 内核地址显然不在其内。

事实上,KiServiceTable 被映射到的 805fbf7c 内核地址属于“SystemPte 型(即系统页表条目)”内核空间,此类内核空间有多

种用途,包括提供给 MDL 来把 SSDT/KiServiceTable 映射到此处。

系统页表条目(PTEs)内核空间,用于动态地映射系统页面,例如 I/O 空间,内核栈,以及映射内存描述符列表(MDLs)。

系统 PTE 的分配者除了各种执行体/内核组件外,多数是一些加载到内核空间的设备驱动程序,其中有系统自带的,也有第三方软

硬件供应商开发的;

它们请求在系统 PTE 区域中分配内存的目的都是与映射视图,MDLs(内存描述符列表),适配器内存映射,驱动程序映像,内核

栈, I/O 映射等相关的,如下图所示:

内核空间中有多处被划分为 SystemPte 类型,我们把 KiServiceTable 映射到第一个 SystemPte 型内核空间,该区域大小为 4

MB。

按下“g”继续执行,这会导致 MapMdl() 返回新映射的地址到 DriverEntry(),后者挂钩 nt!NtCompleteConnectPort(),另一方

面,我们还可以通过计算出来的 nt!_MDL 头部大小访问到其后的 PFN 数组,检查其内保存的物理页框号是否就是虚拟地址

0x83CABF7C 和 0x805fbf7c 两者执行地址转译后所在的物理页框号,它们都被转译到物理地址 0x3cabf7c,页框号为

0x03cab,虚拟地址的后 12 位偏移量(0xf7c)直接拷贝到物理地址的后 12 位偏移量;

页框号还可以通过对 pfn_array_follow_mdl 执行指针运算并解引地址处的内容得出,也是 0x03cab;

两者的区别在于,描述虚拟地址 0x83CABF7C 的 PTE 内容设置了只读标记;而描述虚拟地址 0x805fbf7c 的 PTE 内容设置了可读

标记,因此通过虚拟地址 0x83CABF7C 向实际的物理页写入就会蓝屏;而通过虚拟地址 0x805fbf7c 则可以安全写入!

访问 KiServiceTable 中的 0x39 号系统服务,已经被替换为我们的钩子例程:

我提供了一个 UnMapMdl() 例程,把它注册为该 rootkit 的卸载回调,大致逻辑是,在驱动卸载时,取消映射新的内核虚拟地址,

并释放 MDL 指针 ,如此一来,卸载 UseMdlMappingSSDT.sys 后,既不能通过新映射的地址访问 KiServiceTable,也不能通过

指针访问 nt!_MDL 结构(但该结构确实尚未释放):

最后,让我们填充前一篇博文中那张 MDL 架构图中的占位符,以便让各位能够洞察整个来龙去脉。祝愿你没有被那些红红绿绿的

箭头搞晕!

附上源码包的下载地址,欢迎反馈。

https://files.cnblogs.com/files/flying-shark/kmdsource_use_mdl_mapping_ssdt.rar

-------- ROOTKIT 核心技术——系统服务调度表挂钩调试(PART III) --------的更多相关文章

  1. Rootkit 核心技术——利用 nt!_MDL(内存描述符链表)突破 SSDT(系统服务描述符表)的只读访问限制 Part I

    -------------------------------------------------------- 在 rootkit 与恶意软件开发中有一项基本需求,那就是 hook Windows ...

  2. -------- Rootkit 核心技术——利用 nt!_MDL 突破 KiServiceTable 的只读访问限制 Part II --------

    ------------------------------------------------------------------------------------------- 本篇开始进入正题 ...

  3. ----------- Rootkit 核心技术之绕过 IopParseDevice() 调用源检测逻辑 ---------------

    ---------------------------------------------------------------- 在上一篇文章中,我们已经看到 IopParseDevice() 如何对 ...

  4. ------- 软件调试——还原 QQ 过滤驱动对关键内核设施所做的修改 -------

    -------------------------------------------------------------------------------- 在前一篇博文中,我们已经处理完最棘手的 ...

  5. ------- 软件调试——挫败 QQ.exe 的内核模式保护机制 -------

    ------------------------------------------------------------------------ QQ 是一款热门的即时通信(IM)类工具,在安装时刻会 ...

  6. 【黑客免杀攻防】读书笔记17 - Rootkit基础

    1.构建Rootkit基础环境 1.1.构建开发环境 VS2012+WDK8 1.2.构建基于VS2012的调试环境 将目标机.调试机配置在同一个工作组内 sVS2012配置->DRIVER-& ...

  7. Windbg内核调试之三: 调试驱动

    这次我们通过一个实际调试驱动的例子,来逐步体会Windbg在内核调试中的作用.由于条件所限,大多数情况下,很多人都是用VMware+Windbg调试内核(VMware的确是个好东西).但这样的调试需要 ...

  8. SSDT

    2.系统服务调度表SSDT及SSSDT Shadow 系统服务:由操作系统提供的一组函数(内核函数),API可以间接或者直接的调用系统服务.操作系统以动态链接库(DLL)的形式提供API. SSDT: ...

  9. Windows内核开发-Windows内部概述-2-

    Windows内部概述-2- 线程: 执行代码的实体是线程.一个线程的包含在进程里面的,线程使用进程提供的资源来运行代码. 一个线程拥有以下的内容: 1:明确的运行模式,用户态或者内核态. 2:执行的 ...

随机推荐

  1. Md2All

    微信公众号:颜家大少欢迎关注我,一起学习,一起进步!目前,知到 Md2All 的朋友还很少,如果你觉得有帮助,希望能告诉身边有需要的朋友. 谢谢! Md2All 简介 一个Markdown在线转换工具 ...

  2. Caused by: org.xml.sax.SAXParseException; systemId: file:/home/hadoop/hive-0.12.0/conf/hive-site.xml; lineNumber: 5; columnNumber: 2; The markup in the document following the root element must be well

    1:Hive安装的过程(Hive启动的时候报的错误),贴一下错误,和为什么错,以及解决方法: [root@master bin]# ./hive // :: INFO Configuration.de ...

  3. jQuery Mobile Slider 禁用点击事件

    阿子原创,转载请注明出处. 在使用jQuery Mobile Slider时,发现在页面上下拖动时,很容易不小心触发Slider的点击事件,从而造成误操作.为此需要禁用Slider的点击事件. 官方A ...

  4. windows PAE扩展和AWE编程

    在32位windows上只能看到最大3GB的内存空间,而且每个应用程序只能访问4GB的的内存,这个限制是windows独有的,为了使程序能够访问大于4GB的内存空间,需要使用AWE编程接口,同时需要开 ...

  5. PE解析器的编写(三)——区块表的解析

    PE文件中所有节的属性都被定义在节表中,节表由一系列的IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的. 具有相同属 ...

  6. 第四章 Windows图形界面-上

    学习<Windows程序设计>记录 概念贴士: 1. 每个GUI应用程序至少应该创建一个窗口,称为主窗口,它作为用户与应用程序间的主界面来提供服务.大多数应用程序也直接或间接地创建其他窗口 ...

  7. Python全栈考试(一)

    1.执行 Python 脚本的两种方式 1) 使用命令行执行Python脚本: python C:\tesst.py 2) 使用各种IDE软件.pycharm wing 2.简述位.字节的关系 位 ( ...

  8. js最常用正则表达式集合

    常用正则表达式合集:验证数字:^[0-9]*$验证n位的数字:^\d{n}$验证至少n位数字:^\d{n,}$验证m-n位的数字:^\d{m,n}$验证零和非零开头的数字:^(0|[1-9][0-9] ...

  9. 【ASP.NET Core分布式项目实战】(一)IdentityServer4登录中心、oauth密码模式identity server4实现

    本博客根据http://video.jessetalk.cn/my/course/5视频整理 资料 OAuth2 流程:http://www.ruanyifeng.com/blog/2014/05/o ...

  10. assert断言

    https://www.cnblogs.com/ggzss/archive/2011/08/18/2145017.html assert是一个宏定义,其作用是如果它的条件返回错误,则终止程序执行,原型 ...