一般先决条件
在分析二进制文件时,重要的是能够将观察到的内容置于上下文中。例如,如何区分CPU指令和非标准格式的二进制数据?这通常需要一些计算机系统的背景知识。我认为在进行任何逆向工程固件尝试之前,至少需要基本熟悉以下概念:
计算机体系结构/计算机系统组织
- CPU 设计和功能(例如寄存器、指令指针、内存访问)
- 内存和内存层次结构
- 指令集、汇编、操作码、寻址模式、语法、助记符
- 信息表示(二进制、十六进制、字节序)
操作系统概念
- 虚拟内存
- usermode vs kernelmode,内核,内核接口(系统调用)
- 内存中的进程布局 - 堆栈、堆、数据、指令
- 可执行格式
- 应用程序二进制接口
- 程序入口点
源代码到目标代码的转换
- 编译、组装、链接
- C/C++ 编程
- 汇编编程
- 源到程序集结构的相关性(例如循环识别、程序集中的开关结构)
- 反汇编与反编译
我的建议如下:
- 尽可能多地阅读:技术规范、组装/拆卸、固件 RE 问题的答案、研究论文、教程、博客、教科书、手册页
- 模仿/复制专业人士采用的方法和方法
- 尽快获得经验:查看并试验许多不同类型的文件(可执行文件、图像文件、压缩文件、固件等),汇编程序以了解它,反汇编许多可执行文件
固件 RE 资源
“介绍嵌入式逆向工程PC反向”伊戈尔Skochinsky提供了什么是参与倒车固件的概述,并在“嵌入式设备安全:固件逆向工程”乔纳斯Zaddach和安德烈海东青勾勒的一般方法逆转固件开始幻灯片31.
看看专业人士给出的答案:
这些可能有用或有趣:
devttys0 的博客
ea的博客
伊戈尔的博客
固件.re
IOActive 实验室研究博客
sviehb 的博客
嵌入式系统通常使用 MIPS 或 ARM 处理器,并通过扩展使用 MIPS 或 ARM 指令集。这意味着在分析这些系统的固件时,熟悉 MIPS 和 ARM 汇编将非常有帮助。
分析二进制
第 1 部分:识别目标设备的架构
我们不能依靠道听途说来获取分析固件所需的信息。必须使用经验证据来证明固件信息的有效性。拥有来自二手源的二进制 blob 和来自不同问题的处理器名称是不够的。
1. 识别目标设备
幸运的是,在这种情况下,至少很容易获得设备名称:SMOK X Cube II。当检查供应商的固件和工具支持页面时,结果是存在具有该名称的真实设备。.hex 文件与台湾半导体制造商 Nuvoton的升级工具捆绑在一起,称为“ NuMicro ISP Programming Tool ”:
~/firmware/e-cig/XCUBE II upgrading tool $ file *
config.ini: ASCII text, with CRLF line terminators
NuMicro ISP Programming Tool.exe: PE32 executable (GUI) Intel 80386, for MS Windows
NuMicro ISP Programming Tool User's Guide.pdf: PDF document, version 1.5
XCUBE II-VIVI-52 (160616)V.1.098(checksum=0x28F9).hex: ASCII text, with CRLF line terminators
这个 hex 文件直接来自设备处理器的制造商,而不是来自二手来源。它也是一个较新的版本 - v1.098 而不是 v1.07。我决定分析旧固件版本 (v1.07),因为这是问题中二进制文件的版本。
2. 识别处理器
用于描述升级过程的图片中有一些有趣的东西:名称NuMicro和工具名称中的首字母缩略词ISP,术语DataFlash,对称为APROM 的东西的引用,以及最重要的部件号:NUC220LE3AN。这个数字是什么“部分”?Nuvoton基于 ARM 的 Cortex-M0 处理器开发的微控制器。
3. 识别指令集架构
Nuvoton 很友好地免费分享 NuMicro NUC220 系列的技术文档,包括数据表和技术参考手册,以及各种软件工具和培训材料(点击 NUC220LE3AN 产品页面顶部的“资源”选项卡)。
来自数据表的第 1 节:“一般说明”,第 7 页(强调我的):
NuMicro NUC200 系列32 位微控制器嵌入了最新的 ARM® Cortex™-M0 内核,其成本与传统 8 位 MCU 相当,适用于需要丰富通信接口的工业控制和应用。NuMicro NUC200 系列包括 NUC200 和 NUC220 产品线。
这些信息足以断定固件二进制文件中的代码由 32 位 ARM 指令组成吗?不,它不是。让我们仔细看看处理器的功能描述(第 6 章:功能描述,第 1 节:ARM Cortex-M0 内核,第 48 页):
让我们特别注意以下信息:
该处理器可以执行 Thumb 代码并与其他 Cortex®-M 配置文件处理器兼容。
ARMv6-M Thumb® 指令集
Thumb-2 技术
请注意,处理器是 ARM Cortex-M0 内核而不是 ARM Cortex-M0+ 内核,后者具有不同的指令集。
来自 ARM 的Cortex-M0 技术参考手册:
该处理器实现了 ARMv6-M Thumb 指令集,包括许多使用 Thumb-2 技术的 32 位指令。ARMv6-M 指令集包括:
什么是“Thumb 代码”和“Thumb 指令集”?
来自Joe Lemieux 的“ ARM 拇指介绍”(重点是我的):
Thumb 指令集由16 位指令组成,这些指令充当标准 ARM 的 32 位指令子集的紧凑速记。每条 Thumb 指令都可以通过等效的 32 位 ARM 指令执行。但是,并非所有 ARM 指令都在 Thumb 子集中可用;例如,无法访问状态或协处理器寄存器。此外,一些可以在单个 ARM 指令中完成的功能只能用一系列 Thumb 指令来模拟。
说到这里,你可能会问为什么在同一个 CPU 中有两个指令集?但实际上 ARM 只包含一个指令集:32 位指令集。当它在 Thumb 状态下运行时,处理器只是将从内存中提取的较小的速记指令扩展为它们的 32 位等效指令。
两个等效指令之间的区别在于指令在执行之前如何获取和解释,而不是它们如何运行。由于从 16 位指令扩展到 32 位指令是通过芯片内的专用硬件来完成的,因此它的执行速度不会有丝毫减慢。但是更窄的 16 位指令确实提供了内存优势。
Thumb 指令集提供了典型应用所需的大部分功能。支持算术和逻辑运算、加载/存储数据移动以及条件和无条件分支。根据可用的指令集,任何用 C 编写的代码都可以在 Thumb 状态下成功执行。但是,设备驱动程序和异常处理程序通常必须至少部分以 ARM 状态编写。
这是来自 SO 的一个很好的解释:ARM、Thumb 和 Thumb 2 指令混淆
来自ARMv6-M 体系结构参考手册,第 A5 章:Thumb 指令集编码,第 1 节:Thumb 指令集编码,第 82 页:
此外:
NuMicro NUC200 系列仅支持 little-endian 数据格式。
总而言之:固件二进制文件中的代码将由小端 16 位 ARM Thumb 指令和一些 32 位 Thumb2 指令组成,这些指令由实现 ARM 16 位 Thumb 指令的 32 位 ARM Cortex-M0 处理器执行设置支持 Thumb2。
4. 识别设备的内存布局
访问技术参考手册使我们能够确定 APROM 和 ISP 是什么。来自第 6 章:功能描述,第 4.4.1 节:闪存组织,第 191 页:
NuMicro NUC200 系列闪存由程序存储器 (APROM)、数据闪存、ISP 加载程序存储器 (LDROM) 和用户配置组成。程序存储器是用户应用程序的主存储器,称为 APROM。用户可以将他们的应用程序写入 APROM 并将系统设置为从 APROM 启动。
ISP 加载器程序存储器是为加载器实现在系统编程功能而设计的。LDROM 独立于 APROM,系统也可以设置为从 LDROM 启动。因此,用户可以使用LDROM 来避免APROM 代码损坏时系统启动失败。
从第 6 章:功能描述,第 4.4.5 节:在系统编程 (ISP),第 199 页:
ISP 提供更新板载系统固件的能力。丰富的外设接口让 LDROM 中的 ISP loader 轻松接收新的程序代码。执行 ISP 的最常用方法是通过 UART 以及 LDROM 中的 ISP 加载程序。一般来说,PC通过串口传输新的APROM代码。然后ISP加载器接收它并通过ISP命令重新编程到APROM中。
根据config.ini
NuMicro ISP Programming Tool 捆绑文件中的信息,APROM 段的闪存大小为 128 KB:
$ cat config.ini | grep NUC200LE3AN -B2 -A3
[0x00020000]
NAME_STRING = NUC200LE3AN
RAM_SIZE = 16
FLASH_SIZE = 128
下面是闪存地址映射图:
我们知道0x0000_0000到0x0001_FFFF的空间=131071字节,也就是128KB,这是使用升级工具将hex文件中的二进制文件烧写到的区域。在其上方有一个从 0x0002_0000 到 0x0010_000 的内存块,它被标记为“保留供进一步使用”。此“保留”空间的大小为 0x0010_0000 - 0x0002_0000 = 0xE0000,或 917504 字节。这几乎是 1 兆字节的保留空间。为 APROM 保留的 128 KB 占 0x0000_0000 和 0x0010_0000 之间地址空间的 12.5%,但表示为大于约 1 MB 的“保留”块。这很奇怪。在我能找到的技术参考手册中的任何地方也没有关于这个保留块的文档。如果有人可以物理访问该设备,
由于固件二进制文件被写入为用户应用程序保留的闪存空间,固件二进制文件似乎不太可能包含内核代码、引导加载程序代码或文件系统。这与路由器固件不同,后者往往至少包含内核代码。
第 2 部分:二进制文件的直接分析
快速回顾一下我们目前所知道的:
- 设备名称 - SMOK X Cube II
- 处理器 - NuMicro NUC220LE3AN 处理器,基于 ARM Cortex-M0 Core 处理器
- 指令集架构 - little-endian ARM-v6 M 16-bit Thumb
- 固件将写入闪存中的位置 - 用户应用程序的 128KB APROM 区域(换句话说,不是内核)
- NuMicro 是一家台湾公司。我们将很快看到为什么这可能具有相关性。
binwalk
问题中包含的生成的熵图表明固件中没有加密或压缩区域
- 根据问题中包含的信息,文件中存在嵌入的 ASCII 字符串,这些字符串似乎与设备的功能有关
潜在的并发症:
- 固件二进制文件没有像可执行二进制文件那样的标准格式
- 数据可能与二进制文件中的代码/指令混合。如果是这种情况,则字符串等数据可能会被反汇编为指令,从而导致固件代码的表示不正确
初步分析
1.strings
和hexdump
字符串的输出可用于快速启发式地确定固件是否已加密/压缩。如果输出中没有字符串,则表明整个文件以某种方式被混淆了。hexdump
带有 -C 参数的参数可用于为字符串提供一些上下文,即它们在二进制文件中的位置与代码和彼此相关。换句话说,字符串是打包在一个块中,还是分散在整个二进制文件中?答案可以提供有关固件布局的线索。
使用hexump
,我们看到 ASCII 字符串与可能是代码的东西混合在一起:
00002ed0 01 21 1b 20 fd f7 6e fe 21 46 38 6a 09 f0 16 fd |.!. ..n.!F8j....|
00002ee0 64 21 09 f0 13 fd 08 46 0a 21 09 f0 0f fd 10 30 |d!.....F.!.....0|
00002ef0 14 21 48 43 42 19 01 21 25 20 fd f7 5b fe 73 e0 |.!HCB..!% ..[.s.|
00002f00 68 e2 88 e0 57 41 54 54 0a 00 00 00 4d 4f 44 45 |h...WATT....MODE|
00002f10 0a 00 00 00 7c db 00 00 88 db 00 00 54 45 4d 50 |....|.......TEMP|
00002f20 0a 00 00 00 4d 45 4d 4f 52 59 0a 00 20 4d 4f 44 |....MEMORY.. MOD|
00002f30 45 20 0a 00 ac 01 00 20 53 54 52 45 4e 47 54 48 |E ..... STRENGTH|
00002f40 0a 00 00 00 3c 0b 00 20 20 4d 49 4e 20 0a 00 00 |....<.. MIN ...|
00002f50 53 4f 46 54 0a 00 00 00 4e 4f 52 4d 0a 00 00 00 |SOFT....NORM....|
00002f60 48 41 52 44 0a 00 00 00 20 4d 41 58 20 0a 00 00 |HARD.... MAX ...|
00002f70 ea cf 00 00 42 4c 55 45 54 4f 4f 54 48 0a 00 00 |....BLUETOOTH...|
00002f80 20 20 20 4f 4e 20 20 20 20 0a 00 00 20 20 20 4f | ON ... O|
00002f90 46 46 20 20 20 0a 00 00 ea d0 00 00 20 20 20 4c |FF ....... L|
00002fa0 45 44 20 20 20 0a 00 00 6a d1 00 00 53 54 45 41 |ED ...j...STEA|
00002fb0 4c 54 48 0a 00 00 00 00 20 4f 46 46 20 20 0a 00 |LTH..... OFF ..|
00002fc0 20 20 4f 4e 20 20 0a 00 20 20 54 4f 44 41 59 20 | ON .. TODAY |
00002fd0 20 0a 00 00 80 96 98 00 f6 e1 00 00 83 e5 00 00 | ...............|
00002fe0 a0 86 01 00 10 27 00 00 21 46 38 6a 09 f0 8e fc |.....'..!F8j....|
00002ff0 0a 21 09 f0 8b fc 10 31 14 20 41 43 4a 19 01 21 |.!.....1. ACJ..!|
二进制中其他地方的另一组 ASCII 字符串:
00004f70 84 e0 04 f0 40 fe 00 28 13 d0 00 20 03 f0 ec ff |....@..(... ....|
00004f80 1e 49 80 31 08 69 88 61 35 4a 90 42 00 d3 8c 61 |.I.1.i.a5J.B...a|
00004f90 88 69 08 62 33 48 06 23 04 22 00 90 19 46 00 20 |.i.b3H.#."...F. |
00004fa0 62 e0 6b e0 20 43 48 45 43 4b 20 20 0a 00 00 00 |b.k. CHECK ....|
00004fb0 41 54 4f 4d 49 5a 45 52 0a 00 00 00 f6 e0 00 00 |ATOMIZER........|
00004fc0 28 03 00 20 ac 01 00 20 7a e0 00 00 20 20 43 48 |(.. ... z... CH|
00004fd0 45 43 4b 20 20 0a 00 00 10 4b 00 00 ba e0 00 00 |ECK ....K......|
00004fe0 44 4f 4e 27 54 0a 00 00 41 42 55 53 45 0a 00 00 |DON'T...ABUSE...|
00004ff0 50 52 4f 54 45 43 54 53 21 0a 00 00 3c 0b 00 20 |PROTECTS!...<.. |
00005000 20 57 41 54 54 20 0a 00 2c 2f 00 00 60 ea 00 00 | WATT ..,/..`...|
00005010 36 e1 00 00 2d 53 48 4f 52 54 2d 20 0a 00 00 00 |6...-SHORT- ....|
00005020 b2 eb 00 00 88 13 00 00 20 53 48 4f 52 54 20 20 |........ SHORT |
00005030 0a 00 00 00 81 0b 00 00 49 53 20 4e 45 57 0a 00 |........IS NEW..|
00005040 43 4f 49 4c 3f 20 0a 00 59 0a 00 00 4e 0a 00 00 |COIL? ..Y...N...|
00005050 7c db 00 00 88 db 00 00 dc 05 00 00 a0 db 00 00 ||...............|
00005060 0f 27 00 00 94 db 00 00 fb f7 e0 fd 28 46 fd f7 |.'..........(F..|
00005070 a1 f8 fb f7 f0 fe 07 20 fd f7 08 fb af 20 fb f7 |....... ..... ..|
00005080 2f ff 00 20 fb f7 30 ff 38 bd ff 49 08 60 70 47 |/.. ..0.8..I.`pG|
00005090 fe 49 88 72 70 47 fd 48 80 7a 70 47 10 b5 13 24 |.I.rpG.H.zpG...$|
其他地方的更多 ASCII 字符串:
00005490 44 2f 00 00 34 0c 00 20 a0 db 00 00 88 db 00 00 |D/..4.. ........|
000054a0 94 db 00 00 7c db 00 00 ea d5 00 00 36 0a 00 00 |....|.......6...|
000054b0 2e 0a 00 00 50 4f 57 45 52 0a 00 00 20 4f 46 46 |....POWER... OFF|
000054c0 20 0a 00 00 20 20 4f 4e 20 0a 00 00 e7 03 00 00 | ... ON .......|
000054d0 0f 27 00 00 9f 86 01 00 33 08 00 00 5f db 00 00 |.'......3..._...|
000054e0 fb f7 a4 fb fd 49 20 68 07 f0 10 fa 7d 27 08 46 |.....I h....}'.F|
000054f0 ff 00 39 46 07 f0 0a fa f9 4e 00 01 80 19 01 22 |..9F.....N....."|
在文件的不同部分还有几个这样的 ASCII 字符串簇。产品手册中提到了一些 ASCII 字符串:
但是,手册中并没有提到二进制中的许多 ASCII 字符串,例如这些:
00009d00 21 b0 f0 bd 00 01 00 50 00 ff 01 00 b4 ed 00 00 |!......P........|
00009d10 43 12 67 00 45 52 52 4f 52 3a 20 20 20 0a 00 00 |C.g.ERROR: ...|
00009d20 4e 4f 20 53 45 43 52 45 54 0a 00 00 2d 4b 45 59 |NO SECRET...-KEY|
00009d30 21 20 20 20 20 0a 00 00 ef 48 00 68 c0 07 c0 0f |! ....H.h....|
二进制的可视化还表明,属于ASCII 范围内的字节序列分散在整个二进制中(蓝色是 ASCII):
2. 考虑到固件开发的地区
固件、升级工具和微控制器均由台湾新唐公司开发。也许二进制中也有繁体字的序列。
默认情况下,strings
搜索 ASCII 字符序列和 -C 选项用于hexdump
将 ASII 范围内的字节打印为 ASCII 字符。但是,如果二进制文件中除了 ASCII 编码的字符串之外还有Unicode编码的字符串呢?Radare2 可用于直接在 hex 文件中搜索字符串,而不是依赖于不同工具的输出(hexdump 非常灵活,但使用radare2 速度更快)。要搜索字符串,izz
命令将用于在整个二进制文件中搜索字符串:
$ r2 ihex://SMOK_X_CUBE_II_firmware_v1.07.hex
-- I am Pentium of Borg. Division is futile. You will be approximated.
[0x00000000]> izz
Do you want to print 1444 lines? (y/N) <--- enter "y", obviously
这有一些潜在的有趣结果:
vaddr=0x0000aa95 paddr=0x0000aa95 ordinal=1093 sz=28 len=13 section=unknown type=wide string=h(胐恇ԇӕ栠だi(胐⁇ԇ
vaddr=0x0000aab5 paddr=0x0000aab5 ordinal=1094 sz=54 len=26 section=unknown type=wide string=i(胐ⱇ潩ᄆHhШ⣐ࡉ⡀ѡ⣠ũड蠅⡃灡h(胐
vaddr=0x0000aaef paddr=0x0000aaef ordinal=1095 sz=10 len=4 section=unknown type=wide string=Hh̨⣐
vaddr=0x0000ab07 paddr=0x0000ab07 ordinal=1096 sz=62 len=30 section=unknown type=wide string=h(胐ᄆ탕HhШ棐칩ࡉ桀ѡ棠ũड蠅桃灡i(胐༂웕Hh̨棐
vaddr=0x0000ab53 paddr=0x0000ab53 ordinal=1097 sz=70 len=34 section=unknown type=wide string=i(胐삵汍쁨ԇǐ栠だh(胐ꁇԇ˕栠끠h(胐恇ԇӕ栠だi(胐⁇ԇ
vaddr=0x0000ab9d paddr=0x0000ab9d ordinal=1098 sz=58 len=28 section=unknown type=wide string=i(胐ⱇ潩ᄆ꧕HhШ⣐ꡩࡉ⡀ѡ⣠ũड蠅⡃灡h(胐ꈂཌ
vaddr=0x0000abd7 paddr=0x0000abd7 ordinal=1099 sz=10 len=4 section=unknown type=wide string=Hh̨⣐
vaddr=0x0000abef paddr=0x0000abef ordinal=1100 sz=62 len=30 section=unknown type=wide string=h(胐ᄆ雕HhШ棐鑩ࡉ桀ѡ棠ũड蠅桃灡i(胐༂賕Hh̨棐
vaddr=0x0000ac3b paddr=0x0000ac3b ordinal=1101 sz=22 len=10 section=unknown type=wide string=i(胐袽腈ཨሢᄅ腃
我看不懂这些字符,所以我不知道它们来自什么语言。也许这只是胡言乱语。
3. 使用十六进制编辑器
一个具有GUI十六进制编辑器可以用来快速搜索数据中的模式。例如,该字节0A
看起来像是用作 ASCII 字符串的终止字符:
拆卸
那么应该如何使用 r2 反汇编二进制文件呢?16 位 ARM Thumb 指令 + 一些 32 位 Thumb2 指令是否有任何特殊参数或命令?
从如何反汇编到ARM UAL?:
-b16 假定为拇指,而不是因为指令大小或寄存器大小。使事情变得更简单的例外。因为它只是cpu的一种模式。
-b16 在顶点反汇编器(以及在 gnu 中)中设置 thumb2 模式。Thumb2 包含 2 字节和 4 字节指令长度。Thumb 只有 2。但是 thumb 和 thumb2 是 binarynl 兼容的,所以在这里使用 thumb2 是有意义的,除非 cpu 不支持它。
从我从 ual 中了解到的是,这只是一种语法,并且这种语法应该在顶点中准备就绪。
Capstone 对代码或数据一无所知。它只是拆卸。
为了正确反汇编文件,指定正确的体系结构至关重要:
-b 位强制 asm.bits (16, 32, 64)
对于这个固件二进制文件,-b 16
应该使用,而不是-b 32
:
$ r2 -a arm -b 16 ihex://SMOK_X_CUBE_II_firmware_v1.07.hex
如果-b 32
使用,结果是相当多的字节序列 r2 由于未对齐而读取为无效:
作为参考,这里是从相同偏移量 开始的反汇编0x1e8
,具有正确的 16 位对齐:
显然这是完全不同的。
要分析反汇编代码,必须熟悉 ARM Thumb 指令集和汇编,可能更一般地熟悉 ARM(CPU 设计、寄存器等)。Azeria Labs 系列教程似乎是一个很好的起点。
其他注意事项
- ISP 升级工具是一个 MS Windows PE32 可执行二进制文件。这可以通过逆向工程来确定闪蒸过程是如何发生的。
- 对微控制器的物理访问可能很有用。可以转储和分析闪存的全部内容。这也将使人们能够准确了解闪存中的所有内容
- 如果可以隔离已知的良好代码块,则可以对其进行反编译
结论
希望这里使用的方法对您未来的固件 RE 努力有用。分析固件带来了一系列挑战,因为它与其设计嵌入的硬件之间的关系密切。 由于设备的设计和架构决定了固件的布局和内容,因此有时无法在不访问的情况下逆转固件到设备,或者至少知道设备的指令集架构。