4、固件二进制分析:ARM/MIPS/RISC-V架构基础、反汇编工具链对比、固件入口点定位

好,咱们进入正题。这一章聊的是固件二进制分析,说白了就是拿到一个陌生的固件文件,怎么下手。我见过不少新手,上来就用IDA一顿猛怼,结果发现反汇编出来的代码根本看不懂——为啥?因为连目标芯片是什么架构都没搞清楚。

嗯,磨刀不误砍柴工。咱们先打好基础。

4.1 三大嵌入式架构:ARM、MIPS、RISC-V

做固件逆向,第一件事就是判断架构。你想想看,ARM的指令长度和MIPS都不一样,用错反汇编引擎,出来的全是乱码。

4.1.1 ARM架构

ARM是目前智能家居固件里的绝对主流。我拆过的设备,十有八九都是ARM核。它有两个模式你得记住:

  • ARM模式:指令固定4字节,性能高
  • Thumb/Thumb-2模式:指令可以是2字节或4字节,密度高

这里有个坑。我曾经拿到一个固件,用IDA默认的ARM模式反汇编,结果函数入口全是乱码。折腾了半天才发现,这固件其实是Thumb-2混合编码的。切换模式后,代码瞬间就清晰了。

注意:ARM的PC寄存器在ARM模式下指向当前指令+8,在Thumb模式下指向当前指令+4。这个细节在做栈回溯时特别重要,搞错了调用链就全歪了。

4.1.2 MIPS架构

MIPS在路由器、网关设备里很常见。它的特点是:

  • 指令固定4字节,没有Thumb这种变长模式
  • 有延迟槽(Delay Slot)——分支指令后面的那条指令一定会被执行
  • 大小端模式都有,得看具体芯片

我个人习惯,拿到MIPS固件第一件事就是看入口点附近的指令。如果是luiaddiu这种组合,基本就是MIPS没跑了。

小技巧:MIPS的延迟槽是逆向时的噩梦。我曾经在分析一个路由器固件时,因为没注意延迟槽,把一个关键函数的调用关系完全搞反了。建议你在反汇编时,把延迟槽指令单独标出来。

4.1.3 RISC-V架构

RISC-V是后起之秀,最近几年在IoT设备里越来越多。它的特点:

  • 指令长度可变:基础指令是2字节,但大部分是4字节
  • 模块化设计:RV32I是基础整数指令集,RV32M是乘除法扩展
  • 寄存器数量多,有32个通用寄存器

说实话,RISC-V的固件我接触得还不多,但趋势很明显。我建议你现在就开始熟悉它的指令格式,别等满大街都是RISC-V设备了再学。

4.2 反汇编工具链对比

工具这东西,没有最好的,只有最顺手的。我三个都用过,给你说说我的真实感受。

特性 Ghidra IDA Pro Radare2
价格 免费开源 商业软件(贵) 免费开源
架构支持 ARM/MIPS/RISC-V全支持 全支持,且更新快 全支持,但需手动加载
反汇编质量 好,尤其是ARM Thumb 极好,业界标杆 良好,但需调参
脚本能力 Python/Java Python/IDC Python/R2Pipe
学习曲线 中等 陡峭 陡峭
我最常用的场景 固件批量分析 深度逆向、调试 快速查看、自动化

4.2.1 Ghidra —— 我的主力工具

Ghidra是NSA开源的,说实话,刚出来时我还不信它能比IDA好。用了一段时间后,真香。它的优势在于:

  • 自动分析能力强:加载固件后,它能自动识别函数、变量、字符串
  • 反编译功能:直接把汇编转成C代码,虽然不一定100%准确,但能省80%的时间
  • 团队协作:可以多人同时分析同一个项目

我现在的流程是:先用Ghidra做初步分析,定位关键函数,然后再用IDA做深度逆向。

4.2.2 IDA Pro —— 老牌王者

IDA Pro我用了快十年了。它的反汇编质量确实是最好的,尤其是对付混淆过的代码。但缺点也很明显:

  • 贵,个人用户基本买不起
  • 插件生态虽然丰富,但配置起来很麻烦

我一般只在两种情况下用IDA:一是遇到加壳或混淆的固件,二是需要动态调试时。

4.2.3 Radare2 —— 命令行利器

Radare2是纯命令行的,刚开始用会很不习惯。但一旦上手,你会发现它特别适合自动化分析。比如:

# 加载固件并自动分析
r2 -A firmware.bin

# 查看入口点
[0x00000000]> afl

# 反汇编指定地址
[0x00000000]> pd 20 @ 0x1000

我写自动化脚本时,首选就是Radare2。它轻量、可定制,而且支持管道操作。

4.3 固件入口点定位

这是最关键的步骤。入口点找错了,后面全白干。

4.3.1 常见入口点类型

  • Reset Vector:ARM/MIPS上电后第一个执行的地址,通常是0x00000000或0xFFFF0000
  • Startup函数:C运行时初始化代码,负责设置栈、BSS段等
  • main函数:用户代码的入口

4.3.2 我的定位方法

我一般按这个顺序来:

  1. 看文件头:如果是ELF或PE格式,直接读头里的入口点字段
  2. 找中断向量表:ARM的向量表在0x00000000,第一个就是复位向量
  3. 搜索特征字符串:比如"main"、"start"、"_start"
  4. 分析交叉引用:从已知的库函数反推入口
实战案例:我曾经分析过一个智能门锁的固件,是裸机程序,没有文件头。我通过搜索"0xEA00000E"(ARM的B指令)找到了复位向量,然后顺着跳转链找到了main函数。整个过程花了不到10分钟。

4.3.3 架构特定的入口点特征

不同架构的入口点有各自的特点:

  • ARM:复位向量通常是LDR PC, [PC, #offset]B label
  • MIPS:入口点通常是lui sp, high + addiu sp, low设置栈指针
  • RISC-V:入口点通常是j _startauipc + jalr组合

嗯,这里要提醒一句:有些固件会故意混淆入口点,比如用花指令或者跳转表。遇到这种情况,别慌,从已知的库函数(比如memset、memcpy)反向追踪,往往能找到线索。

4.4 本章知识体系

下面这张图,是我梳理的固件二进制分析的核心流程。你可以把它当作一个检查清单:

固件二进制分析核心流程 ① 固件获取与识别 ② 架构判断(ARM/MIPS/RISC-V) ③ 选择反汇编工具 Ghidra IDA Pro Radare2 ④ 入口点定位与分析

说白了,固件二进制分析就是一条流水线:拿到固件 → 判断架构 → 选工具 → 找入口。每一步都有坑,但只要你按这个流程走,至少不会跑偏。

好了,这一章的内容就到这儿。下一章咱们会深入具体的反汇编实战,到时候我会拿一个真实的智能插座固件来演示。


专注资料整理