本文写作时使用的 IDA Pro 版本:Version 8.3.230608 Windows x64
作者现已升级到 Version 9.1.20250226
IDA 从 Version 9 开始启用新的默认快捷键方案,如果用不惯,在 Options > Shortcuts… 里取消勾选 “Use new shortcuts”
IDA(Interactive Disassembler,交互式反汇编器)由 Hex-Rays 开发,是无数逆向工程师心中的女神是反汇编和反编译行业的首选解决方案。IDA 反编译器将机器代码(反汇编过程的结果)转换为人类可读的类似 C 语言的伪代码文本。
IDA 可以作为通用反汇编器使用,其支持的文件类型请参考 Disassembly Gallery。当然,由于是 “通用”,说明 IDA 可能无法良好完成特定语言/平台的反汇编/反编译,这时请寻找专门工具,比如 Python 的 pyc 文件有 uncompyle6 (3.😎 库和 pycdc (3.9+),exe 文件有 pyinstxtractor 脚本;.NET 平台有 dnspy 和 dotPeek;Java 有 JADX 和 JEB。
1. 安装
要么正版:ida-free
有无 Fugger 让我看看正版 😘,一年要一千多刀乐呢!
要么到 吾爱破解 上搜一搜。本笔记使用的 IDA Pro 就是来自 52 上的分享
2. Python 插件
IDA 支持以 Python 语言编写的插件,你可以在官方的 Plugins & Apps 中找到丰富的插件,如果你有能力,也可以自己开辟一片天地。
较新版的 IDA 建议使用 Python 3.11。如果你想要更换 IDA 使用的 Python 版本,可以运行安装目录下的 idaptswitch.exe
。注意 IDA 不能识别相对路径,此时请在终端运行 idaptswitch.exe -s <目标 Python 的绝对路径>
。
如果你使用 Pyenv 安装 Python,建议更换其他方式安装的 Python,或者使用 Embeddable Python(嵌入式版本 Python)。
Embeddable Python 只需要解压到 IDA 安装目录即可。注意,如果使用 Embed 版本,需使用解压得到的 Python 目录下的 python.exe 安装 pip 及后续依赖包。
插件的安装很简单:将插件放在安装目录下的 plugins 文件夹里就行。
这里推荐两个插件:
- KeyPatch:用以修改汇编指令。使用前需要在 python 中通过 pip 安装依赖
keystone-engine
- LazyIDA:用于提取数据、批量修改数据
3. 选择哪个 IDA
进入 IDA 的安装目录,我们有两个 IDA:ida.exe 和 ida64.exe,要选哪一个?
很简单,要反汇编 32 位可执行文件,就用 ida.exe (32-bit);要反汇编 64 位可执行文件,就用 ida64.exe (64-bit)。
在 IDA 9 中,HexRays 终于将这两个可执行文件合二为一了。换句话说,对于 IDA 9,无论是 32 位还是 64 位可执行文件,都使用 ida.exe。
如果不知道可执行文件的位数,我们可以:
- 用 Linux 系统下的
file
命令 - 用 peid、exeinfo 和 DIE 等查壳软件(首选 DIE)
请确保目标程序和 IDA 等逆向工具的位数相同(32 位对 32 位,64 位对 64 位),否则可能出现出乎意料的结果。
4. 熟悉 IDA 的子窗口
- 函数 (Functions) 窗口。列举所有已经被 IDA 识别的函数
- IDA View 窗口。汇编代码窗口,空格键切换图形模式和文本模式,Tab 键或 F5 键切换到伪代码窗口 (Pseudocode)
- 伪代码窗口 (Pseudocode)。在伪代码位置按下 Tab 键可以切换到对应的汇编窗口 (IDA View)。
- 字符串窗口。列举程序代码所有引用到的字符串常量
- Shift + F12 打开字符串窗口
- Ctrl + F 可以弹出底部搜索小窗口
- 其他窗口,如 HEX View、Exports、Imports、Structures
View > Open subviews 可以找到 IDA 绝大部分子窗口的入口。
5. 命名前缀
IDA 需要调试符号文件(对于 Microsoft C / C++ 和 C# 程序,为 PDB 文件)来获取代码元素(变量、函数等)的名字。如果没有,那么 IDA 会尝试自动生成这些元素的名字,一般是 prefix_ + random number
。命名前缀有这些:
sub_
:指令和子函数起点locret_
:返回指令块loc_
:普通指令块off_
:数据,包含偏移量seg_
:数据,包含段地址值asc_
:数据,ASCII 字符串byte_
:数据,字节(或字节数组)word_
:数据,16 位数据(或字数组)dword_
:数据,32 位数据(或双字数组)qword_
:数据,64 位数据(或 4 字数组)flt_
:浮点数据,32 位(或浮点数组)dbl_
:浮点数,64 位(或双精度数组)tbyte_
:浮点数,80 位(或扩展精度浮点数)stru_
:结构体(或结构体数组)algn_
:对齐指示unk_
:未处理字节
6. 示例
我们希望找到程序中的 main
函数,因为 main
函数里头是我们真正想要看到的代码。
如何找到 main
函数?一种方式是看 IDA 的 Functions 窗口,找找看有没有 main
函数。
没有或者列出的函数量太大的话就需要分析程序行为了。
试着运行一下程序,看看它的输入输出。很多程序会输出一些提示用字符串,我们可以通过字符串来定位main
函数。
转到字符串窗口,用 Ctrl + F 唤起搜索小窗口并输入你要找的字符串,然后双击,IDA 会跳到字符串在反汇编中的位置。
你可能会看到像这样的指令:
1 | .rdata:004250EC aD db '距离出现答案还有%d秒,请耐心等待!',0Ah,0 |
这时可以右击这行指令,选择 “Jump to xref to operand” 或者 “List cross reference to…”,IDA 会列出所有引用了这个字符串的函数,然后你就可以选择要跳到main
函数了。
找到main
函数,转到伪代码窗口,我们可以得到一个相对好阅读的代码。这个代码中有一些 IDA 没能填上的 “坑”,需要我们合理猜测,将函数和常变量猜出来。
入门阶段逆向程序的基本思路是:
graph LR A[查、脱壳程序] --> B[运行程序] B --> C[收集字符串] C --> D[寻找字符串的引用函数] D --> E[生成函数伪代码] E --> F[修复匿名函数] F --> G[分析程序逻辑] G --> H[获得 Flag 😄]
当然,随着学习的深入,这套流程的局限性也会显现。