2、嵌入式系统基础:嵌入式硬件架构(MCU/MPU)、外设接口(UART/SPI/I2C/CAN)、固件与操作系统(RTOS/Linux)基础

嵌入式安全模糊测试(Fuzzing)并非在真空中进行,其测试目标、输入注入方式、崩溃检测手段以及执行环境,均深深植根于嵌入式系统的硬件架构、外设通信机制与软件运行形态。若缺乏对底层系统的清晰认知,安全测试人员将难以判断一个崩溃是源于内存破坏、逻辑竞态,还是外设时序异常。本章作为课程的第二块基石,将系统梳理嵌入式硬件架构(MCU与MPU的差异)、主流外设接口(UART/SPI/I2C/CAN)的电气特性与协议要点,以及固件与操作系统(RTOS/Linux)的运行模型,为后续章节中针对特定目标设计模糊测试策略奠定坚实的知识框架。

嵌入式系统模糊测试目标分层架构 硬件架构层 • MCU: Cortex-M, 内部Flash • MPU: Cortex-A, 外部DDR • 内存保护单元(MPU/MMU) • 调试接口: SWD/JTAG • 时钟/复位/电源域 外设接口层 • UART: 异步串行, TX/RX • SPI: 同步全双工, MOSI/MISO • I2C: 半双工, SDA/SCL • CAN: 差分总线, CAN_H/L • DMA/中断控制器 固件与OS层 • 裸机/RTOS (FreeRTOS) • Linux Kernel + Rootfs • 设备驱动/中断处理 • 系统调用/IPC • 固件镜像/文件系统 寄存器/中断 协议栈/驱动 模糊测试(Fuzzing)攻击面入口 网络报文 / 串口指令 / 配置文件 / 固件解析 / 物理协议注入 安全测试视角: 1. 硬件层决定内存隔离能力(MPU/MMU)与故障注入接口(电压/时钟毛刺)。 2. 外设接口是数据输入的主要通道,协议状态机是模糊测试的关键状态依赖。 3. 固件与OS决定崩溃的可观测性(panic日志、看门狗复位、core dump)。

2.1 核心原理:MCU与MPU的架构差异及其安全影响

嵌入式处理器根据计算能力、内存管理和应用场景,主要分为微控制器(MCU)和微处理器(MPU)两大类。MCU(如ARM Cortex-M系列)将CPU核心、Flash存储器、SRAM以及丰富的外设控制器集成在单一芯片上,采用哈佛架构或改进型冯·诺依曼架构,强调实时性、低功耗和确定性执行。其内存保护通常依赖可选的MPU(Memory Protection Unit),仅提供区域访问权限控制,不提供虚拟地址映射。而MPU(如ARM Cortex-A系列)通常指高性能处理器核心,需要外接DDR内存和存储芯片,运行完整的Linux或Android系统,依赖MMU(Memory Management Unit)实现进程间虚拟地址隔离。

从模糊测试的角度看,这一差异直接决定了测试策略的可行性。对于MCU目标,由于缺乏MMU,一个野指针或缓冲区溢出可能直接导致硬件故障(HardFault),系统表现为看门狗复位或死机,崩溃现场通常只能通过调试器(JTAG/SWD)或串口打印的异常信息获取。对于MPU目标,用户态进程的崩溃通常被内核捕获并生成core dump或日志,不会导致整个系统宕机,这使得自动化模糊测试的崩溃采集更加容易。此外,MCU的Flash和SRAM资源有限,固件通常为裸机程序或轻量级RTOS,而MPU则运行着复杂的Linux内核与用户空间程序,攻击面更大,但测试环境也更接近通用软件Fuzzing。

安全测试要点:在开始Fuzzing之前,务必确认目标芯片是否启用MPU/MMU。若MCU未启用MPU,则任何内存访问错误都可能造成不可预期的硬件行为,此时建议使用硬件调试器配合异常向量表分析崩溃原因;若MPU启用了MMU,则优先在用户态进行Fuzzing,利用操作系统的错误隔离机制提高测试效率。
对比维度MCU (如STM32F4)MPU (如i.MX6ULL)
内存保护可选MPU,无虚拟地址MMU,支持虚拟内存与进程隔离
存储介质内部Flash (KB~MB级)外部DDR (MB~GB级) + eMMC/NAND
操作系统裸机/RTOS (FreeRTOS, RT-Thread)Linux, Android, VxWorks
崩溃表现HardFault、看门狗复位Segmentation Fault、内核Oops
Fuzzing环境需硬件在环,依赖调试器可QEMU模拟或本机运行

2.2 判断方法与操作流程:识别外设接口与数据通道

外设接口是嵌入式系统与外界交互的物理层通道,也是模糊测试数据注入的主要入口。UART(通用异步收发器)是最常见的调试与通信接口,仅需TX/RX两根线,数据以帧格式传输,包含起始位、数据位、校验位和停止位。SPI(串行外设接口)为同步全双工通信,主设备提供时钟SCLK,通过CS片选选择从设备,数据在MOSI/MISO线上传输。I2C(集成电路总线)为半双工同步通信,仅需SDA(数据)和SCL(时钟)两根线,通过设备地址寻址,支持多主多从。CAN(控制器局域网)为差分异步通信,广泛应用于汽车和工业控制,具有优先级仲裁和错误检测机制。

