把Thumb落到通信协议状态机的触发条件、可观察状态和复查材料上,先判断问题从哪里收窄。
Thumb落地前要同时核对通信协议状态机的接收缓冲区与协议帧、失败路径和解析结果与应答帧。
Thumb用帧边界、状态机、CRC校验连接到通信协议状态机的调试、验证和交付动作。
在固件逆向工程中,面对 Cortex-M 系列处理器,首要挑战并非理解每条指令的语义,而是从杂乱的二进制数据中,准确识别出指令集边界与函数起始、结束位置。Cortex-M 处理器仅支持 Thumb/Thumb-2 指令集,这意味着传统的 ARM 模式(32位)指令在固件中不会出现,但 Thumb-2 的变长指令(16位与32位混合)却给反汇编器的同步带来了巨大困难。本节的核心目标,就是掌握如何利用 BL(Branch with Link)和 BX(Branch and Exchange)指令的固定编码模式,结合栈帧(Stack Frame)的典型建立与销毁序列,在反汇编工具中自动或半自动地标记出函数边界,为后续的固件逻辑分析奠定基础
函数边界推断的成败,直接决定了反汇编结果的可读性与分析效率。错误的边界会导致反汇编器“跑飞”,将数据误译为指令,产生大量无意义的示例片段。因此,优先识别 BL/BX 指令作为函数调用的“锚点”,是逆向工程中最可靠的第一性原理
在 Thumb/Thumb-2 指令集中,BL 指令用于实现函数调用,其编码格式固定为 11110xxxxxxxxxxx(高5位)加上 11x1xxxxxxxxxxxx(高5位),共32位。而 BX 指令(编码 010001110xxx0xxx)则常用于函数返回或间接跳转。在固件二进制中,这些指令的机器码模式具有极高的辨识度,是定位函数调用关系的“信标”
具体操作时,我们可以在反汇编器(如 Ghidra 或 IDA Pro)中,通过脚本或手动搜索这些固定模式。例如,在二进制文件中搜索 BL 指令的机器码序列,其目标地址由指令中的立即数计算得出。一旦找到 BL 指令,其目标地址几乎可以确定是一个函数的起始地址。同时,BX lr(编码 4770)是 Thumb 模式下最标准的函数返回指令,其出现位置通常标志着函数体的结束
在 Ghidra 中,使用 Search -> Program Text 搜索十六进制模式 F0 00 00 F8(一个典型的 BL 指令编码),可以快速定位所有函数调用点。随后,通过交叉引用(XRefs)功能,即可自动生成函数边界
仅依赖 BL/BX 指令推断函数边界,在遇到内联函数、中断向量表或尾调用(Tail Call)优化时,可能会产生遗漏或误判。此时,栈帧的建立与销毁序列成为第二重验证手段。Cortex-M 的 AAPCS(ARM Architecture Procedure Call Standard)规定了函数序言(Prologue)和尾声(Epilogue)的典型模式
典型的函数序言包含 PUSH {r4-r11, lr}(编码 E92D 4xxx 或 B4xx),用于保存非易失性寄存器和返回地址。而函数尾声则通常包含 POP {r4-r11, pc}(编码 E8BD 8xxx 或 BCxx),用于恢复寄存器并返回。通过识别这些连续的、具有固定模式的指令序列,可以精确地勾勒出函数体的范围,尤其是在 BL/BX 指令不明显的场景下(如函数被内联或通过函数指针调用)
| 检查项 | 标准 | 是否通过 |
|---|---|---|
| BL 指令目标地址 | 目标地址必须对齐到半字(2字节),且位于代码段内 | 未检查目标地址是否在有效内存范围内,导致将数据区误判为… |
| BX lr 指令 | 确认 4770 编码后紧跟的指令不是数据,而是下一个函… | 将 BX lr 后的数据(如字面量池)误认为函数体的一… |
| PUSH/POP 序列 | 检查序言中 PUSH {lr} 或 PUSH {r4,… | 忽略了中断服务函数中可能存在的特殊序言(如 MRS 指… |
| Thumb-2 32位指令对齐 | 确认反汇编器正确识别了 32 位 Thumb-2 指令… |
Thumb的下一步可以从风险倒推:哪个模块最可能让Thumb-2指令集识别失效,哪份函数边界推断最能证明问题已经被缩小。扩展时先锁定指标对照卡和Thumb-2指令集识别之间的关系,再决定补数据、补参数、补实验,还是重做通信协议状态机相关的接口或流程。这样留下的是可执行的项目判断,而不是“已经讲完”的总结,后续协作能据此继续开发或验收。本节留下的复查锚点是Thumb:Thumb-2指令集识别是否还能解释Thumb-2指令集识别,再用函数边界推断核对源码结构到项目成果的变化。第04节适合把Thumb-2指令集识别写成一条判断记录,标明触发条件、观察位置和结束标准。