3、固件基础知识:固件定义、固件类型(Bootloader、RTOS、应用固件)、固件文件格式(BIN、HEX、ELF、UBoot镜像)

固件(Firmware)是嵌入式系统中介于硬件与上层软件之间的关键层,它直接驱动硬件寄存器、管理中断向量、调度任务并承载业务逻辑。与通用计算机的BIOS/UEFI不同,嵌入式固件往往以“裸机镜像”或“RTOS镜像”的形式整体烧录到NOR Flash、NAND Flash、eMMC或SPI Flash中。理解固件的定义、类型与文件格式,是进行逆向分析、二进制提取、漏洞挖掘和固件更新的前提。本章将从固件的本质出发,梳理Bootloader、RTOS、应用固件的分层关系,并深入解析BIN、HEX、ELF、UBoot镜像四种主流格式的存储结构、加载地址与转换方法。

固件类型与文件格式映射关系 硬件层:CPU核(ARM Cortex-M/A / RISC-V / Xtensa) + 存储(NOR/NAND/eMMC/SPI Flash) + 外设(UART/SPI/I2C/DMA/Timer) 固件层(Firmware) Bootloader 启动引导 / 硬件初始化 / 跳转 RTOS内核 任务调度 / 信号量 / 队列 / 内存管理 应用固件 业务逻辑 / 协议栈 / 驱动封装 固件文件格式:BIN(原始二进制) / HEX(Intel HEX) / ELF(可执行与链接格式) / UBoot镜像(uImage + FIT) 逆向分析入口:从Flash提取BIN → 解析Bootloader分区 → 定位RTOS镜像 → 反汇编应用固件 关键点:基地址(Load Address)、入口点(Entry Point)、校验和(CRC/Checksum)、压缩标志

3.1 固件定义与分层架构

核心原理

固件是存储在非易失性存储器中的软件集合,它直接操作硬件寄存器,不依赖操作系统或中间件。在嵌入式系统中,固件通常由三部分构成:Bootloader(引导程序)、RTOS内核(实时操作系统)和应用固件(业务逻辑)。三者并非总是同时存在——小型MCU项目可能只有裸机应用固件,而复杂的SoC(如高通、海思平台)则包含多级Bootloader(如XBL、ABL、U-Boot)和多个RTOS/HLOS镜像。

从逆向工程视角看,固件是一个“二进制大对象”(Binary Large Object, BLOB),其内部结构取决于编译链接脚本(Linker Script)和启动流程。分析固件的第一步是确定其加载地址(Load Address)和入口点(Entry Point),这决定了反汇编时使用的基址。例如,ARM Cortex-M系列通常从0x08000000(Flash起始)启动,而Cortex-A系列则可能从0x40000000或0x80000000启动。

判断方法

  • 查看启动向量表:ARM Cortex-M的向量表位于Flash起始地址,前4字节为初始SP值,第5字节为Reset_Handler地址。通过分析向量表可快速定位固件类型。
  • 识别RTOS特征:FreeRTOS的TCB(任务控制块)包含固定偏移的字段,uC/OS-II的OS_TCB有特定签名;RT-Thread的线程控制块也有独特结构。
  • 分析Bootloader字符串:U-Boot镜像通常包含"U-Boot 2020.04"等版本字符串,可通过binwalk或strings工具提取。

案例拆解:从路由器固件中分离三部分

某家用路由器固件(16MB SPI Flash)提取后,使用binwalk -e扫描,发现偏移0x0处为U-Boot(约256KB),0x40000处为Linux内核(LZMA压缩),0x200000处为SquashFS根文件系统。进一步分析U-Boot环境变量,发现bootcmd指定了内核加载地址0x82000000,设备树地址0x81000000。通过dd命令分别提取三个分区,再使用jefferson解包SquashFS,最终定位到Web服务程序(应用固件)的二进制文件。

复盘要点:固件分层分析的关键是“先分区、后解析”。使用binwalk、firmware-mod-kit或ubi_reader等工具,先识别文件系统边界,再针对每个分区单独逆向。切勿直接对整个固件进行线性反汇编,否则会因数据与代码混杂导致大量无效指令。

3.2 固件类型详解:Bootloader、RTOS、应用固件

3.2.1 Bootloader

Bootloader是上电后最先执行的代码,负责初始化时钟、DDR、Flash控制器,并加载后续镜像。常见Bootloader包括:U-Boot(广泛用于ARM/PPC/MIPS)、Coreboot(x86/ARM服务器)、Little Kernel (LK)(Android设备)、Barebox(嵌入式Linux)。Bootloader通常包含网络协议栈(TFTP/NFS)、Flash编程命令和交互式Shell,这些功能为逆向分析提供了丰富的字符串和函数特征。

Bootloader类型典型平台存储介质逆向特征
U-BootARM64 / ARM32 / RISC-VSPI NOR / eMMC包含"U-Boot"字符串、md/cp/mw命令表
LK (Little Kernel)Qualcomm / MediaTekeMMC / UFSABL(Android Bootloader)分区,包含"LK"版本号
Bareboxi.MX / AM335xNAND / NOR类似Linux的Shell,支持devicetree

3.2.2 RTOS内核

RTOS提供任务调度、中断管理、时间片轮转和同步原语。常见RTOS包括:FreeRTOS(开源,MCU主流)、RT-Thread(国产,支持POSIX)、VxWorks(商业,航空航天)、ThreadX(微软,IoT)。RTOS固件的逆向重点在于识别任务控制块(TCB)结构、调度器入口和任务栈布局。例如,FreeRTOS的pxCurrentTCB指向当前任务,通过分析任务切换函数(如vTaskSwitchContext)可定位所有任务入口。

