← 返回目录课程:《嵌入式固件Bootloader逆向分析专题课程》
02

02 STM32L4 Bootloader向量表重映射与读保护绕过

分析RDP等级切换逻辑,实操Option Bytes修改绕过读保护
章节导航 难度:入门类型:排障定位
本页抓手

把STM32L4 Bootloader向量表重映射与读保护落到Bootloader升级链路的触发条件、可观察状态和复查材料上,先判断问题从哪里收窄。

判断线索
接口配置流程状态日志
复用位置
代码片段排障表检查清单架构图

查看现场信号与复查材料

  1. 核对Bootloader升级链路的输入条件、变化信号和结果材料
  2. 再把命令、配置、日志和状态结果对应到同一个操作结果
  3. 最后用启动成功率验证结果是否可复现

代码阅读线索

STM32L4 Bootloader向量表重映射与读保护涉及源码、函数、脚本或 API 时,应先确认代码对象、调用条件和结果信号是否对应。

本节用Bootloader升级链路的真实调用点说明代码变化会影响哪一个操作结果。

向量表重映射与RDP等级:读保护绕过的工程基础

Bootloader向量表重映射STM32L4中心对象与关键关系01⭐向量表重映射与RD明确检查要点02🧭RDP等级切换逻辑明确检查要点03⭐STM32L4的技明确检查要点04对象边界先定义适用范围05触发条件确认起点与约束06处理步骤按顺序完成操作

STM32L4 Bootloader向量表重映射与读保护架构示意

Boot ROM
→
Bootloader
→
App分区
→
回滚记录

Bootloader升级链路的验收口径

在嵌入式固件逆向分析中,Bootloader向量表重映射(Vector Table Relocation)与读保护(Read Protection, RDP)是绕过硬保护机制的两道核心关卡。以STM32L4系列为例,其系统存储器(System Memory)中驻留的出厂Bootloader通过VTOR(Vector Table Offset Register)寄存器定义中断向量表的位置。当芯片上电或复位后,内核首先从0x00000000地址获取堆栈指针(MSP),再从0x00000004获取复位向量,而这一映射关系由硬件决定。但在实际工程中,Bootloader需要将向量表重映射到用户Flash起始地址(如0x08000000),以接管中断响应。这一机制既是安全启动链的基石,也是逆向工程师寻找绕过路径的切入点

读保护等级(RDP Level)是STM32L4提供的三级保护机制:Level 0(无保护)、Level 1(禁止通过调试接口读取Flash)、Level 2(永久禁止调试,且无法回退)。RDP等级存储在Option Bytes(选项字节)的RDP字段中,位于系统存储器的特定区域。逆向分析的核心目标之一,就是通过修改Option Bytes来绕过Level 1保护,从而读取受保护的固件。然而,直接修改Option Bytes并非易事——芯片硬件会检测RDP等级切换的合法性,并在Level 1向Level 0回退时触发全片擦除(Mass Erase),导致固件丢失。因此,理解RDP等级切换逻辑与Option Bytes的编程时序,是绕过读保护的关键前提

关键判断

RDP Level 1向Level 0回退时,STM32L4硬件强制执行全片擦除,这是保护固件不被直接读取的最后防线。绕过策略必须在此约束下寻找漏洞,而非试图阻止擦除

RDP等级切换逻辑与Option Bytes修改路径

RDP等级的切换通过修改Option Bytes中的RDP字段实现,但硬件控制器(Option Byte Loader)会校验切换序列的合法性。具体而言,当系统检测到RDP值从0xAA(Level 1)变为0xBB(Level 0)时,会触发以下工序:

  1. 触发条件:通过FLASH_OPTKEYR寄存器写入正确的密钥序列(0x08192A3B和0x4C5D6E7F)解锁Option Bytes编程
  2. 关键检查点:硬件在写入新RDP值前,会检查当前RDP等级。若当前为Level 1且目标为Level 0,则设置内部擦除标志
  3. 判定条件:擦除操作在Option Bytes编程完成后立即执行,且不可中断。若此时芯片意外掉电,下次上电时仍会执行擦除

