IT评测·应用市场-qidao123.com

标题: NB!小哥竟然绕过了安全启动,Dump了SoC的BootROM。 [打印本页]

作者: 张春    时间: 2024-9-2 12:12
标题: NB!小哥竟然绕过了安全启动,Dump了SoC的BootROM。
  推荐语:
这是一篇关于怎样绕过安全启动,然后实现破解BootRom的文章。通过这篇文章,可以让你对于ATF、安全启动等有个更深刻的影响哦。
   往期经典:
  

Amlogic S905 系统级芯片是一款专为视频应用计划的 ARM 处理惩罚器。
它广泛用于 Android/Kodi 媒体盒子中。该 SoC 实现了 TrustZone 安全扩展,以运行一个可信执行环境(TEE),该环境支持数字版权管理(DRM)和其他安全功能:

该 SoC 包罗一个安全启动机制,用于在将受信执行环境(TEE)映像加载到 TrustZone 之前对其举行身份验证。安全启动链的第一个环节是 BootROM 代码,该代码直接存储在芯片中。
本文介绍了怎样从基于 Android 的 Inphic Spot i7 装备中的此 SoC 提取 BootROM 代码。
技术文档

Amlogic 在 Hardkernel 的资助下发布了 S905 数据手册的公开版本。然而,该版本被大量删减,此中大部分关于安全启动或 TrustZone 的内容已被移除。
但我们仍然可以在 Amlogic 和原始装备制造商(OEM)发布的 GPL 源代码包中找到大量技术信息。
例如,我们可以找到 BootROM 代码的一个潜伏地点:
  1. #define ROMBOOT_START   0xD9040000
  2. #define ROM_SIZE        (64 * 1024)
  3. #define ROMBOOT_END     (ROMBOOT_START + ROM_SIZE)
复制代码
通过 UART 获取 root 访问权限

我们首先从连接串口(或 UART)开始,由于这个接口可以快速轻松地访问引导步伐和 Linux 内核上的调试消息和串行控制台。
由于板上有一个带有引脚布局标签的端口讨论,因此识别该板上的串口相当简朴:

我们将 USB 到 UART 适配器连接到这个端口。一旦 Linux 内核启动过程完成,我们就可以直接访问 root shell。
我们可以开始探索系统(的非安全侧)。例如,我们可以转储分区:
  1. root@p200:/# ls -l /dev/block/platform/d0074000.emmc/
  2. lrwxrwxrwx root     root              2015-01-01 00:00 boot -> /dev/block/boot
  3. lrwxrwxrwx root     root              2015-01-01 00:00 bootloader -> /dev/block/bootloader
  4. drwxr-xr-x root     root              2015-01-01 00:00 by-num
  5. lrwxrwxrwx root     root              2015-01-01 00:00 cache -> /dev/block/cache
  6. lrwxrwxrwx root     root              2015-01-01 00:00 crypt -> /dev/block/crypt
  7. lrwxrwxrwx root     root              2015-01-01 00:00 data -> /dev/block/data
  8. lrwxrwxrwx root     root              2015-01-01 00:00 env -> /dev/block/env
  9. lrwxrwxrwx root     root              2015-01-01 00:00 instaboot -> /dev/block/instaboot
  10. lrwxrwxrwx root     root              2015-01-01 00:00 logo -> /dev/block/logo
  11. lrwxrwxrwx root     root              2015-01-01 00:00 misc -> /dev/block/misc
  12. lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0 -> /dev/block/mmcblk0
  13. lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0boot0 -> /dev/block/mmcblk0boot0
  14. lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0boot1 -> /dev/block/mmcblk0boot1
  15. lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0rpmb -> /dev/block/mmcblk0rpmb
  16. lrwxrwxrwx root     root              2015-01-01 00:00 recovery -> /dev/block/recovery
  17. lrwxrwxrwx root     root              2015-01-01 00:00 reserved -> /dev/block/reserved
  18. lrwxrwxrwx root     root              2015-01-01 00:00 rsv -> /dev/block/rsv
  19. lrwxrwxrwx root     root              2015-01-01 00:00 system -> /dev/block/system
  20. lrwxrwxrwx root     root              2015-01-01 00:00 tee -> /dev/block/tee
复制代码
虽然 tee 分区(Trusted Execution Environment,受信执行环境)为空,但引导步伐分区包罗多个引导步伐。
但 BootROM 不在此中,由于它存储在 SoC 中,而不是闪存中。
(实验失败)读取 BootROM

由于我们拥有 root 权限和 BootROM 的潜伏内存地点,我们可以实验直接读取它。
提供的 Android ROM 包罗一个方便的 debugfs 接口,用于从用户空间窥探和访问物理内存:
  1. root@p200:/# echo "d0070000" >/sys/kernel/debug/aml_reg/paddr               
  2. root@p200:/# cat /sys/kernel/debug/aml_reg/paddr                             
  3. [0xd0070000] = 0x1000254
