ARM Cortex-M 架构基础:寄存器模型、指令集与异常处理
搞嵌入式固件逆向,ARM Cortex-M 是绕不开的坎。我见过太多人一上来就盯着二进制数据猛看,结果连寄存器怎么用都搞不清楚。说白了,不了解处理器架构,逆向就是瞎蒙。这一章,咱们把 Cortex-M 的底裤扒干净。
寄存器模型:逆向工程师的“眼睛”
Cortex-M 的寄存器组,是你分析固件行为的第一手资料。我个人习惯,拿到一个固件样本,先看它用了哪些寄存器,基本就能猜出代码在干什么。
通用寄存器 R0-R12:这些是干活的主力。R0-R3 通常传参数,R4-R11 是局部变量。我在逆向一个 IoT 设备时,发现它大量使用 R4-R7 保存敏感数据,这明显是开发者想避免栈溢出被利用——嗯,有点意思。
堆栈指针 SP (R13):分 MSP 和 PSP。MSP 是主栈,处理异常时用;PSP 是进程栈,跑普通任务时用。调试时看到 SP 突然跳到奇怪地址,十有八九是栈溢出了。
链接寄存器 LR (R14):保存函数返回地址。逆向时,LR 的值能告诉你调用链。我曾经靠 LR 里的地址,追出一个隐藏的后门函数——那家伙藏得真深。
程序计数器 PC (R15):当前执行地址。这个不用多说,断点、单步全靠它。
特殊寄存器:xPSR(程序状态寄存器)、PRIMASK(中断屏蔽)、FAULTMASK(故障屏蔽)、BASEPRI(优先级屏蔽)。这些在安全分析时特别关键——攻击者经常通过篡改它们来绕过保护。
寄存器速查表(逆向必备)
| 寄存器 | 别名 | 逆向用途 |
|---|---|---|
| R0-R3 | 参数寄存器 | 看函数调用参数 |
| R4-R11 | 局部变量 | 分析函数内部状态 |
| R13 | SP | 判断栈使用情况 |
| R14 | LR | 追踪调用链 |
| R15 | PC | 定位执行流 |
| xPSR | 状态寄存器 | 看条件标志、中断状态 |
指令集概览:Thumb/Thumb-2 的“方言”
Cortex-M 只支持 Thumb 和 Thumb-2 指令集。你想想看,一个 32 位处理器,指令却是 16 位和 32 位混着来——这给逆向增加了不少乐趣。
Thumb 指令(16 位):短小精悍,代码密度高。常见的有 MOV、ADD、SUB、LDR、STR、B、BL 等。逆向时看到 16 位指令,基本就是 Thumb 模式。
Thumb-2 指令(32 位):Thumb 的扩展,能执行更复杂的操作。比如带立即数的 LDR、带偏移的 STR、条件分支等。Thumb-2 让 Cortex-M 既能保持代码密度,又能有接近 ARM 指令的性能。
常见指令模式:
- 数据处理:MOV、ADD、SUB、AND、ORR、EOR、LSL、LSR——这些是算术逻辑运算,逆向时看它们能猜出算法。
- 内存访问:LDR(加载)、STR(存储)、LDM(批量加载)、STM(批量存储)——这些是数据搬运,分析数据流的关键。
- 分支跳转:B(无条件跳转)、BL(带链接跳转)、BX(跳转并切换模式)、BLX(带链接跳转并切换模式)——这些是控制流,逆向时重点关注。
- 其他:SVC(系统调用)、BKPT(断点)、WFI(等待中断)——这些是特殊操作,安全分析时经常遇到。
避坑指南:我曾经在逆向一个固件时,发现反汇编出来的指令全是 32 位的,但处理器却跑在 Thumb 模式。后来才发现,那个固件用了 Thumb-2 的 32 位指令,但反汇编器默认只识别 16 位。所以,一定要确认反汇编器支持 Thumb-2。
异常处理与中断向量表:固件的“命门”
异常处理是 Cortex-M 的强项,也是逆向分析的重点。攻击者经常通过篡改中断向量表来劫持控制流——你想想看,如果能把一个中断向量指向恶意代码,那系统就彻底沦陷了。
异常类型:
- 系统异常:复位、NMI、硬故障、内存管理、总线故障、用法故障、SVCall、PendSV、SysTick——这些是内核自带的,优先级固定。
- 外部中断:IRQ0-IRQn——这些是外设触发的,优先级可配置。
中断向量表:这是异常处理的核心。它是一张表,每个条目对应一个异常处理函数的地址。向量表通常放在固件的起始地址(0x00000000 或 0x08000000)。
向量表结构:
| 偏移 | 内容 | 说明 |
|---|---|---|
| 0x00 | 初始 SP 值 | 复位后栈指针 |
| 0x04 | 复位向量 | 复位后第一条指令地址 |
| 0x08 | NMI 向量 | 不可屏蔽中断处理 |
| 0x0C | 硬故障向量 | 硬故障处理 |
| 0x10-0x3C | 其他系统异常 | 内存管理、总线故障等 |
| 0x40+ | 外部中断向量 | IRQ0-IRQn |
异常处理流程:
- 异常发生,处理器自动压栈(xPSR、PC、LR、R12、R3-R0)。
- 从向量表取出对应处理函数地址。
- 跳转到处理函数执行。
- 处理函数执行完,执行异常返回指令(BX LR 或 POP {PC})。
- 处理器自动出栈,恢复现场。
安全警示:逆向时,一定要检查向量表是否被篡改。我曾经遇到一个固件,它的复位向量被改成了一个 shellcode 地址——攻击者通过一个缓冲区溢出漏洞,把恶意代码写到了向量表区域。所以,向量表保护是安全防护的第一道防线。
知识体系图:Cortex-M 逆向核心
下面这张图,把 Cortex-M 逆向的核心知识点串起来了。你对照着看,心里就有谱了。
嗯,这一章的内容就到这儿。寄存器、指令集、异常处理——这三样东西,是逆向 Cortex-M 固件的三把钥匙。你把这章吃透了,后面分析签名绕过、调试漏洞的时候,心里就有底了。