工程实践中,逆向工程师常通过Bootloader命令注入(如利用command_check函数的漏洞)来绕过这一检查。例如,某些STM32L4的出厂Bootloader在解析自定义命令时,未充分验证命令长度或参数范围,导致攻击者可以构造恶意数据包直接写入Option Bytes,绕过RDP等级切换的硬件擦除逻辑。以下是一个典型的命令注入攻击流程:

// 示例片段:利用Bootloader command_check漏洞修改Option Bytes
uint8_t cmd_buffer[64];
uint32_t option_addr = 0x1FFF7800; // STM32L4 Option Bytes基址
uint8_t payload[] = {0xBB, 0x00, 0x00, 0x00}; // 目标RDP值(Level 0)
// 构造恶意命令:将RDP字段直接写入Option Bytes区域
cmd_buffer[0] = 0x73; // 自定义写命令标识
cmd_buffer[1] = 0x02; // 命令长度
memcpy(&cmd_buffer[2], &option_addr, 4);
memcpy(&cmd_buffer[6], payload, 4);
// 发送命令至Bootloader
if (command_check(cmd_buffer) == VALID) {
    execute_write(cmd_buffer); // 直接写入Option Bytes,绕过RDP检查
}

这段配置属于“问题代码/原始配置”,核对键名、默认值、取值范围和修改后影响的行为。

上述代码展示了如何利用command_check函数的校验缺陷,直接向Option Bytes区域写入0xBB(Level 0)。成功执行后,芯片的RDP等级将降为Level 0,且不会触发全片擦除——因为硬件擦除逻辑仅在RDP字段通过合法编程接口修改时触发,而此处通过Bootloader命令直接写入,绕过了Option Byte Loader的检查

实操步骤

在逆向分析时,优先定位Bootloader中处理Option Bytes写入的command_check函数。通过模糊测试(Fuzzing)构造异常命令长度或非法地址,观察芯片是否返回错误码或直接执行写入,这是发现绕过路径的高效手段

STM32L4的技术资产与验证方式

为了系统化验证RDP绕过方法,以下提供一套可复用的检查清单,用于评估目标芯片的读保护状态与Bootloader漏洞可利用性:

Bootloader向量表重映射 相关检查
检查项标准是否通过常见遗漏
当前RDP等级读取通过 FLASH_OPTR 寄存器读取 RDP 字段,…是/否未区分Level 1与Level 2(Level 2不…
Bootloader命令接口暴露通过UART/I2C/SPI发送 0x00 (Get命…是/否未检查命令长度边界(如发送超长命令导致缓冲区溢出)
command_check函数定位在固件二进制中搜索 0x73 (写命令标识)或 0x0…是/否未考虑命令标识被混淆或加密的情况
Option Bytes写入验证尝试写入非关键Option Byte(如 BOR_LE…是/否未先解锁Option Bytes编程(需写入 FLAS…

在验证过程中,记录以下关键参数:

真实项目场景

某工业控制器采用STM32L4作为主控,固件通过Bootloader升级。逆向团队发现,Bootloader的command_check函数在处理写命令时,未验证目标地址是否位于Option Bytes区域。通过构造0x73命令写入0x1FFF7800地址的RDP字段,成功将Level 1降为Level 0,且未触发全片擦除。随后通过SWD接口直接读取完整固件,提取出加密算法与通信协议

条件复核

理解STM32L4 Bootloader向量表重映射与读保护时,先分清Bootloader向量表重映射在机制里承担的角色,再看STM32L4怎样改变状态或输出。如果只记名称,很容易在新场景里把边界混淆;更稳的做法是用读保护绕过说明当前结论依赖哪些前提。后续遇到类似问题时,可以先复查分析RDP等级切换逻辑是否仍成立,再判断本节方法是直接复用、局部调整,还是降级为现象记录。遇到相邻章节结论冲突时,不直接替换答案,先对照STM32L4 Bootloader向量表重映射与读保护与概念联动,再确认Bootloader向量表重映射记录的是原因、过程还是结果。第02节的复盘出口是读保护绕过,它要能说明STM32L4 Bootloader向量表重映射与读保护、Bootloader向量表重映射和概念联动之间哪一项先发生变化。