独角兽暑期训练营系列 | 高通芯片安全相关熔丝设定及检测方法研究

阅读量    46070 | 评论 1

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

本研究由独角兽安全夏令营第二届成员谢意同学完成

独角兽暑期训练营

360无线电安全研究院每年暑假都会面向在校学生举办一次暑期训练营,申请者投递简历并提交自己想做的课题介绍后,若入选,会在360技术专家的指导下完成课题。

本系列文章会发布今年5位学员在训练营中的成果。文章相关代码后续会在训练营github代码仓库发布 。

 

引言

随着移动通信网络的发展和智能手机的普及,手机逐渐取代PC成为人们日常计算和通信的主要工具,从早期的GSM网络开始,就出现了一些针对手机或者是通信网络的安全研究及实际攻击案例。近几年来,随着移动支付的发展和普及,方便别人的生活的同时,也催生了更多的网络犯罪。智能手机与个人财产相关性越来越高,促使手机安全愈发重要。而本篇文章从手机芯片的角度,以熔丝机制作为切入点,从一个全新的视角来对手机安全机制进行剖析和研究。

 

研究准备

研究对象的选取

实际上目前手机的芯片厂商有很多,例如苹果、高通、联发科等等,为了让我们的研究成果适用于更多的设备,我们查找了关于各个品牌份额的相关资料。根据Counterpoint公司的调查报告来看,各个品牌在2016——2017的市场份额趋于稳定,高通一直以份额第一的地位遥遥领先于其他品牌,份额甚至是第二名Apple的两倍,并且其市场份额还有继续上升的趋势,因此本次研究我把高通作为研究对象。 图片 1

熔丝的概念

我们本次研究的重点是熔丝,那么我们首先得弄明白熔丝是什么。 如果单从硬件角度来看,熔丝类似于一个可编程存储器。我们把想要存储的数据烧录进去并熔断之后,这块区域所存储的信息就没法再被更改,想要改变信息的话只有更换芯片。 我们这次主要从软件如何使用熔丝的角度来分析熔丝。由于熔丝的一次性可编程特性,它常常被用来存储一些重要的安全相关的信息,以达到防止这些信息被恶意篡改的目的。例如手机Secure Boot中根证书的Hash值就会存储在熔丝中,防止证书被替换,后面我会对这个部分进行详细的说明。

 

研究思路

既然手机的Secure Boot利用到了熔丝机制来保证证书不被替换,那么我们不妨从Secure Boot入手,看看它如何使用熔丝机制,这有利于我们对于熔丝的进一步了解。

Secure Boot的概念

Secure Boot可以理解成为一个队列,队列中是系统的执行程序,这个队列我们称之为安全启动队列。在这个队列中,程序按照次序启动,前一个启动的程序负责下一个程序的验证以及启动。若当前程序对下一个将要启动的程序验证通过,说明下一个程序是合法程序,启动执行;若当前程序对下一个将要启动的程序验证不通过,则说明这个程序在当前程序看来不是合法程序,拒绝启动,则系统启动失败。很多PC、手机系统都采用这种机制来避免恶意软件被加载运行。 在这个安卓系统的Secure Boot机制中,前一个阶段的引导程序利用相应的证书验证后一阶段程序的签名。 那么我们会发现这样一个问题:既然系统利用证书的方式来对程序的合法性进行验证,并且程序是以队列的形式启动的,那么队列中的第一个程序应该如何验证?这就用到了熔丝机制。 简单来说,我们把整个验证链的第一个证书称为根证书,根证书是验证其他证书的基础。为了保证根证书的有效,系统利用熔丝机制将根证书的hash值存储到fuse中。在芯片通电之后,主引导程序(PBL)首先会验证这个根证书的hash值与熔丝中存储的是否一致,若一致则继续后面的启动过程,若不一致则启动失败。由于PBL本身也是在芯片制造时固化到芯片中,所以在这个阶段,PBL和根证书的Hash都不能再改变,由此保证了Secure Boot不被绕过。Secure Boot的启动过程可以用下面这张图来表示。 

高通平台的相关机制

在理解Secure Boot机制的基础上,我们具体看一看高通平台的相关实现。

