rust逆向技巧
字数 2017 2025-08-29 22:41:24
Rust逆向分析技巧详解
一、Rust逆向三板斧
1. 快速定位关键函数(真正的main函数)
- 观察程序输出和输入
- 使用字符串搜索功能
- 设置断点逐步调试
- 关键技巧:如果一个函数在被调试运行(F8)之后,既有输出又要求输入,那么当前函数很可能不是真正的main函数
2. 定位关键加密区
- 根据输入的flag,在flag的内存区域设置硬件读断点
- 当程序访问flag内存区时,调试器会停止,此处大概率就是加密区
- 关键技巧:对于包含flag(无论加密前后)的内存区域,首先打上硬件读断点
3. 定位错误输出及比较功能
- 错误输出附近通常有比较功能的程序
- 定位到比较位置后,可以提取出正确加密后的结果
- 关键技巧:在C语言层面,对临时变量、局部变量等的修改,在汇编层面一定会反映到对内存空间的修改上
二、Rust语言特性与逆向
1. 传参与返回值
- 前6个参数分别使用寄存器:di, si, dx, cx, r8, r9
- 返回值使用ax寄存器
2. 与Go语言的对比
- Go语言前6个参数使用寄存器:ax, bx, cx, di, si, r8
- 额外参数使用:r9, r10, r11
- 返回值同样使用ax寄存器
三、实战案例分析
案例1:ciscn2024 rust_baby
1. 定位关键函数
- 先运行观察输出的错误字符串
- 在IDA中搜索不到时,通过调试定位关键输入输出函数
- 在入口函数设置断点,逐步跟踪到真正的main函数
2. 定位flag加密区
- 输入flag后,在flag内存区设置硬件读断点
- 程序访问flag内存区时停止,此处即为加密区
- 分析伪代码或汇编代码理清加密逻辑
3. 加密分析
- 示例中发现flag被8个字符一组处理(不足用'E'填充)
- 经过encode加密后,再异或0x33
- encode函数分析:
- 非对称加密
- 通过特定输入测试(如"bbbbbbbb"→"aabbccdd")
- 推断出key_1 = [1,1,0,0,-1,-1,-2,-2],对字符ASCII码进行加减
4. 多层加密处理
- 第一层加密后,flag内存位置改变,需重新设置硬件断点
- 发现第二轮加密:16个一组,共7轮,与静态key数组异或
- 通过输入不同flag验证key数组是否为静态
5. Base64加密
- 定位到base64加密区域
- 提取base64编码表
- 加密后结果存储到新内存区域
6. 比较区域
- 在base64加密后的内存区域设置断点
- 定位到比较区域,比较输入的flag加密后结果与正确结果
- 错误输出紧邻比较区
7. 解密流程
- 根据分析的加密步骤和提取的数据逆向flag
案例2:[羊城杯 2024]sedRust_happyVm
1. 定位关键函数
- 根据输出字符串快速定位
- 在flag内存设置硬件断点
2. 初始检查
- 分析汇编发现检查flag格式:
- 头部必须为"DSACTF"
- 长度必须为0x28
- 可通过输入"DASCTF{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}"绕过检查
3. Base64编码
- 提取flag的{}中内容到新内存空间
- 类似base64编码处理(3字符一组,83=64)
- 编码结果存储到新内存区域
4. VM虚拟机加密
- 对base64编码后的flag(base_flag)进行加密处理
- 将base_flag两个一组取出,进行移位、相加、与操作
- 与程序常数0x0B1000018结合,传入vmp函数加密
5. 正确性判断
- 定位输出"正确"的位置
- 发现vmp函数通过设置内存区域[rsp+0C88h+check]的值来判断
- 该值在vmp函数中被修改,最终与0比较
6. vmp函数分析
- 在vmp函数中定位修改判定条件的位置
- 发现a1[1048]的值被加法和异或操作修改
- 这两个操作是判断flag正确的关键
7. 加密/比较过程
- base_flag与程序立即数0xB1000018一起传入
- 第一次异或:对base_flag加密
- 第二次异或:加密结果与正确值比较
- 比较结果影响最终判定条件
8. 数据提取与解密
- 提取两组异或值,相互异或还原base_flag
- 对base_flag解码得到原始flag
四、IDA调试技巧
1. 硬件断点使用
- 对关键内存区域设置硬件读断点
- 当程序访问该区域时中断
- 特别适用于跟踪flag处理流程
2. 动态数据提取
- 使用IDA脚本在调试时提取关键数据:
start_process(path, args, sdir) // 启动进程并附加调试器 run_to(ea) // 运行到指定地址 wait_for_next_event(WFNE_SUSP|WFNE_CONT, -1) // 等待进程挂起后继续 get_wide_byte(ea) // 获取指定地址的值 get_reg_value("ECX") // 获取寄存器值
3. 断点管理
- 在关键操作位置设置断点
- 注意IDA可能将断点标记为"Unresolved"
- 必要时在汇编代码中直接观察寄存器和内存值
五、总结
- Rust逆向核心在于快速定位关键函数、加密区和比较区
- 硬件断点是跟踪flag处理流程的最有效工具
- 多层加密需要逐层分析,注意内存区域变化
- VM虚拟机逆向重点在于识别加密模式和关键判断条件
- 动态调试结合静态分析是解决复杂Rust逆向问题的有效方法