1. 动态调试的概念

动态调试是指在程序运行中,通过附加在程序进程上的调试器(debugger),获知程序的执行流程、内存数据和寄存器信息等的一种手段。

我们还有其他的监控程序运行的手段,比如动态插装和内存修改器(CE 大法好)

对于逆向工程,动态调试可以帮助使用者验证静态分析时的一些猜测,有时可以直接解决静态分析下表面上复杂的算法,例如对于某个本质上是可逆的算法,可以直接将密文作为输入,在动态调试中查看原程序处理后的明文。这比从头写解密脚本要快速得多,而且不容易出错。

Tip

建议可以优先尝试动态调试,看看能不能通过原程序直接得到 flag。

我们还可以通过动态调试完成对花指令和壳的分析。


IDA 可以应对大部分动态调试任务。如果出现 IDA 无法调试的情况,可以换用 olly dbg (32-bits) 和 x64dbg,因为后两者有比较完善的反调试插件(OpenSource 魅力时刻)。


2.IDA 支持的调试特性

2.1 断点

  • 软件断点

    IDA 将程序目标地址上的原字节覆盖为调试字节。当断点命中时,IDA 再恢复原字节

  • 硬件断点

    IDA 利用 CPU 提供的断点机制,将目标地址存入特殊的几个寄存器。CPU 执行到目标地址时,会向操作系统发送异常指令,IDA 就会捕获这个断点

  • 条件断点

    用户预设一段代码,程序执行到断点处,执行这段代码。如果代码返回 “True”,命中断点;如果代码返回 “False”,不命中断点。

  • 脚本断点

    用户预设一个脚本,每命中断点一次就执行一次脚本。脚本执行完后可以返回 “False”

    比如我们希望循环获取程序中某个寄存器的值,并且要求自动处理断点,我们就可以设置脚本断点,并让其返回 “False”


2.2 控制程序运行

  • 步入

  • 步过

  • 步出函数

  • 执行到光标位置


2.3 调试代码

  • 汇编级
  • 伪代码级
  • 源码级

2.4 内存操作

  • 寄存器读写
  • 内存读写

2.5 特殊调试

  • 进程调试
  • 附加调试

3.IDA 动态调试演示

BUUCTF - Reverse1

我们先查看程序的伪代码:

1
2
3
4
5
6
7
printf("input the flag:");
scanf("%20s", Str1);
v5 = j_strlen(Str2);
if ( !strncmp(Str1, Str2, v5) )
printf("this is the right flag!\n");
else
printf("wrong flag\n");

本段程序的目的是比较 Str1Str2Str1 由我们输入,而 Str2 作为目标 flag,是不依附于任何输入的。我们可以对

1
if ( !strncmp(Str1, Str2, v5) )

这一行设置断点,当断点命中时,查看 Str2 的值

(在伪代码窗口直接查看)

(汇编代码窗口查看)

FCTF 2025 - Tree

本题如果只靠静态分析加密算法的话是很吓人的,毕竟这里的加密算法又是二叉树又是 DFS 的,一看就搞不定。

真的搞不定吗?可以动态调试看看。

将密文作为输入,下断点在加密函数执行后,查看用户输入变量,惊奇地发现我们已经得到了 flag—— 不需要任何的密码和算法经验。

为什么?如果去问 DeepSeek,可以找到一些答案(但不要寄希望于小鲸鱼可以直接写出解密脚本,它也说不清楚):所有子节点指针都是 NULL,实际上没有构建出任何树结构,这不过是出题者写的纸老虎。此时该算法退化成简单的对称加密。

Note

尽管如此,我们提供的信息仍然无法让 DeepSeek 给出正确的解密脚本(至少我是如此)。DeepSeek 不厌其烦地跟我提示这里还有其他未发现的加密流程,可我无法定位。动态调试的建议直到我明确表述加密和二叉树无关后才提及。


4.IDA 附加调试演示

还是上面的例子,设置断点,但我们不从 IDA 运行程序。我们在外部先运行程序。

然后进入 Debugger > Attach to process… ,选择我们要调试的进程:

开始调试后,IDA 会先将程序停在某个系统 dll 库中,我们一般需要继续运行程序。


5. 调试代码演示

F7 是**步入(Step into)**,程序会进入下一个函数。如果需要撤回,可以按 Ctrl+ F7 (Run until return)。 F8是**步过(Step over)**,程序会跳过函数(`scanf`等具有阻塞机制的函数除外)。 F4是**执行到光标处(Run to cursor)**,程序可以执行到当前位置之*后*的任意位置。