Elf与证书链

下图是高通平台的一种二进制文件的格式,可以把它看做elf格式。但是需要注意的是和普通的Elf文件不同,高通只是借用了Elf格式作为其modem,wifi,trustzone,GPU固件的组织形式。我们主要关注的是这个文件中的Hash Table Segment模块。 

这个模块包含了整个Elf文件各个部分的Hash值以及签名、证书链等等。高通的签名技术似乎与其他的不同,它不是直接对整个模块进行签名,而是先对header、segment等各个部分分别进行hash,这些hash的集合就存放在Hash Table Segment中,签名的时候直接对整个Hash的集合进行签名,就像下图展示的一样。图片中右下角就是刚刚提到的证书链,从根证书开始,一层一层地验证,最后对这个Elf文件的签名进行验证。 图片 2

下面这张图更详细地说明了整个证书链的工作原理。先用私钥对程序进行签名,验证的时候利用证书中的公钥对文件签名进行验证。 图片 3

证书锚

就像前面提到的那样,证书链的信任根是根证书,而根证书的hash值存放在fuse中,我们称之为证书锚。有了证书锚,整个证书链才是有效可信任的。那么Hash值等信息如何烧录到熔丝中呢?

sec分区

在高通平台的存储器中,熔丝烧结信息存储于sec分区。系统第一次启动时,会检测是否存在sec分区,若存在则读取sec分区中的信息并进行熔丝的烧录。也就是说如果我们能读取sec分区中的相关信息,就可以知道熔丝中的相关安全性配置和信息,这样就实现了本次研究的目标。 那么,我们现在主要的问题就变成了如何有效地正确解析sec分区的信息。

sec分区提取

将手机连接ubuntu之后,利用adb连接手机,在手机端授权成功之后利用命令列出各分区的信息ls -la /dev/block/platfrom/soc/624000.ufshc/by-name。可以得到

lrwxrwxrwx 1 root root   15 1970-01-07 02:13 sec -> /dev/block/sdd4

我们使用dd命令将其拷贝出来,命名为sec.dat

dd if=/dev/block/sdd4 of=/sdcard/sec.dat

这样我们就获得了sec.dat文件,下面,我们的目标是对其进行解析。

 

研究进展

sec.dat文件的解析

我们直接打开sec.dat文件(如下图),除了第二行能读到一串字符,显然无法获取其他有效的信息。我猜想sec.dat采用了某种特定的格式对信息进行了打包。 图片 4

直接漫无目的的猜解显然是低效的,在github上我们找到了某款高通芯片的部分源码,或许这其中就包含了sec.dat文件相关的代码。我们对这个部分进行初步的分析之后,找到了commom、tools目录下的sectools文件夹。这个文件夹就包含了sec.dat文件的生成模块,整个文件夹是由一堆python文件构成的一个工具集,入口文件是sectools.py。 我们尝试直接寻找sec.dat文件格式规定的相关源码。直接根据其中规定的格式来解析sec.dat文件。但是在我使用tree命令尝试查看整个目录结构的时候,我放弃了这个想法。 图片21

从上图可以看到,sectools文件夹下面有123个子目录,一共包含1043个文件,显然盲目地寻找关于sec.dat文件格式的源码是很困难的。我们不妨换一种思路。 我们可以以sectools.py这个入口文件开始,模拟整个程序从解析命令行参数开始,直到调用相关模块,最后生成sec.dat文件的过程,人工模拟执行程序语句,直到找到格式相关的部分。这种方法虽然也很费时费力,但是显然比刚刚的思路快很多。由于整个分析的过程很复杂,我们在这里只列举出几个重要的跳转的地方,具体的语法逻辑留给大家自行梳理。 图片23

首先打开入口文件sectools.py,如上图。直接跳转到执行的函数,找到其中的for循环语句,这里遍历的FEATURES_LIST就是整个工具支持的工具列表,我们跳转到其定义处。 图片24

可以看到整个工具目前分为五个模块,我们需要的熔丝模块为fuseblower,从fbc文件夹导入,我们打开相应的文件。 图片25

如上图,打开之后,我们发现相关的执行模块FuseBlowerCore又是从其他文件导入,我们再次跳转。 图片26