复制代码
这个 aml_reg 驱动步伐使用 ioremap 内核函数来为请求的地点设置适当的内核页表映射。
但是,如果我们实验读取假定的 BootROM 区域:
  1. root@p200:/# echo "d9040000" >/sys/kernel/debug/aml_reg/paddr
  2. root@p200:/# cat /sys/kernel/debug/aml_reg/paddr
  3. [  376.546491@0] Unhandled fault: synchronous external abort (0x96000010) at 0xffffff80001aa000
  4. [  376.549396@0] Internal error: : 96000010 [#1] PREEMPT SMP
  5. [  376.554712@0] Modules linked in: dwc_otg dhd(O) aml_thermal(O) mali(O) aml_nftl_dev(PO)
复制代码
内核崩溃了。以是要么是 BootROM 地点错误,要么是这个内存区域被设置为安全的。
由于我们没有 BootROM 地点的其他候选者,我们可以说从非安全世界无法访问 BootROM 区域。
进入安全世界

理论上,安全启动链会制止在安全世界中加载未授权的代码。
在启动的早期阶段,通过 UART 快速查抄调试日记表明,这些引导步伐基于 ARM Trusted Firmware(ATF)参考实现。

现在我们将探索一些进入安全世界的方法。
U-Boot 引导步伐

通过 UART 连接到控制台,我们可以中断 U-Boot 的启动序列以访问提示符。从这里,我们可以运行任意的 U-Boot 下令:
  1. Hit any key to stop autoboot: 0
  2. gxb_p200_v1#help
  3. ?       - alias for 'help'
  4. aml_sysrecovery- Burning with amlogic format package from partition sysrecovery
  5. amlmmc  - AMLMMC sub system
  6. amlnf   - aml nand sub-system
  7. amlnf_test- AMLPHYNAND sub-system
  8. autoping- do auto ping test
  9. autoscr - run script from memory
复制代码
然而,U-Boot 引导步伐(在 ATF 计划中称为 BL33)在非安全模式下运行,这可以从 UART 控制台的启动日记中看出:
  1. INFO:    BL3-1: Preparing for EL3 exit to normal world
  2. INFO:    BL3-1: Next image address = 0x1000000
  3. INFO:    BL3-1: Next image spsr = 0x3c9
  4. U-Boot 2015.01-ga9e9562-dirty (May 06 2016 - 03:36:02)
复制代码
以是在这个点上,我们已经被安全世界锁定在外了。接下来我们实验其他方法。
SMC 接口

安全世界和非安全世界可以通过 ARM 安全监督器调用(SMC)举行通讯。当焦点执行 SMC 指令时,它会切换到安全监督器模式(异常级别 EL3)。
在 ATF 计划中,在 EL3 下运行的代码被称为引导步伐阶段 3-1(BL31)。我们可以在之前转储的引导步伐分区中找到这个映像。此代码对 TrustZone 安全至关重要,因此我们应该对其举行研究。
BL31 映像中的开源 ATF 代码库通过逆向工程促进了分析,由于我们可以快速恢复 ATF 代码结构。
以下是处理惩罚来自正常世界的 SMC 中断的已注册服务列表:

sip_svc 服务很有趣,由于它包罗 Amlogic 开发的一些自界说函数:

乍一看,hdcp22_sec_read_reg 和 hdcp22_sec_write_reg 函数很有希望,由于它们是用于安全内存的读写原语。但是,它们严格限制了对特定内存范围的访问:

对其他函数的快速(不完整)分析并未在参数清理(任意读写毛病)方面发现任何显着的缺陷。此中一些函数相当复杂,特别是加密函数,因此我们尚未对其举行任何查抄。
如果我们发现这些函数中的某个存在毛病,我们大概可以或许从正常世界触发安全世界内存损坏,从而实现特权提升到安全世界。然而,这需要一些专业技能来现实利用这些毛病。因此,让我们探索另一种攻击向量。
绕过安全启动链

访问安全世界的另一种解决方案是在安全启动链的某个阶段打破/绕过/诱骗/请求安全启动链。安全启动链的一个常见攻击面是下一阶段的加载、解析和认证步骤。
由于BL1代码存储在SoC中,因此我们(目前)无法访问它。但我们拥有之前转储的引导步伐分区中的BL2映像。因此,我们将分析BL2用于解析和认证BL31映像的机制,希望能找到有趣的毛病。
现在,我们将开始一个漫长的逆向工程过程,这个二进制文件没有任何系统调用,只有极少量的字符串来引导我们的工作。幸运的是,BL2映像相当小,只有约40KB。而且我们有一些节流时间的方法:
与BL31一样,BL2映像遵循ATF(Arm Trusted Firmware)代码逻辑,因此逆向工程工作得到了一定水平的简化:我们可以快速找到ATF代码库中界说的主要函数和结构。
另一个逆向工程技巧是通过识别函数访问的内存映射装备来推断它们的作用。这些内存区域的几个地点范围可以在SoC数据手册和GPL源代码中找到。例如,我们可以预期加密函数会访问专用于硬件加密引擎的内存寄存器。
最后,我们不想花时间去逆向开源代码,尤其是加密代码,由于这项任务相当艰巨。而且从开发者的角度来看,这也很复杂,以是我们可以推测他们使用了一个大概是开源的库。因此,我们在BL2代码和几个潜伏的开源软件(OSS)库之间探求函数原型、调用序列和上下文结构初始化的相似性。在我们的案例中,我们很快发现加密代码来自OSS PolarSSL/mbed TLS项目。
分析BL2认证例程

一旦BL2从NAND加载了BL3映像,就会解析其头部。我们目前还没有关于头部结构的任何信息(ATF代码中不存在),但我们可以留意到它以一个常量把戏值"@AML"开头。这有助于我们在BL2二进制文件中快速定位解析代码。
我们结合“猜测”(即在十六进制编辑器中检察BL31头部)和对BL2解析代码的逆向工程,来找出头部结构的一些成员:
  1. struct aml_img_header {
  2.   unsigned char magic[4];// "@AML"
  3.   uint32_t total_len;
  4.   uint8_t header_len;
  5.   uint8_t unk_x9;
  6.   uint8_t unk_xA;
  7.   uint8_t unk_xB;
  8.   uint32_t unk_xC;
  9.   uint32_t sig_type;
  10.   uint32_t sig_offset;
  11.   uint32_t sig_size;
  12.   uint32_t data_offset;
  13.   uint32_t unk_x20;
  14.   uint32_t cert_offset;
  15.   uint32_t cert_size;
  16.   uint32_t data_len;
  17.   uint32_t unk_x30;
  18.   uint32_t code_offset;
  19.   uint32_t code_len;
  20.   uint32_t unk_x3C;
  21. } aml_img_header_t;
复制代码
头部表明映像被分为4个部分:

在我们的目标装备上,BL31映像的签名范例(头部中的sig_type)是SHA-256。这很有趣,由于仅SHA-256哈希本身并不敷以提供认证。
以下是BL2中认证例程的简化算法伪代码:
  1. int auth_image(aml_img_header_t *img){
  2.   validate_header(img); // checks on magic value & header length
  3.   hash = hash_sha256(img);// hash whole image except signature
  4.   if(img->sig_type == RSA) {
  5.     return check_rsa_signature(img, hash)
  6.   }else{
  7.     return memcmp(hash, (char*)img + (img->sig_offset));
  8.   }
  9. }
复制代码
我们可以确认,SHA-256选项仅会对加载的映像举行哈希处理惩罚,并将结果与同一映像中预盘算的哈希值举行比力。我们本可以设想一个更复杂的解决方案,如HMAC,但现实上在这种环境下,仅查抄了完整性,而没有举行认证。
纵然加载的映像使用RSA签名,我们仍然可以将签名范例更改为SHA-256并重新生成正确的哈希值。
如果签名范例由eFuse强制执行,则可以避免此问题。
这意味着我们可以轻松地修改BL31映像,这是TrustZone中最具特权的代码。
自界说BL31映像

在前面的部分中,我们描述了SMC函数hdcp22_sec_read_reg,该函数可以从平凡世界读取安全内存的受限范围。
现在是时候训练我们的NOP技术(NOP是一种汇编语言指令,代表“无操作”,用于添补代码空间或延迟执行),以摆脱这些限制,从而完全访问安全内存。

我们还需要扩展页表,由于BootROM内存区域没有映射。MMU(内存管理单元)初始化是在ATF代码库中实现的,因此再次在BL31二进制文件中很轻易找到并分析。
默认环境下,以下内存区域被映射:

我们将此中一个的巨细扩展以覆盖BootROM区域:

映射区域0xD9000000的新巨细为0x80000,因此它包罗了BootROM区域0xD9040000-0xD9050000。
我们险些完成了对BL31的修改:我们还需要更新SHA-256哈希值。
aml_bootloader_tool:解析并重新盘算Amlogic引导加载步伐的SHA-256

此工具可以解析并重新生成引导加载步伐分区中包罗的引导加载步伐的SHA-256。源代码在GitHub上。
每个引导加载步伐都通过UUID举行标识,这些UUID在ATF源代码中界说。在我们的案例中,BL31映像是第2个条目:
  1. $ ./aml_bootloader_tool ./dump/bootloader.img H 2
  2. fip_toc_header.name:        aa640001
  3. fip_toc_header.serial_number:        12345678
  4. fip_toc_header.flags:        0
  5. TOC ENTRY #2
  6. fip_toc_entry.uuid:        47D4086D4CFE98469B952950CBBD5A00
  7. fip_toc_entry.offset_address:    14000 (absolute: 0x20000)
  8. fip_toc_entry.size:        0x11130
  9. fip_toc_entry.flags:        0x0
  10. magic[@0x0]:        @AML
  11. total_len[@0x4]:    0x11130
  12. header_len[@0x8]:    0x40
  13. unk_xC[@0xC]:        0x5eec9094
  14. sig_type[@0x10]:    0x0
  15. sig_offset[@0x14]:    0x40
  16. sig_len[@0x18]:        0x20
  17. data_offset[@0x1c]:    0x60
  18. unk_x20[@0x20]:        0x0
  19. cert_offset[@0x24]:    0x60
  20. cert_len:        0x0
  21. data_len:        0x110d0
  22. unk_x30[@0x30]:        0x0
  23. code_offset[@0x34]:    0x60
  24. code_len[@0x38]:    0x110d0
  25. unk_x3C[@0x3C]:        0x0
  26. signature:        263BEFAFC5A051C550D31791EC1212576BE65DB8AD365074560F0BABC076D3CA
  27. computed_sha256:    35AD6B284EE2D6B5672DD0958592028D5BF455A6DCD1EB086D8336FB86533853
复制代码
BL31映像的哈希值已更新,我们现在可以在装备上重新刷新转储:
  1. $ dd if=./bootloader.img of=/dev/block/bootloader
复制代码
最后,我们重启装备以在TrustZone中加载我们自界说的BL31映像。
转储BootROM

SMC系统调用只能从EL1(执行级别1)及以上级别调用。因此,我们创建了一个简朴的内核模块,该模块将在EL3级别执行SMC调用到我们修改后的函数hdcp22_sec_read_reg。
这个快速而“肮脏”的hack是基于Amlogic的debugfs驱动步伐reg_access。源代码在GitHub上。
一旦加载,为了启动SMC调用,我们将参数写入文件/sys/kernel/debug/aml_smc/smc。第一个参数是被调用的SMC函数的ID(在hdcp22_sec_read_reg的环境下为0x82000018)。第二个参数(对于这个特定的SMC ID)是读取的内存地点。结果DWORD(双字)直接打印在内核日记中(我们说它“肮脏”)。
  1. $ insmod ./smc_access.ko
  2. $ echo 82000018 D9040000 > /sys/kernel/debug/aml_smc/smc
  3. [  219.092948@0] smc_access: SMC call 82000018 returns: aa1f03e0
复制代码
结果aa1f03e0很有希望,它对应于ARM指令:MOV X0, XZR
为了自动提取整个BootROM内存区域,我们创建了一个简朴的脚本:
  1. $ seq -f %1.f 0xD9040000 0x4 0xD9050000 | xargs printf "echo "82000018 %x" > /sys/kernel/debug/aml_smc/smc\n"
  2. echo "82000018 d9040000" > /sys/kernel/debug/aml_smc/smc
  3. echo "82000018 d9040004" > /sys/kernel/debug/aml_smc/smc
  4. echo "82000018 d9040008" > /sys/kernel/debug/aml_smc/smc
  5. [...]
  6. echo "82000018 d904fff8" > /sys/kernel/debug/aml_smc/smc
  7. echo "82000018 d904fffc" > /sys/kernel/debug/aml_smc/smc
复制代码
最后,我们将全部这些DWORD(双字)归并到一个名为bootrom.bin的文件中。
  1. $ ls -l ./bootrom.bin
  2. -rw-r--r-- 1 user user 65537 juil.  8 12:43 ./bootrom.bin
  3. $ sha1sum bootrom.bin
  4. bff0c7fb88b4f03e732dc7a4ce504d748d0d47dd  bootrom.bin
  5. $ strings bootrom.bin |tail -22
  6. BL1:
  7. FEAT
  8. READ
  9. EMMC
  10. NAND
  11. LOOP
  12. auth failed, reboot...
  13. 08dafda0fd31778
  14. glacier.amlogic
  15. qian
  16. 04/14/15_14:23:08
  17. gcc version 4.8
  18. 08dafda0fd31778
  19. boot@USB
  20. boot@SDC
  21. BAD PASSWORD
  22. !!!!
  23. vRQ>
  24. 8STs
  25. LwH'
  26. Err:sha
  27. 0!0
复制代码
结论

S905 SoC提供了支持安全启动的硬件特性,但OEM(原始装备制造商)仍然可以选择是否启用它。但纵然在强制执行安全启动的环境下,Amlogic当前版本的BL2中的一个缺陷仍然可以绕过它。因此,可信执行环境(TEE)并不可信。好消息是,与BootROM差别,BL2可以举行修补。
我要感谢@Karnalzi的资助!
披露时间表



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4