3.2.3 应用固件

应用固件是用户业务逻辑的载体,可能包含网络协议栈(lwIP)、文件系统(LittleFS)、加密算法(mbedTLS)等。在物联网设备中,应用固件往往通过OTA(Over-The-Air)更新,因此逆向时需关注固件签名验证逻辑和版本回滚保护机制。

风险提示:在分析RTOS任务时,不要仅依赖静态反汇编。建议使用JTAG/SWD调试器附加运行,通过实时读取pxCurrentTCB和任务栈内容,动态确认任务优先级和状态。静态分析容易将任务函数误判为普通函数,导致调用关系混乱。

3.3 固件文件格式:BIN、HEX、ELF、UBoot镜像

3.3.1 BIN(原始二进制)

BIN文件是纯二进制数据,无任何元数据,必须知道加载地址才能正确反汇编。它通常由objcopy -O binary生成,或直接从Flash中dd提取。BIN文件的优点是体积最小,缺点是缺乏符号信息和段边界。逆向BIN时,需通过向量表、字符串引用或已知外设寄存器地址来推断基址。

3.3.2 Intel HEX(HEX)

HEX文件是ASCII文本格式,每行以冒号开头,包含长度、地址、类型、数据和校验和。类型包括:00(数据)、01(文件结束)、02(扩展段地址)、04(扩展线性地址)。HEX文件适合烧录器,但逆向时需先转换为BIN。使用objcopy -I ihex -O binary firmware.hex firmware.bin即可转换。

3.3.3 ELF(可执行与链接格式)

ELF是Linux/Unix系统及嵌入式交叉编译的标准格式,包含ELF头、程序头表(段)和节头表(节)。关键段包括:.text(代码)、.rodata(只读数据)、.data(已初始化数据)、.bss(零初始化数据)。ELF保留了符号表和重定位信息,是逆向分析的最佳格式。使用readelf -a可查看所有节,objdump -d可反汇编。

3.3.4 UBoot镜像(uImage / FIT)

U-Boot镜像在BIN/ELF基础上增加了64字节的头(对于uImage)或FIT(Flattened Image Tree)结构。uImage头包含:镜像类型(内核/ramdisk)、加载地址、入口点、CRC32校验值。FIT是设备树源(DTS)描述的镜像集合,支持多配置和数字签名。解析uImage使用mkimage -l uImage,解析FIT使用dumpimage -T flat_dt -l fit.itb。

格式元数据加载地址符号信息逆向工具
BIN无需手动指定无IDA / Ghidra(手动加载)
HEX地址记录内嵌无objcopy / 十六进制编辑器
ELF节/段表程序头指定有(.symtab)readelf / objdump / Ghidra
uImage64字节头头内指定无mkimage / dumpimage

案例拆解:从ELF到BIN的完整转换与逆向

某智能门锁固件(基于STM32F407)提供firmware.elf,使用readelf -h查看入口点0x08000135,readelf -S发现.text起始0x08000000,.data加载地址0x20000000。使用objcopy -O binary -R .bss firmware.elf firmware.bin生成纯代码段BIN。在Ghidra中加载BIN,设置基址0x08000000,自动分析后定位到main函数(通过向量表Reset_Handler)。进一步交叉引用,发现OTA升级函数ota_update,其中包含对固件签名的RSA验证逻辑。

经验提醒:当固件以HEX格式提供时,优先转换为BIN再分析。HEX的扩展线性地址记录(类型04)可能将地址扩展到0xFFFF0000以上,直接反汇编HEX会导致地址错乱。转换命令:arm-none-eabi-objcopy -I ihex -O binary input.hex output.bin。

3.4 固件格式识别与转换实战

操作流程

  1. 文件类型探测:使用file firmware.bin查看文件类型;使用binwalk firmware.bin扫描嵌入的文件系统。
  2. 头部特征匹配:检查前64字节是否包含uImage头(27 05 19 56魔数)或FIT结构(d0 0d fe ed)。
  3. 地址推断:若为BIN,搜索ARM/Thumb指令特征(如00 00 00 00后的跳转指令),或查找中断向量表(Cortex-M的SP和PC初始值)。
  4. 格式转换:使用objcopy在ELF/HEX/BIN之间互转;使用mkimage生成或解包uImage。
  5. 加载到反汇编器:在IDA/Ghidra中手动指定处理器类型(ARM/Thumb/MIPS)和基址,开始分析。

常见误区

  • 忽略字节序:ARM Cortex-M默认小端,但部分MIPS/PPC平台使用大端。错误设置字节序会导致所有指令解码失败。
  • 混淆加载地址与链接地址:加载地址是镜像在Flash中的位置,链接地址是运行时地址。对于位置无关代码(PIC),两者可能不同。
  • 未处理压缩段:部分固件使用LZMA/gzip压缩内核或文件系统,需先解压再分析。使用binwalk -e自动解压。
总结复盘:固件逆向的第一步是“格式识别与地址恢复”。掌握BIN/HEX/ELF/uImage四种格式的差异,能快速定位加载地址和入口点。对于Bootloader、RTOS、应用固件的分层,建议采用“自底向上”的分析策略:先解析Bootloader的启动流程,再定位RTOS内核的调度入口,最后分析应用固件的业务逻辑。实际项目中,优先获取ELF格式的固件(包含调试信息),可大幅降低逆向难度。