转载

使用WinDbg调试Windows内核(一)

如果可以检查操作系统的内部工作过程,那么将会是一种强大的能力。一些先进的恶意软件都将内核作为共同的目标,许多最强大的漏洞也表现在内核组件中。因此使用一款调试器来探究这个环境是任何研究人员武器库中必备的有力工具。

学习这种调试的过程是很艰巨的,所以我提供了一些入门 WinDbg 调试的例子。我们尝试从基本命令开始,逐步转移到一些更高级的调试器的使用。本文使用了三个例子来展示 WinDbg 调试的能力,希望通过这种方式来证明这个工具的强大。

0×01  设置内核模式调试环境

下面所有的例子将使用 WinDbg ,可以从 微软官网 获得这款“ Windows 调试工具”,提供了包创建以及多用途的调试器。

当设置为内核调试时,你需要两台机器。其中一台用于调试器和另一台用于运行被调试的程序。建立内核调试环境的最简单方法是使用虚拟机和一款叫做 VirtualKD 的软件。 VirtualKD 可以让你调试命名管道,就好像是一个串行接口,大大加快了连接。它还提供了一个虚拟机( VM )监视器,只要你启动虚拟机调试器,它会自动启动。

VirtualKD与VMware或VirtualBox的效果很好。安装简单,指令可以在 SysProgs网站 找到。如果一切顺利的话你的虚拟机将会在调试器中断,就像这样:

使用WinDbg调试Windows内核(一)

现在所有的调试环境设置已经做好了。在任何时候,你可以使用“ g ”(执行)命令让虚拟机重新执行调试。同样,你可以通过使用 WinDbg 中的 CTRL + BREAK 快捷键中断一个正在运行的虚拟机。

0×02 设置符号

调试的一个重要方面是建立目标系统的正确符号。符号允许调试器匹配编译的二进制程序的地址,匹配函数或变量名,源文件路径以及每个符号对应于源文件中的行号。要显示的符号的重要性可以看看这两个相同的堆栈跟踪结果的差异:

没有设置符号:

使用WinDbg调试Windows内核(一)

设置符号:

使用WinDbg调试Windows内核(一)

幸运的是微软提供了大部分的二进制公共符号。公共符号通常包括定义所有的函数,静态和全局变量。他们还提供了一个符号服务器,以便调试器可以查询二进制文件中正确的符号。建立符号最简单的方法是设置“ _NT_SYMBOL_PATH ”环境变量。这是 WinDbg 和其他程序,如 IDA ,标准的查询符号路径的环境变量。您可以使用它连接到 Microsoft 符号服务器以及缓存本地符号路径: c:/symbols 。本地缓存加速后来的符号访问:

srv*c:/symbols* http://msdl.microsoft.com/download/symbols

一旦符号路径设置,重新启动 WinDbg ,将会正确地设置新的符号路径。你可以在 WinDbg 中键入“ . sympath ”确认它正在使用的符号路径。在这一点上,你可以运行命令“ .reload -f ”,这将迫使的目标系统下载所有的符号,并且为每个模块缓存并加载。

0×03 开始使用一些基本的调试命令

WinDbg 是一个强大的工具,但对于没调试过的人来说不是特别人性化。它 提供了大量的可用命令,一些常见的命令还是值得查看的。 这里 是详细的命令列表, 帮助命令是“ .hh <CMD> ”。我们将通过 WinDbg 调试系统调用的基本函数。下面均是在 Windows 7 64 位系统下完成的。

首先,让我们来看看有哪些模块是加载在当前目标系统上。如果你的符号设置正确你就可以执行你的第一个 WinDbg 的命令。使用“ lm ”(列表模块)命令,你应该看到这是当前加载的模块列表。你应该看到模块名称,并看到被加载的地址信息。这是从我的虚拟机中的截取的列表。

使用WinDbg调试Windows内核(一)

上述列表中“ NT” 模块比较有趣。这是 Windows 内核执行模块的名字。该模块是 Windows 内核主功能区,它负责 I / O ,对象管理,安全和过程管理。我们在用另一个命令深入到内核中,查看它的导出函数。 WinDbg 的命令“ X” (检查)查询一个给定模块的符号。它可以被调用为 < 模块 > < !符号 >” ,并接受通配符。所有可访问的系统调用都是先从字母 NT 开始。我们用“ X NT  NT * File * 命令列出进行文件操作相关的系统调用的列表。

