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"
  • 必要时在汇编代码中直接观察寄存器和内存值

五、总结

  1. Rust逆向核心在于快速定位关键函数、加密区和比较区
  2. 硬件断点是跟踪flag处理流程的最有效工具
  3. 多层加密需要逐层分析,注意内存区域变化
  4. VM虚拟机逆向重点在于识别加密模式和关键判断条件
  5. 动态调试结合静态分析是解决复杂Rust逆向问题的有效方法
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字符一组,8 3=6 4) 编码结果存储到新内存区域 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脚本在调试时提取关键数据: 3. 断点管理 在关键操作位置设置断点 注意IDA可能将断点标记为"Unresolved" 必要时在汇编代码中直接观察寄存器和内存值 五、总结 Rust逆向核心在于快速定位关键函数、加密区和比较区 硬件断点是跟踪flag处理流程的最有效工具 多层加密需要逐层分析,注意内存区域变化 VM虚拟机逆向重点在于识别加密模式和关键判断条件 动态调试结合静态分析是解决复杂Rust逆向问题的有效方法