嵌入式系统硬件基础:MCU/CPU架构、存储器映射与启动流程

做固件逆向分析,第一关就是搞懂硬件。你连芯片怎么启动、外设怎么访问都不知道,那分析起二进制来就像盲人摸象。我个人习惯,拿到一块新板子,第一件事不是看代码,而是翻芯片手册里的存储器映射图和启动流程。这章咱们就把这些基础打牢。

常见MCU/CPU架构:三足鼎立

目前嵌入式领域,你大概率会遇到这三种架构:ARM Cortex-M、RISC-V 和 Xtensa。它们各有各的脾气。

架构 典型代表 指令集特点 我的看法
ARM Cortex-M STM32、nRF52、GD32 Thumb/Thumb-2,变长指令 生态最成熟,资料最多,逆向工具链最全
RISC-V GD32V、CH32V、ESP32-C 基础整数指令集RV32I,模块化扩展 开源,指令规整,逆向起来反而清爽
Xtensa ESP32、ESP8266 可配置、可变长指令 乐鑫家的看家本领,指令编码有点绕

为什么说这个重要?你逆向的时候,第一眼就要识别出架构。ARM的向量表在0x00000000,RISC-V的复位向量在0x80000000附近,这都是硬线索。我在分析一个ESP32的固件时,一开始没注意它是Xtensa架构,用ARM的反汇编工具去拆,结果全是乱码。嗯,白忙活了两小时。

存储器映射与总线结构

说白了,MCU就是一块地址空间。从0x00000000到0xFFFFFFFF,每个地址要么是Flash,要么是SRAM,要么是外设寄存器。你想想看,CPU怎么知道去哪个地址取指令?全靠这个映射表。

典型Cortex-M3存储器映射(以STM32F1为例)

  • 0x00000000 - 0x000FFFFF:别名区/Flash映射,用于启动
  • 0x08000000 - 0x080FFFFF:主Flash,代码存放地
  • 0x20000000 - 0x2000FFFF:SRAM,栈和堆
  • 0x40000000 - 0x400FFFFF:外设总线,GPIO、UART、TIM等寄存器

这里有个坑。我曾经逆向一个固件,发现代码里直接写地址0x40021000,我当时就知道这是RCC寄存器。但如果你不熟悉映射,看到这种地址会一头雾水。所以,我建议你把常见MCU的映射表背下来,至少知道Flash、SRAM、外设的大致范围。

外设寄存器与MMIO

外设寄存器,就是通过内存地址来控制的硬件。你往某个地址写一个值,GPIO就输出高电平了。这就是MMIO(Memory-Mapped I/O)。

逆向分析时,你会频繁看到类似这样的代码:

// 假设这是从固件中反编译出来的伪代码
*(volatile uint32_t*)0x40010C00 |= (1 << 12);  // 设置GPIOB_ODR的第12位

看到0x40010C00,你要能反应过来:这是GPIOB的输出数据寄存器。怎么做到的?靠查手册。我习惯在IDA Pro或Ghidra里,把常见外设的基地址和寄存器偏移量做成注释,这样分析起来快很多。

我的小技巧:把芯片手册里的寄存器描述截图,或者做成表格,放在逆向工程的工作目录下。遇到MMIO访问,直接对照。省时省力。

启动流程与Bootloader

芯片上电后干了什么?这是逆向分析的起点。以Cortex-M为例,启动流程非常固定:

  1. 从0x00000000读取栈顶指针(MSP)
  2. 从0x00000004读取复位向量,跳转执行
  3. 执行SystemInit,配置时钟
  4. 跳转到main

RISC-V稍有不同。它从复位向量地址(通常是0x80000000)开始执行,没有向量表的概念,异常处理用mtvec寄存器指定。

Bootloader就更关键了。很多设备都有两级启动:一级Bootloader(固化在ROM里)负责检测启动条件,二级Bootloader(存在Flash里)负责加载固件或进入升级模式。

避坑指南:我曾经逆向一个IOT设备,发现固件里有一段代码在0x1FFF0000附近执行。我一开始以为是用户代码,后来才意识到这是芯片内部的系统Bootloader。差点把系统固件当成应用固件来分析。所以,一定要区分清楚哪些是芯片自带的,哪些是用户写的。

知识结构图:嵌入式硬件基础全景

下面这张图,把本章的核心知识点串起来了。你可以把它当作一个快速索引。

嵌入式硬件基础全景图 嵌入式硬件基础 MCU/CPU架构 ARM Cortex-M RISC-V Xtensa 存储器映射 Flash SRAM 外设总线 外设寄存器与MMIO GPIO UART TIM 启动流程与Bootloader 一级Bootloader 二级Bootloader 应用固件 提示:逆向分析时,先确定架构,再定位存储器映射,最后分析启动流程。这是标准套路。

小结

这一章的内容,说白了就是嵌入式硬件的“世界观”。你知道了芯片怎么划分地址空间,外设怎么控制,系统怎么启动,后面分析固件时才能有的放矢。别小看这些基础,我见过太多人上来就反汇编,结果连代码在Flash还是SRAM里都分不清,那分析出来的东西能准吗?