如上图,找到相应的类,发现这个类中定义的四个函数显然与sec.dat文件的生成没有直接的关系,因此我们有理由相信我们要找的函数是在这个类继承的父类(FuseCommonCore)中定义的。 图片27

我们跳转到上图中父类的定义处,果然在父类中找到generate()这个函数,如下图。这个函数中调用了secdat_pg()这个函数,再次跳转。 图片28

图片28_2

找到secdat_pg函数的定义处,发现这个类中的set_data函数,跳转到ParseGenSecdat定义处。 图片30

图片31

跳转到format目录之后,尝试运行tree命令。可以看到目录和文件数已经大大减少,并且经过分析可以知道这些源码按照目录名称,分别对应了sec.dat文件的不同部分的生成格式。 图片32

分析的结果如下图,整个sec.dat文件大致分为三个部分,header、segment以及footre,其中segment部分分为几个小部分,包括fuse header和若干个fuse entry。 

此外,高通把所有的字符信息,按照不同类型的格式通过struct库中的pack()函数打包成二进制格式,右边是不同的数据类型相应的格式化字符串表格,供大家参考。那么显然,我们应该利用unpack()函数并借助相应的格式化字符串对各部分的内容进行反向解析。 由于sec.dat文件的footer部分实际上就是一个固定长度的hash值。他是通过对header部分和segment部分整体做了一个hash(SHA-256算法)。我们也尝试自行对这两个部分进行一次hash,与解析之后的footer进行比对,发现二者一模一样。说明这个熔丝文件没有被损坏。 

解析完footer之后,尝试对header进行解析。header部分是固定的48字节长度。 

第三部分我尝试对segment中的fuse header进行解析,这个部分实际上分为两个字部分,我们为了简洁直接统称为fuse header。 

最后,对qfuse entry部分进行解析,通过源码可以知道每个fuse entry部分长度都为固定的20字节。 这样,整个解析工具就完成了,工具的源码可以在独角兽团队github仓库夏令营页面上找到。

结果的提取与汇总

工具的解析结果会输出到同目录下的txt文件中,txt格式比较方便手工查看。整个生成的过程很快,没有什么复杂的运算算法。通过解析的结果,我们可以得到熔丝中关于手机安全设置的很多有用信息,比如OEM_PK_HASH、读写权限、rollback开关等。 图片45_1

图片45_2

 

总结

解析工具的测试

利用配置文件进行测试

由于我们工具的输入是sec.dat文件,输出是txt文件,因此想要对工具进行测试,就必须找到足够多的sec.dat文件。但是要找到很多不同芯片的手机再提取出sec.dat文件显然是不现实的。由于sectools文件的工作原理是借助芯片的下图这三个配置文件来生成熔丝信息存储到sec.dat。因此我们只要有不同型号的配置文件,就可以得到相应型号的熔丝文件(sec.dat)。 

经过努力,我们一共收集到了44个芯片的相关资料,但是其中15个型号缺少了三个配置文件中的某一个或几个,因此我们只能对剩下的29种芯片进行测试。 

在能够得到sec.dat文件的这些型号中,测试通过率达到百分之百,这一定程度上说明了不同型号芯片的熔丝模块的格式是固定的。

实机测试

我们对三款手机进行了实际的测试,先提取出手机中的sec分区,再利用我们的解析工具进行解析测试,结果如下:

手机型号 芯片型号 测试结果
Nokia 8工程机 MSM8998 sec分区全为0,未启用熔丝
Google pixel MSM8996 正确解析,获得相关信息
Mi 4c MSM8992 sec分区全为0,未启用熔丝

 

结论

通过本次研究,我们发现通过解析sec分区来获取熔丝的相关信息与安全设置是可行的,高通不同型号芯片的sec分区生成格式比较统一,可以采用相同的方法对其进行解析。有兴趣的读者可以考虑在本文的基础上实现一个内核驱动模块,模块加载后,可以提取熔丝状态,从而更便捷地获取熔丝信息。

源代码地址见独角兽团队github仓库夏令营页面:https://github.com/UnicornTeam/summer-camp

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多