探索黑客技术攻防,实战研究与安全创新

导航菜单

Windows内核调试命令利器分析

 近几年随着Rootkit技术的快速发展,越来越多的安全技术爱好者开始了解Rootkit的实现原理,从上层API函数到nativeAPI再到各类未公开的内核函数、内核对象。大多数Rootkits的开发都离不开内核对象的操作,如调用表CallTables的劫持、系统函数补丁、基于DKOM技术的进程及驱动隐藏、过滤驱动开发等。本文将对内核驱动调试工具的各种命令进行分析,期望能给热爱内核驱动调试的读者带来一点帮助。

很多时候,我们往往需要重写内核函数,此时就要用到内核调试,以了解内核数据结构;更重要的是,当完成一个sys驱动程序的编写后,我们并不确定程序是否符合编写目的,内核单步调试就派上用场了。本文是在参考《WindowsInternalsPart.16th.Edition》和《TheRootkitarsenal:escapeandevasioninthedarkcornersofthesystem》等相关书籍完成的。

内核调试必备文件和工具

1)WindowsSymbolsFiles

微软提供的Windows符号表是我们研究Windows内核的必备利器。首先,符号文件中包含内核函数和变量的名称以及数据结构体的布局和形式。在启动调试会话后,若引用到了某个镜像,此时必须确保调试器能访问到其所关联的符号文件。即在使用内核调试工具查看Windows内核对象如进程和线程列表、已加载驱动列表、内存使用情况时,须确保正确加载了内核镜像。

2)Windows调试工具包

Windows调试工具包最新版本已经作为Windows软件开发包SDK的一个组件,包含在软件开发包中。这些调试工具可用来调试用户模式下的进程及内核进程对象等。当安装完Windows驱动开发包WDK后,会看到6个可用的调试环境:VisualStudiowithintegratedWindowsdebugger、MicrosoftWindowsDebugger(WinDbg)、MicrosoftKernelDebugger(KD)、NTKD、MicrosoftConsoleDebugger(CDB)和MicrosoftNTSymbolicDebugger(NTSD)。

本文主要介绍Windbg和KD工具,其中Windbg工具是一款基于Windows系统的强大调试工具,支持用户和内核模式两种调试,如调试Windows内核、内核模式驱动、系统服务及用户模式下的应用程序和驱动等。使用Windbg对内核进行调试时,需要两台机器(即主机和目标机),如使用Vmware虚拟一台主机与本地主机进行关联调试,具体设置方式本文不做介绍。设置完成后,Windbg的界面如图1所示。


001.png

内核调试命令利器分析

1)列出可加载内核模块命令lm

内核模式下,使用lm命令来查看当前进程已经加载的模块,WinDBG会列出一个模块加载列表,如图2所示。

002.png

图2模块加载列表

2)!PROCESS命令

内核调试器!process命令用来显示某个进程对象及相关联的结构体信息。!process命令形式为:!processProcessFlags,其中Process参数可以指定为进程ID号或者与此进程相关的EPROCESS结构体基地址;Flags参数占5bit,用来标识显示的详细级别。若Flags等于0,则显示最小化信息,反之,若Flags=31,则显示进程的全部信息。大多数情况下,用户并不知道感兴趣的目标进程ID或者进程基地址,为了确定这些值,我们通常会缺省将参数值均设为0,即列出当前运行的所有进程基本信息,如图3所示。

003.png

从图3中给出的结果,可以获取active进程的进程ID和进程EPROCESS基地址。显然,此时我们只需要从列表中找到目标进程,然后执行“!process+进程基地址+Flags”即可获取到对应进程的详细信息。系统中每个运行进程都可以找到其对应的EPROCESS块。

EPROCESS结构中包含了指定进程的大量元素信息,而且还包含了一些子结构体和指向其他进程块的指针。如PEB域,即进程环境块指针,包含了进程镜像、进程导入的DLLs,及其它需要从用户模式下访问的Windows组件等。同样,我们可以利用Windbg工具的!peb命令导出PEB结构体,即使用“!peb+进程PEB指针”。有关PEB和EPRCOESS结构体的详细解析,可参看《WindowsInternalsPart.16th.Edition》一书P359~P367。

3)类型显示命令dt

当我们确认了一个符号对象后,在重定义此对象或者使用此对象的成员变量时,往往需要进一步确认此对象的结构体成员,此时显示类型变量命令dt就派上用场了。如我们需要进一步确认EPROCESS结构体成员变量域,可以使用“dt_EPROCESS”命令,如图4所示。

004.png

4)反汇编命令u

若我们需要确认一个底层符号函数的具体实现逻辑,此时可使用u命令,获取指定内存区域的intel汇编代码及机器码。u命令形式如图5所示。

005.png

图5u命令形式

若使用不带任何参数的u命令时,系统会从当前地址,即EIP寄存器值开始,连续打印出8条机器指令。我们也可以指定一个特定的线性地址开始,或者指定一个地址区域,设置直接指定某个函数。如图6所示,给出了使用u命令反汇编某个函数的打印结果。

006.png

5)显示命令集(d*)

若我们需要确定某个地址区域存放的数据内容,此时(d*)命令集可实现。通过(d*)命令集可以查看指定内存区域的数据内容,同样,(d*)命令集也存在多种表现形式,如图7所示。

007.png

从上面给出的命令形式集可知,若不带任何参数直接执行dd命令,则Windbg会从当前地址开始打印32个DWORDs;用户也可以指定起始地址如“dd692c8246”,即从地址0x692c8246开始打印32个DWORDs;同样,也可指定起始地址和结束地址,来获取指定区域的内存数据。

6)寄存器命令(r)

在内核调试器的上下文内,寄存器命令允许我们监视系统寄存器值。当系统存在多个处理器时,我们需要附上处理器ID,处理器ID一般以数字形式从0开始标识,当使用0x80作为参数时,可打印出控制寄存器内容;使用0x100时,则会dump出描述符寄存器内容,如图8所示。

008.png

7)内存搜索命令(s*)

Windowsx86系统进程的地址空间为4GB,通常Windows程序使用的内存空间占用从几百KB到几十MB之间,显然从内存中手工搜索指定的内容不切实际,此时s命令集可以帮助我们实现指定内容的搜索。其中的一个用法格式为:“s–[[Flags]]sa|suRange”,其中Range用来指定内存范围,sa用来搜索ASCII字符串,su则用来搜索UNICODE字符串,[Flags]则可用来指定搜索选项。比如“s–[l5]sapoi(nt!PsInitialSystemProcess)l200”,即可搜索变量nt!PsInitialSystemProcess所指向地址开始的512个字节范围内,任何长度不小于5的ASCII字符串。

小结

本文给出了Windows提供的调试工具下的常用命令,灵活掌握上述命令将会对Windows内核有更深入的了解,同样对Rootkit编写有一定的帮助。显然,Windows调试工具的命令不仅仅包含上面的内容,如栈回溯常用命令kp、查看内存属性的!address命令等。若读者感兴趣,可参看张银奎编写的《软件调试》和《WindowsInternalsPart.16th.Edition》等。这里再向大家推荐一本对Rootkits写的相对全面的书籍《TheRootkitarsenal:escapeandevasioninthedarkcornersofthesystem》firstedition。

(完)