调试与逆向
在这小节,我们将学习简单的调试以及逆向技能,这对于恶意软件开发领域有这些帮助:理解当下的恶意软件的技术、功能、原理,分析恶意软件并且改进,开发漏洞利用以及 Shellcode,理解安全产品的原理以规避检测等。
我们将主要使用 WinDBG 作为动态调试工具,IDA 作为逆向工具。两者相辅相成,动态与静态相结合。WinDBG 可以在微软商店中获取:
IDA 可以从 https://hex-rays.com/ida-free/ 下载,拥有专业版自然更好。
WinDBG
调试器是插入在目标应用程序和 CPU 之间的计算机程序,充当类似代理的角色。使用调试器使我们能够查看应用程序的内存和执行流程并与之交互。接下来的课程内容中,我们将与用户模式交互。
CPU以二进制级别处理代码,这对人类来说很难阅读和理解,而汇编语言引入了二进制内容和编程语言之间的一对一映射。尽管汇编语言应该是人类可读的,但它仍然是一种低级语言,并且需要时间来掌握。 操作码是由 CPU 解释为特定指令的二进制序列,这在调试器中显示为十六进制值以及汇编语言的翻译。
接下来,利用 WinDbg,我们将学习如何使用断点来单步执行和控制应用程序的流程。
自定义界面
为了能有一个舒适的调试环境,我们可以对 WinDBG 的界面进行自定义,这样当我们调试应用程序的时候,可以在用户界面中查看到所需的信息,例如内存、汇编代码、断点信息等。
在导航栏中选中 View,我们可以添加多个窗口,这里面对我们调试过程会十分有帮助的有 WinDBG 命令 (Command)、寄存器 (Registers)、内存 (Memory)、栈 (Stack)、汇编代码 (Disassembly)。
点中之后,对应的窗口会浮现出来,可以使其与 WinDBG 主窗口相互独立,也可以将其嵌入至 WinDBG 主窗口,我会更推荐将它们嵌入至主窗口。不过因为主窗口空间有限,如果添加的窗口数量过多,也会影响我们对信息的提取效率,诸如模块 (Module)、断点 (Breakpoints) 等窗口我们不一定要添加到主页面,而是通过 WinDBG 的命令来查看相关信息。
下图是个人偏好的一个界面布局,你们可能注意到我添加了 2 个内存窗口,因为我们还想查看 RSP 的状态。
当我们想要调试一个进程或者应用的时候,可以选择使用 WinDBG 启动目标程序,或者附加到正常运行的进程中。
附加上之后,进程会自动被设置一个软件断点,对应的汇编指令为 int 3。
我们可以执行 WinDBG 命令 g 来继续执行。
在进入对 WinDBG 基本命令的学习之前,我们还需要知道调试符号。符号 (Symbol) 文件允许 WinDbg 使用名称而不是地址来引用内部函数、结构体和全局变量。例如,我们想给 kernelbase.dll 中的 CreateProcessA 函数设置软件断点,我们不需要先得到载入的 kernelbase.dll 中的 CreateProcessA 函数的地址,使用名称即可,命令为 bp kernelbase!CreateProcessA。在后面,我们也可以用符号来查看一些结构体。
符号文件以 .pdb 为拓展名,当应用程序的 pdb 与 PE 文件在同一目录下,符号文件会被自动载入从而识别应用程序中的符号。
这样,我们可以使用 process_calc!Main 来定位到 process_calc.exe 程序中的 Main 函数。
基本命令
反汇编
读取内存
读取结构体
修改和写入内存
搜索内存空间
检视寄存器
计算器
列举模块
调用栈
TEB
内存状态
软件断点
硬件断点
单步执行
t
p
执行至
ph 和 th
动态调试
pa 和 ta