使用WinDbg调试Windows内核(一)

返回值是位于内存中的函数名。我们用“ U ”(反汇编)看看其中一个内存中的函数。“ U ”命令需要一个内存地址,该地址是内存中函数的地址,返回值是该函数的反汇编函数。我们可以利用内存地址反汇编 NtCreateFile 函数, Windbg 会解析为我们解析该处的地址:

使用WinDbg调试Windows内核(一)

如果你想反汇编整个函数,那么可以使用“ uf ”反汇编命令。现在,我们可以尝试在 NtCreateFile 上下一个断点,来检查一些函数。添加断点命令是“ bp ”,它也需要一个存储器地址(或一个有效符号)作为参数。一旦设置断点并使用“ g ”继续执行,不久便在断点处断下:

使用WinDbg调试Windows内核(一)

在上面的截图中断点断下,然后使用“ K ”(栈)命令来显示这个函数的堆栈调用。 WinDbg 未能解析底部的一些符号。这是因为我们已经进入了一个没有加载符号的用户模式进程上下文中。我们可以通过“ .reload /user ”中加载这些丢失的用户模式符号。当在内核调试时,你必须始终牢记这些用户模式进程在何时被映射到内存中。由于 Windows 使用虚拟地址空间,用户模式地址仅适用于它们被分配的进程上下文。当用户进程上下文切换时,符号将需要重新加载该用户上下文。可以在 这里 找到虚拟寻址的说明,。一旦重新加载符号我们就可以得到一个完整的调用堆栈:

使用WinDbg调试Windows内核(一)

我们可以用“! process -1 0 !”在进程中查询当前映射(该过程最终调用 NtCreateFile 第一个参数( -1 )请求用于当前进程信息,第二个参数( 0 )是要显示的数据量。设置为 0 时表示显示最少的信息。

使用WinDbg调试Windows内核(一)

在这种情况下,我们被称为 SearchIndexer 。最后,我们可以找出 NtCreateFile 调用磁盘的文件。为了帮助我们找到这些信息,我们需要知道有关 NtCreateFile 的参数。 MSDN 已经记录了大多数的系统调用函数。 NtCreateFile 是这样的:

NTSTATUS NtCreateFile(

_Out_    PHANDLE            FileHandle,

_In_     ACCESS_MASK        DesiredAccess,

_In_     POBJECT_ATTRIBUTES ObjectAttributes,

_Out_    PIO_STATUS_BLOCK   IoStatusBlock,

_In_opt_ PLARGE_INTEGER     AllocationSize,

_In_     ULONG              FileAttributes,

_In_     ULONG              ShareAccess,

_In_     ULONG              CreateDisposition,

_In_     ULONG              CreateOptions,

_In_     PVOID              EaBuffer,

_In_     ULONG              EaLength

);

来源是 这里

在内核 API 中,文件名字段为 OBJECT_ATTRIBUTES 结构体,   作为指针传递给 NtCreateFile 。在这种情况下,它是第三个参数,因此将在 R8 寄存器传递。阅读关于在 64 位调用约定的 文档 ,了解函数是如何被调用。有了这些知识后,因为它是被传递到我们的断点函数中,可以显示此结构的内容。命令 dt (显示类型)可以显示 我们只需给它一个内存地址和数据类型。这里,我们将使用“ DT _OBJECT_ATTRIBUTES @ R8” ,就好像是一个 OBJECT_ATTRIB UTES结构,来显示R8寄存器引用的内存。

使用WinDbg调试Windows内核(一)

注意:当它们一般由下划线进行结构处理。这是因为大多数微软结构的名称均带有一个前导下划线,然后 typedef 定义具有相同名称省略下划线。

现在,我们就大功告成了,我们可以删除我们设定在一开始的断点。您可以使用“ BL ”(断点列表)和“ BC ”删除断点:

使用WinDbg调试Windows内核(一)

现在,我们已经通过进一步的调试,掌握了所需的基本工具和技术。你现在应该能够检查内存结构,断点功能,查询符号和查看调用堆栈。结合这些能力,你应该可以开始探索该系统。当使用上述技术继续下一个部分的调试研究时,我们还将学会更多更高级的调试技巧。

*参考来源: contextis.com ,FB小编老王隔壁的白帽子翻译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

原文  http://www.freebuf.com/articles/web/99512.html
正文到此结束
Loading...