0x00 前言
大家好, 我是来自银基 Tiger-Team 的 KEVIN2600. 今天想跟大家分享如何使用 Ghidra对ARM固件进行逆向破解的有趣案例. 希望通过本文能够让大家对嵌入式系统固件逆向有更多的了解.
0x01 Ghidra探索之旅
Ghidra是一款由美国NSA发布的功能强大且开源的逆向分析工具. 用户能够在多种平台上分析编译后的代码. 功能包括反汇编,汇编,反编译,绘图和脚本等. Ghidra支持多种处理器指令集和可执行格式. 可以在用户交互模式和自动模式下运行. 用户还可以使用公开的API开发自己的Ghidra插件和脚本.
让我们先热个身来看一道CTF送分题吧. 题目要求很简单, 只要输入正确的Password便可以得到 Flag
通过file指令我们可以了解其为ELF格式, 并且没有stripped. 这对我们的逆向工作非常有利.
我们可以将其导入Ghidra. 并通过 Ghidra的反编译功能, 将其变为容易理解的代码
当然我们还可以对反编译后的代码, 进行少许优化使其可读性更高
通过分析代码我们可以很容易发现正确的密码, 是一组长度为10, 且第5 位为 “@” 的任意字符串. 最后通过验证, 成功拿到Flag.
0x02 Bare-Metal ARM固件分析
在热身后, 我们步入此次的主要目标 Bare-Metal 固件分析. 首先我们先要了解下什么是Bare-Metal. 简单来说就是通指那些没有OS, 程序直接运行在硬件设备上的嵌入式产品. 这类产品覆盖了我们生活的方方面面. 在IOT智能设备领域尤为突出, 比如我们常见的智能手环或硬件钱包等.
目前主流的微处理器架构有几十种, 而其中ARM 系列是最常见的之一. 事实上90%的手机处理器都采用了ARM 架构. 同时ARM 家族子架构众多, 根据不同的运用场景, 衍生出Cortex A; Cortex M 和 Cortex R 这3种架构.
其中Cortex A 的A 为 Application, 是高性能旗舰产品的代表, 几乎所有的手机;平板电脑都使用了这种架构. 而Cortex R 的 R 代表 RTOS, 即为实时操作系统. 这在汽车应用中比较常见, 例如安全气囊;发动机系统等. 最后 Cortex M 中的M 是指MCU. 身为32位的处理器, 其特点是高性能低功耗. 该系列的代表产品即为ST公司的STM32系列.
想要对某款芯片进行固件逆向, 需要对其架构特性有所了解. 虽说每款芯片的FLASH; RAM, 以及引脚的定义都不尽相同. 但整体架构是相同的. 通常我们可以在厂商的官网上找到Datasheet. 比如本文的测试目标STM32F446芯片系列, 内核也是ARM 架构的一种.
在Datasheet 中我们可以找到STM32F446的引脚定义图. 方便我们了解每根引脚的位置及功能. 在硬件CTF 比赛中这个是极为重要的信息.
同样内存映射图可以获得固件的加载位置. 以及每个外设的内存地址范围.
首先FLASH Memory 的内存范围是0x08000000-0x081FFFFF, 这样我们就知道了正确的加载位置. 其次是内存SRAM 从0X20000000 开始, 程序动态执行的部分会存在该部分. 还有就是外设的寄存地址 0x40000000.
我们还可以从datasheet了解到芯片各个寄存器的地址及功能.
0x03 SVD-Loader自动化脚本
在对Bare-Metal 固件进行逆向时, 我们需要花费大量时间来注释内存映射的外设, 以便了解代码如何与芯片功能交互. 但手工创建这些外设映射表是一项艰巨的工作. 读取数据表并创建所有不同的存储器区结构和存储器寄存器将花费很长时间. 因此各大芯片厂商提供了CMSIS系统描述文(CMSIS-SVD). 其规范了微控制器中包含的系统的描述, 特别是外设的内存映射寄存器表.
德国黑客Thomas Roth 发布了针对Ghidra开发的 SVD-Loader 自动化脚本. 通过解析SVD文件, 自动为650多种不同的微控制器自动生成完整的外设结构和存储器映射表. SVD能够自动注释控制器的所有外设, 从而大大简化了ARM固件的逆向过程. 如下图当导入SVD-Loader后, 例如_DAT_40000200自动变成易于阅读和读写的结构.
0x04 Nucleo-64 CTF实战
这里我们用ST公司的Nucleo-64开发板, 做一道Thomas Roth提供的硬件CTF题, 来体验下SVD-Loader 脚本的威力. 此开发板采用 ARM Cortex M4 Core, 以及 512Kb的Flash memory 和128Kb 的SRAM.
这道硬件CTF 题从屏幕上可以得知, 需要我们在按下按钮的同时, 输入正确的电子信号才能得到Flag. 那么正确信号的输入方式, 只能从逆向固件得知了.
首先我们将目标固件导入Ghidra, 并根据datasheet输入Flash 和 RAM 的地址
导入成功后可以在 Memory Map 中确认地址信息是否有误
一切准备就绪后就可以点击分析固件, 分析完成后我们可以根据defined strings 找到反编译后的目标代码段.
当然这个时候的代码还需要翻看Datasheet, 才能得知其具体功能
所以我们需要请出SVD-loader 脚本, 并选中正确的SVD芯片型号.
运行之后再次检查memory map 表, 发现已经自动添加存储器映射地址.
外设GPIO 也自动修改好了. 大大减少了我们查找芯片手册的时间. 在进一步优化和将数值转换为二进制格式后得到最后可读性很高的代码.
在分析代码后, 我们很容易得知想要跳出循环. 需在按下按钮的同时, 满足GPIOC的 PIN 3 和 PIN 1 的值为HIGH. 这里我们可以通过面包板连通PIN3; PIN1 和 VDD 口从而达到目的.
最后我们得到flag为 Kevin2600 Love You
0x05 结语
ARM体系架构由来已久, 为嵌入式行业所青睐. 随着近年来IOT及车联网设备的兴起, 嵌入式系统安全成为安全研究人员必须关注的领域. 本文只是起到一个抛砖引玉的作用, 为想要学习硬件逆向的小伙伴们提供些许思路. 最后向Thomas Roth在研究过程提供帮助表示感谢. 大家可以关注他的硬件培训课程和视频 (地址在参考文献中). 同时推荐来自平安银河实验室朱文哲的课程 ”逆向工具Ghidra介绍及应用”. 其中包含了使用Ghidra分析VxWorks固件等硬核内容. 感兴趣的朋友可自行围观. 让我们一起向这些业界的开拓者们学习与致敬.
0x06参考文献
https://leveldown.de/blog/svd-loader
https://www.youtube.com/watch?v=q4CxE5P6RUE
https://www.ghidra-sre.org/releaseNotes_9.1.2.html
https://github.com/leveldown-security/SVD-Loader-Ghidra
https://advancedsecurity.training/training/live-hardware-intro
www.st.com/en/microcontrollers-microprocessors/stm32f446re.html