6. 内存修改演示

调试时,我们一个比较常用的窗口是内存窗口 (Hex view)。

在 Hex View 窗口按下 G 键,或进入 Jump > Jump to address…,出现跳转窗口,输入你需要跳转到的地址即可。

IDA 提供了修改内存的功能。

我们跳到 Str1 处。

F2 或者右键 > Edit… 进入修改模式

通过修改对应位上的十六进制值,我们就可以修改 Str1 的内容:

修改完成之后再按一次 F2 或者右键 > Apply Changes,保存修改结果。


有时我们需要一次性复制大量内存数据,这时就可以用其他开发者提供的插件了,比如此处使用的 LazyIDA 插件:

插件提供了十六进制输入、Base64 编码输入和 ASCII 码输入三种输入方式:

我们的内存就被改好了。

需要注意的是,插件并不会自动添加字符串结尾的‘0’。如果你想要输入的是字符串,请手动添加末尾的‘0’。

如果需要修改寄存器的值,可以在 General registers 窗口点击目标寄存器的值进行修改。


7. 模块窗口演示

进入 Debugger > Debugger windows > Module list,弹出的窗口展示了当前程序加载的所有模块。在 Windows 系统上一般为.dll 文件,在 Linux 系统上一般为.so 文件。

调试.dll 或.so 库时需要关注这个窗口。


8. 跨平台调试

8.1 Windows 动态调试

如果要调试 PE 文件,我们直接使用 IDA 的 Windows 本地调试 (Local Windows debugger) 即可(当然 IDA 也支持远程调试 Windows 程序)

一般步骤:

  1. 选择调试器:Debugger > Select Debugger > Local Windows debugger
  2. 开始调试:Debugger > Start Process

注意调试前先设好断点。


8.2 Linux 动态调试

Linux 的 ELF 文件无法在 Windows 系统上运行,更不用说动态调试了。所以 IDA 提供了远程调试,在 Windows 上将调试指令发送到 Linux 上,在 Linux 中调试程序。

远程调试需要在被调试机上安装一个远程调试服务端。实际的调试指令由该服务端执行,IDA 作为调试前端展示调试结果。

IDA 和服务端之间通过 tcp 通信发送调试指令。

调试机和被调试机之间要保持网络畅通,一般两机是在同一个内网部署。

打开已经部署的 Linux 系统,将 IDA 安装目录 (Windows) 下 dbgsvr 的 linux_server 和 linux_server64 上传到 Linux 系统,运行 server

对于 Windows 用户,可以通过以下方式部署 Linux 系统:

  1. VMware、VirtualBox 等虚拟机软件
  2. WSL2 (⚠️必须是 WSL2,WSL1 不能远程调试)
  3. 本机双系统
  4. 云服务
  5. 再买一台主机装 Linux

你应该看到这样的输出:

之后我们打开 IDA。

我们还要将 Windows 上需要调试的文件上传到 Linux 中。我们可以手动上传,但在配置好远程调试后,IDA 也可以帮我们上传文件到 Linux。

选择 Debugger > Process options…,在弹出的窗口中按照 Linux_server 监听 (Listen) 的 IP 地址和端口设置 Hostname 和 Port。

0.0.0.0 表示监听所有可用地址。由于我们是本机调试,所以 Hostname 应填写 127.0.0.1,表示本地调试。

接下来选择 Remote Linux debugger,开始调试。由于 Linux 系统中没有目标文件,因此 IDA 会问我们需不需要上传到 Linux 中,这里我们选择 Yes,然后就进入我们熟悉的调试界面了:


9. 动态调试技巧

  • Ctrl + N 设置代码执行的位置(用来跳过不想运行的代码)
  • 使用插件(如 LazyIDA)批量修改内存

  • 附加调试(附加到一个正在运行的进程进行调试,一般附加成功后程序会断在一个固定的库函数处)

    1. 一般用来调试动态库

    2. 绕过一些反调试


©2025-Present Watermelonabc | 萌ICP备20251229号

Powered by Hexo & Stellar latest & Vercel & 𝙌𝙞𝙪𝙙𝙪𝙣 𝘾𝘿𝙉 & HUAWEI Cloud
您的访问数据将由 Vercel 和自托管的 Umami 进行隐私优先分析,以优化未来的访问体验

本博客总访问量:capoo-2

| 开往-友链接力 | 异次元之旅 | 中文独立博客列表

猫猫🐱 发表了 41 篇文章 · 总计 209.8k 字