在实际Fuzzing过程中,判断目标使用哪种接口,通常通过硬件原理图、PCB走线或固件逆向分析获得。操作流程上,首先通过逻辑分析仪或示波器捕获接口波形,确认协议类型与波特率/时钟频率。其次,使用USB转串口工具(如CP2102)连接UART,使用USB转CAN工具(如PCAN)连接CAN总线。对于SPI和I2C,通常需要MCU作为主设备主动发起通信,Fuzzing工具需要模拟从设备或通过调试接口直接注入数据。下表总结了常见接口的物理特征与测试接入方式。

接口信号线通信模式Fuzzing数据注入方式
UARTTX, RX, GND异步全双工直接连接串口工具,发送畸形字节流
SPISCLK, MOSI, MISO, CS同步全双工需模拟主设备或通过MCU固件转发
I2CSDA, SCL同步半双工使用USB转I2C适配器,构造地址与数据
CANCAN_H, CAN_L异步差分使用CAN卡发送错误帧或畸形数据帧

2.3 案例拆解:基于UART的Bootloader模糊测试实战

某IoT设备基于Cortex-M4 MCU,内置Bootloader支持通过UART升级固件。安全测试目标为验证Bootloader对固件头部的解析是否存在缓冲区溢出漏洞。初始现象是设备上电后等待0xAA55起始标志,随后接收长度字段和固件数据。测试环境搭建:使用USB转TTL模块连接目标板UART1,波特率115200,通过Python脚本构造随机数据包。

关键输入参数包括:起始标志(2字节)、固件长度(4字节,小端序)、CRC32校验值(4字节)以及固件数据(最大支持64KB)。分析判断过程:由于Bootloader通常运行在特权模式且无MPU保护,一旦解析函数发生溢出,很可能直接覆盖返回地址导致HardFault。实际操作步骤:首先编写Fuzzing脚本,固定起始标志和CRC值,随机化长度字段(从0到0xFFFF)和填充数据。其次,通过SWD调试器连接目标板,设置断点在固件解析函数的返回指令处。结果对比:当长度字段设置为0xFFFF时,设备立即触发HardFault,通过调试器查看PC指针被覆盖为0x41414141,确认存在栈溢出漏洞。

风险提示:对Bootloader进行Fuzzing可能导致设备变砖。务必在测试前备份原始固件,并准备SWD/JTAG接口用于恢复。此外,部分MCU具有读保护(RDP)机制,若触发保护将无法通过调试器读取Flash,需提前解除保护或使用RAM中运行的测试固件。

复盘经验:该漏洞源于固件头部长度字段未与实际缓冲区大小进行边界比较。修复方案为在memcpy前增加长度校验。此案例表明,针对MCU的Fuzzing不仅需要关注数据内容,还需结合硬件调试器实时监控CPU状态,才能准确捕获崩溃现场。

2.4 固件与操作系统基础:RTOS与Linux的模糊测试差异

固件是运行在嵌入式设备上的软件集合,对于MCU而言,固件通常直接包含启动代码、RTOS内核(如FreeRTOS)、设备驱动和应用逻辑。RTOS提供任务调度、信号量、消息队列等机制,但所有任务共享同一地址空间,一个任务的堆栈溢出可能破坏其他任务的数据。对于MPU而言,固件通常指Bootloader、Linux内核、设备树、根文件系统和应用程序。Linux内核提供完善的内存管理、进程隔离和驱动框架,使得Fuzzing可以在用户态进行,利用ASAN(AddressSanitizer)等工具检测内存错误。

在模糊测试执行环境上,RTOS系统通常需要硬件在环(HIL)测试,因为其外设依赖性强且无虚拟化支持。而Linux系统可以借助QEMU等模拟器进行半虚拟化Fuzzing,或者直接在开发板上运行Fuzzing工具(如AFL++)。判断方法:查看固件镜像中是否包含Linux内核镜像(如uImage、zImage)或RTOS的可执行文件(如.axf、.elf)。操作流程上,对于RTOS,需将Fuzzing工具编译为裸机程序或利用JTAG注入测试用例;对于Linux,则优先在用户态编译目标程序并启用ASAN。

经验提醒:在Linux环境下进行嵌入式Fuzzing时,不要忽略设备驱动层。许多漏洞存在于内核驱动对ioctl或read/write处理中。可使用syzkaller等内核Fuzzer,但需配置好对应的硬件模拟或使用真实设备。对于RTOS,建议使用模拟器(如QEMU的STM32目标)先行验证Fuzzing逻辑,再迁移至真实硬件。

总结复盘:理解MCU与MPU的架构差异,是选择Fuzzing工具链和崩溃分析手段的前提。外设接口的物理特性决定了数据注入的带宽和同步方式,而固件与OS的类型则决定了测试的自动化程度和崩溃的可观测性。在实际项目中,建议先通过原理图与数据手册建立硬件抽象,再结合固件逆向确定具体的协议解析代码位置,最后针对性地设计模糊测试用例。