赞
踩
也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大
少走了弯路,也就错过了风景,无论如何,感谢经历
Android作为一个应用广泛的平台,同样支持Verified Boot。以硬件提供保护作为信任根,实现从bootloader到boot分区以及其他分区(system、vendor、oem
等)完整信任链路,在每一步转交执行权限之前都会对数据和代码的完整性(integrity)和真实性(authenticity)进行验证。几个关键节点如下:
Android 4.4
:提供内核dm-verity特性,实现Verified Boot,启动时如果分区损坏会提示用户Android 7.0
:禁止未验证的设备启动,同时引入前向纠错功能,支持自动修复非恶意的数据损坏Android 8.0
:引入支持Treble的Verified Boot
,称为AVB(Android Verified Boot
)或者Verified Boot 2.0
,对分区尾部的数据格式进行格式化,并增加版本回滚保护的功能这只是Android官方的feature时间结点,事实上许多OEM厂商也会针对启动功能进行自定义的配置,比如使用AOSP中的宏来设置或者在自己的私有bootloader中使用不同的校验方式
在 IoT以及IoV 中保护Android 设备安全性的重要一环就是保证固件、代码的完整性,以及被用来对付一些恶意软件试图感染系统的固件的安全威胁。通常为了对付这些安全威胁,一方面是及时修复现有攻击面所面临的漏洞,比如浏览器、蓝牙、调试接口;另一方面需要确保的是即便恶意代码获取了执行权限,也无法修改系统镜像进行持久化。针对这点所构造的安全方案通常称为 Secure Boot
Secure Boot
顾名思义它也称为安全启动,确保当前设备启动之后所加载执行的代码都是可信的,其中主要概念分为:
Secure Boot
(安全启动) 建立了一个完整的信任链 (通过签名公钥验证文件或程序的数据签名,确保启动文件或程序的完整和可信,以防止在启动过程中加载并运行了未经授权的程序),从受硬件保护的信任根开始到引导加载程序、启动分区和其他经过验证的分区,包括系统、vendor和OEM分区。在设备启动期间,每个阶段都会在移交执行之前验证下一个阶段的完整性和真实性。Secure Boot (安全启动) 被用来对付一些恶意软件试图感染系统的固件的安全威胁。用户可能会无意中禁用或软件可能会有意禁用安全启动。因此,配置不正确的话,系统就运行在一个不安全的平台上。它的原理是给引导程序签名,让你的计算机信任这个签名,并仅允许启动有可信签名的引导程序。一旦有人恶意往引导程序注入些东西时,由于签名被破坏,计算机就出于安全目的停止启动了
注:在安全启动机制下,所有启动文件(如:启动引导程序、内核镜像、基带固件)均需先通过签名校验才被允许加载运行,在启动过程的任何阶段,如果签名验证失败,则启动过程会被终止。
安全启动要求在启动之前对所有固件代码和数据的真实性进行加密验证。这包括内核(从引导分区加载)、设备树(从dtbo分区加载)、系统分区、vendor 分区等
设备的安全启动流程如下:
注: Android系统基于Linux,所以bootloader部分也是与传统的嵌入式设备上运行的Linux没有什么区别,由于除Google外的大部分Android厂商都没有提供bootloader的源代码,所以分析手机设备的bootloader需要使用逆向工程的手段,当然由于有了Google官方的开源bootloader代码做参考,能让分析工作轻松不少。需要注意Secure Boot对于不同的厂商,实现上可能会引入不同的名字,比如 Verified Boot、High Assurance Boot 等等,但本质上都是类似的
说道BootLoader,那也要说一下固件。固件(firmware)是一种写入硬件设备的软件,作用是对应用和各项系统功能实时控制。固件中包含底层代码,这些代码能实现软件对硬件的操作。运行固件的设备称为嵌入式系统,嵌入式系统的硬件资源在存储能力以及内存等方面往往具有诸多限制。举例来说,智能手机、智能终端、交通信号灯、无人机、机顶盒都是运行固件的嵌入式设备。
固件通常由bootloader、内核、根文件系统及其他资源组成。根据嵌入式Linux、嵌入式Windows(WinCE)、Windows IoT内核及各种实时操作系统(RTOS)的区别,固件也有多种类型
IoT设备构成分为硬件和软件,软件方面如下:
根文件系统首先是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行
Linux根文件系统中一般有如下的几个目录:
该目录下的命令可以被root与一般账号所使用,由于这些命令在挂接其它文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中
该目录下存放系统命令,即只有系统管理员(最高权限的root)能够使用的命令,系统命令还可以存放在/usr/sbin、/usr/local/sbin
目录下,/sbin目录中存放的是基本的系统命令,它们用于启动系统和修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中
该目录下存放的是设备与设备接口的文件,设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种设备,即通过读写某个设备文件操作某个具体硬件
该目录下存放着系统主要的配置文件,例如人员的账号密码文件、各种服务的其实文件等。一般来说,此目录的各文件属性是可以让一般用户查阅的,但只有root有权限修改
该目录下存放共享库和可加载(驱动程序),共享库用于启动系统。运行根文件系统中的可执行程序,比如:/bin /sbin
目录下的程序
系统管理员(root)的主文件夹,即是根用户的目录,与此对应,普通用户的目录是/home下的某个子目录
/var目录中存放可变的数据,比如spool目录(mail,news),log文件,临时文件
这是一个空目录,常作为proc文件系统的挂接点,proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录,文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统
用于临时挂载某个文件系统的挂接点,通常是空目录,也可以在里面创建一引起空的子目录,比如/mnt/cdram /mnt/hda1 。用来临时挂载光盘、移动存储设备等
用于存放临时文件,通常是空目录,一些需要生成临时文件的程序用到的/tmp目录下,所以/tmp目录必须存在并可以访问
对于嵌入式Linux系统的根文件系统来说,一般可能没有上面所列出的那么复杂,比如嵌入式系统通常都不是针对多用户的,所以/home这个目录在一般嵌入式Linux中可能就很少用到,而/boot这个目录则取决于你所使用的BootLoader是否能够重新获得内核映象从你的根文件系统在内核启动之前。一般说来,只有/bin,/dev,/etc,/lib,/proc,/var,/usr
这些需要的,而其他都是可选的
固件可采用的文件类型有很多种,常见的有squashfs、cramfs、ext2、jeffs2
等。其中设备(尤其是消费级电子设备)最常采用的文件系统是squashfs,攻击者可使用unsqushfs工具对文件系统提取数据。需要注意的是,部分厂商采用了非标准的squasgfs压缩算法,如LZMA和XZ。例如以某路由潘多拉固件为模型,对该固件进行提取和分析,关于本固件的文件系统和压缩算法如下所示:
如上图,该固件文件即为squashfs文件系统,并使用LZMA和XZ压缩算法
注:SquashFS是基于Linux内核使用的压缩只读文件系统。该文件系统能够压缩系统内的文档,inode以及目录,文件最大支持2^64
字节。每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。inode包含文件的元信息,具体来说有Size 文件的字节数、Uid 文件拥有者的User ID、Gid 文件的Group ID、Access 文件的读写执行权限等。linux可以用stat命令,查看某个文件的inode信息。
对squashsf文件系统的解压、提取,需要借助sasquatch工具,可从https://github.com/devttys0/sasquatch
下载安装。如果sasquatch工具不起作用,也可以使用7-zip对后缀为squashsf的文件进行提取(推荐本方式)
注:我们可以把文件系统看作存储配置文件、服务、账号口令、哈希、应用程序代码及启动脚本的地方
Android 系统虽然也是基于 Linux 系统的,但是由于 Android 属于嵌入式设备,并没有像 PC 那样的 BIOS 程序。 取而代之的是 BootLoade 系统启动加载器
一旦bootloader分区出了问题,手机变砖就很难救回了。除非借由高通9008或者MTK-Flashtool之类更加底层的模式来救砖,如果要刷机的话,一般刷机不动这个分区
大部分 bootloader 都支持 fastboot 协议或 download 模式,并支持对设备的持久性存储分区进行写入或者不刷入设备zhijie启动临时系统
用于存放recovery恢复模式的分区,刷机、root必须要动的分区。里面有一套linux内核,但并不是安卓系统里的那个,相当于一个小pe的存在。现阶段的刷机、root基本都要用第三方rec来覆盖官方rec
recovery 操作系统是一个小型的基于 Linux 的操作系统,包含有各种底层工具的 RAM 磁盘,和一个通过设备硬件按钮操作的小型UI。recovery 系统保存在一个特定的分区中,可以在 bootloader处于 download 模式的情况下刷入一个第三方的 recovery,之后即可替换对于公钥或者关闭签名验证。这样 recovery 就允许主系统被一个第三方操作系统镜像完全替换
引导分区,虽然说是引导,但实际是在bootloader之后,与recovery同级的启动顺序。里面装了安卓的linux内核相关的东西,magisk就是修改了这部分程序,实现的root权限的获取
存放 kernel(以及附带的ramdisk) 的分区
用户数据分区,被挂载到/data路径下。内置存储器(内置存储卡)实际也存在这个分区里,用户安装的apk、app的数据都在这个分区。目前主流安卓版本中data分区通过fuse进行了强制加密,密码一般都是屏锁密码,且加密的data分区未必能在recovery下成功解密,所以有时刷机需要清除整个data分区
缓存分区,一般用于OTA升级进入recovery前,临时放置OTA升级包以及保存OTA升级的一些临时输出文件
主要用于旧Android设备(出厂Android版本 < 7.0
) OTA 升级过程中。出厂版本 Android 7.0以及以上版本设备没有这个分区
系统分区。通常在Android运行时这个分区是挂载为只读的,只有在 OTA升级/官方刷机软件刷机时才会修改其中内容,root 后可以挂载为可写分区并在运行时任意修改其中内容
/system/app:ROM 预装的系统 app
/system/priv-app:ROM "私有的"预装的系统 app
数据(userdata
)分区,即手机的内置存储(Internal Storage
)物理分区
数据(userdata)分区里面包括:
/data/app:用户安装的 App
/data/app-private:部分 app 位于这里
/data/data:所有 App 的数据
/data/media:内置存储(Internal Storage),包括设备每个用户的 /sdcard
/data/dalvik-cache:Dalvik / ART Cache(某些手机里这是一个独立物理分区)
/radio:基带(baseband) 分区
/vendor:通常和 system 一样,也是仅在系统升级时修改。驱动分区,例如相机驱动、音频驱动等
/misc
Uboot 引导内核启动后,内核将负责验证 Android 系统分区,验证通过后将其挂载为只读的系统分区。Android 启动后,modem_control
服务负责校验和加载 modem 子系统的固件
/storage:
存放 Internal Storage / External Storage (包括SD卡) 等挂载点的 tmpfs
/storage/emulated:
所有用户的 Internal Storage 存放路径。实际指向 /data/media
/sdcard:
等效于 Linux 的 ~ 用户根目录。是一个符号链接,实际指向 /data/media/{USER_ID},对于第一个(主)用户,即为 /data/media/0。(注:某些Android <= 5.0 的旧设备 /sdcard 和 /data 是两个不同的物理分区,这些旧设备经常会遇到 /sdcard 和 /data 其中一个可用空间不足的问题)
1)/storage
和 /sdcard
不是实际物理分区:
在 (较新版本)TWRP 里wipe /data
时不会清除/data/media
,因此不影响 /sdcard
里内容。(所以这个 wipe 工作在文件系统层,而不是直接格式化块设备?);而 “format data
”则会格式化整个 /data。TWRP 提供的 “Factory reset
” 快捷操作按钮会重置Dalvik / ART Cache, /cache
和/data
(除/data/media
) 这3个分区内容。(Dalvik / ART cache
实际上也位于 /data 分区里)
除一些小分区外,设备闪存划分为 /system
和 /data
两个主要分区。/system
一般出厂划分1-3GB,剩余的大部分空间都在/data
/system, /data
等各分区大小是设备出厂时固定的。可以在 recovery 里用 fdisk 等工具重新分区以调整各分区大小,但过程十分复杂、与具体设备相关并且具有危险性(错误操作设备会变砖)。少数情况下,某些 OTA 升级包也会调整分区划分
/sdcard
是通常 APP 可见的所谓“外置存储”(external storage
)目录。这里的“外置存储”名字与“内置存储”(internal storage
)相对,其名称来源是因为早期Android设备(小于Android 4.0)自带flash
存储很小(几百MB),所有应用和数据都需要安装在额外插入的SD卡里
如果手机有 SD 卡槽,那么插入的 SD 卡会被挂载为 /sdcard1
。/sdcard
和/sdcard1
都属于“外置存储”,“外置存储”对所属用户完全开放访问权限;APP 访问“外置存储”需要READ_EXTERNAL_STORAGE
或WRITE_EXTERNAL_STORAGE
权限。而 /data 里除 /data/media
以外的其他数据,以及 /data/media
里非当前用户的主文件夹都是系统保护的,不是root无法访问
CPU是手机上面最复杂,最贵的Soc(芯片),担任的也是手机中大脑的位置,是手机跑分性能的决定性硬件。智能手机发展到今天,各大手机CPU厂商也从春秋战国逐渐到了现在四国鼎立的时代(高通,MTK,三星,苹果A系列)。当然最大的CPU厂商还是Intel,只不过intel的主力是在x86架构的处理器,主打PC与服务器产品。而我们今天的主角还是ARM架构的移动端处理器(手机CPU)
手机CPU中的分类:
手机CPU中最主要的一部分,手机的系统运作还有APP的运行,靠的都是AP应用处理器。例如:苹果A9处理器指的就是AP
其实很多玩家都只听过基带这个东西,但不知道这个到底是什么。基带处理器管理的是手机一切无线信号(除了wifi,蓝牙,NFC等等),一款手机支持多少种网络模式,支持4G还是3G,都是由基带部分决定的。BP做的最有名的是高通,其实高通发家靠的就是优秀的BP基带处理器,而不是AP应用处理器
可能大家对高通的BP没有什么印象,这里我就跟大家举几个使用高通BP的手机。iPhone4到iPhone6sp全系列手机都是使用高通的BP(这些手机都是我亲手拆解过的,iPhone3Gs等等我不能肯定是不是高通的BP),还有全部3G版的iPad,加上三星这几年的旗舰也是都是使用的BP,还有大量使用高通CPU的手机产品也都是使用高通的BP
其实每个厂商对CP都有不同的名字,比如苹果把它叫做协处理器,高通820叫做“低功率岛”。在早期CP只用于解码视频和处理音频等等简单任务
但是各大厂商发现,CP的性能其实也可以很高,于是开始处理的东西越来越多。现在的CP已经可以处理虚拟现实,增强现实,图像处理,HIFI,HDR,传感器等等
ARM架构和X86架构的区别:
ARM架构使用的是精简指令集,我们可以把它看成一辆汽车,在之前一直都是低功耗的代名词
X86架构使用的是复杂指令集,我们可以把它看成一架飞机,在之前一直都是高性能的代名词
最开始也是因为低功耗,所以移动端的设备,都是使用的ARM。但是随着移动端的高速发展,ARM架构的处理器的性能也开始变得原来越强大。
比如,一条指令来了,要把一个货物从北京运送到上海,这个时候我们会发现飞机必须快过汽车,但是如果另一个指令是要把一个货物从街头运到街尾了?这个时候,飞机发现,它要想做到基本是不太可能,这个时候只有在增加一条新的指令集(相当于要重新制作一架大小适合的飞机了)
但是随着移动端设备的高速发展,ARM架构的性能已经变得越来越强了,ARM架构的性能超过X86架构已经只是时间问题了
查看CPU是哪个厂商的,输入如下命令:
cat /proc/cpuinfo processor : 0 //系统中逻辑处理核的编号。对于单核处理器,则可认为是其CPU编号,对于多核处理器则可以是物理核、或者使用超线程技术虚拟的逻辑核 vendor_id : GenuineIntel //厂商标识 cpu family : 64 //CPU产品系列代号 model : 79 //CPU属于其系列中的哪一代的代号 model name : Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz //CPU属于的名字及其编号、标称主频 stepping : 1 //CPU属于制作更新版本 microcode : 0x1 //微码 cpu MHz : 2499.996 //CPU的实际使用主频 cache size : 40960 KB //CPU二级缓存大小 physical id : 0 //单个CPU的标号 siblings : 1 //单个CPU逻辑物理核数 core id : 0 //当前物理核在其所处CPU中的编号 cpu cores : 1 //该逻辑核所处CPU的物理核数 apicid : 0 //用来区分不同逻辑核的编号,系统中每个逻辑核的此编号必然不同 initial apicid : 0 //初始逻辑核的编号 fpu : yes //是否具有浮点运算单元(Floating Point Unit) fpu_exception : yes //是否支持浮点计算异常 cpuid level : 13 //执行cpuid指令前,eax寄存器中的值,根据不同的值cpuid指令会返回不同的内容 wp : yes //表明当前CPU是否在内核态支持对用户空间的写保护(Write Protection) flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt //当前CPU支持的功能 bogomips : 4999.99 //在系统内核启动时粗略测算的CPU速度(Million Instructions Per Second) clflush size : 64 //每次刷新缓存的大小单位 cache_alignment : 64 //缓存地址对齐单位 address sizes : 46 bits physical, 48 bits virtual //可访问地址空间位数 power management: //对能源管理的支持
开头说了那么多废话,回到正题。在 Android 操作系统更多是软件的开源平台,但软件的某些方面受到制造商或谷歌的限制。在这方面,OEM Unlock
是重中之重。您可能会喜欢自定义 ROM、内核和植根您的设备,如果您要在任何 Android 手机上解锁引导加载程序,那么首先您必须在 Android 手机上启用 OEM 解锁。OEM 解锁选项始于 2014 年的 Android 5 或棒棒糖(lollipop
)。这是因为谷歌带来的安全原因。由于我们现在处于Android Oreo
和Android Pie
的时代,这也是必须要了解如何启用OEM 解锁的其中一个原因
默认情况下,大多数 Android 设备都附带一个已锁定的引导加载程序,这意味着用户无法刷写引导加载程序或设备分区。如果需要,你(以及启用了开发者选项的设备用户)可以解锁引导加载程序来刷写设备新映像
OEM 解锁现在是隐藏在手机中的 Android 安全性的永久部分,但是解锁OEM没有限制。这意味着可以在设置中非常轻松地解锁它。但在此之前,应该知道它是如何工作的,以及为什么我们需要在 Android 手机上解锁 OEM。如果想安装 ROM、 root手机和解锁引导加载程序,OEM功能是我们要进行下一步操作的第一步
如需解锁引导加载程序并允许重新刷写分区,可在设备上运行fastboot flashing unlock
命令。设置完毕后,解锁模式会在重新启动后保留
除非 get_unlock_ability
设置为 1,否则设备应拒绝 fastboot flashing unlock
命令。如果设为 0,用户需要启动进入主屏幕,打开设置 > 系统 > 开发者选项菜单,然后启用 OEM 解锁 选项(将 get_unlock_ability
设置为 1)。设置完成后,此模式在系统重新启动和恢复出厂设置后将保持不变。
注:发送 fastboot flashing unlock
命令后,设备会提示用户,警告他们非官方映像可能存在问题。在用户确认收到警告后,设备应恢复出厂设置,以防止未经授权的数据访问。即使引导加载程序无法正确对设备执行重新格式化,也应重置设备。只有在恢复出厂设置后,才能设置持久标志,以便重新刷写设备。
所有尚未覆盖的 RAM 都应在 fastboot flashing unlock
过程中被重置。此措施可防止出现读取上次启动剩余 RAM 内容的攻击。同样,解锁的设备应在每次启动时清除 RAM(除非这样做会造成不可接受的延迟),但应保留供内核的 ramoops 使用的区域
注:当然,如需锁定引导加载程序并重置设备,请在设备上运行fastboot flashing lock
命令。打算发布销售的设备应以锁定状态发货(get_unlock_ability
返回 0),以确保攻击者不能通过安装新的系统或启动映像来入侵设备
设备制造商(也称为OEM),一般来说,在开发者选项中基本都有一个名为「OEM 解锁
」的选项。除了少部分流入我国市场的国外运营商有锁机外,此选项基本都可供用户开启
解锁 BootLoader 后会立即清空手机中所有数据,但这也是很多玩机操作必经的第一步,建议尽早开启。解锁 BootLoader 还意味着手机等私密设备的安全性大大下降,不少厂商也会在解锁政策上附加上不少条款
顾名思义,BootLoader是操作系统在启动之前需要执行的一段小程序(通过这段小程序,可初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备)。在系统上电时开始执行,主要功能是初始化硬件设备、准备好软件环境,最后调用操作系统内核。BootLoader
种类比较多,常见的X86上的有LILO、GRUB,ARM
架构上比较有名的是U-boot、VIVI
。以及其他的RedBoot/Etherboot
等
注:在嵌入式系统中,通常没有像BOIS那样的固态程序,因此整个系统的加载启动任务就有bootloader来完成,bootloader程序通常安排在嵌入式系统最开始运行的地址处0x0000 0000
bootloader的作用主要包括RAM的初始化(存储易失性数据),串口初始化、设备类型检测、内核参数链表设置、initramfs(基于RAM的初始文件系统)加载及内核镜像调用等(简单地来说就是,bootloader:主要功能是对硬件环境进行初始化、更新固件及认识操作系统的文件格式并将内核加载到内存中去执行)。BootLoader
通过板机支持包(BSP)初始化硬件驱动。简单的说,bootloader和PC的BIOS在启动时的作用是一致的。ARM、MIPS架构架构中常见的bootloader包括redboot、u-boot及barebox等。在bootloader启动内核后,文件系统也就完成了加载过程
注:虽然,Android系统是开源的,但是设备制造商为了保证系统的稳定性,以及维护自身某些方面的利益,并不希望用户更换为其它厂商的ROM。因此,通常各家设备制造商都会对BootLoader进行加锁。在设备BootLoader处于锁定状态时,无法对ROM进行更改,不能进行root操作,也无法刷机为别的ROM。而要解除这些限制,就需要对BootLoader进行解锁
软件层面的攻击对应着设备构成中bootloader和固件的软件部分,它主要包括以下五个方面:不安全的bootloader、不安全的操作系统、固件敏感信息泄露、不安全的应用服务、不正确的配置策略
因为bootloader是一段在设备运行后加载的代码,因此是一个容易被忽略的攻击点。它的功能是初始化并加载固件,因此当问题出现时它的危险程度很高。例如checkm8这个Boot ROM 漏洞被称为是iphone、ipad、apple TV
和 apple watch
上的史诗级漏洞
引导加载程序logcat日志中的一些常见含义介绍,如下:
关键日志 | 含义 |
---|---|
boot_progress_start | 代表着系统进入用户空间,标志着kernel启动完成,Android屏幕点亮,开始显示启动动画 |
boot_progress_preload_start | Zygote启动 |
boot_progress_preload_end | Zygote结束 |
boot_progress_system_run | SystemServer ready ,开始启动Android系统服务,如PMS、APMS等 |
boot_progress_pms_start | PMS开始扫描安装的应用 |
boot_progress_pms_system_scan_start | PMS先行扫描/system 目录下的安装包 |
boot_progress_pms_data_scan_start | PMS扫描/data 目录下的安装包 |
boot_progress_pms_scan_end | PMS扫描结束 |
boot_progress_pms_ready | PMS就绪 |
boot_progress_ams_ready | AMS就绪 |
boot_progress_enable_screen | AMS启动完成后开始激活屏幕,从此以后屏幕才能响应用户的触摸 |
sf_stop_bootanim | SF设置service.bootanim.exit 属性值为1,标志系统开机动画结束 |
wm_boot_animation_done | 开机动画结束,这一步用户能直观感受到开机结束 |
设备制造商(也称为OEM)
一般来说,在开发者选项中基本都有一个名为「OEM 解锁」的选项。除了少部分流入我国市场的国外运营商有锁机外,此选项基本都可供用户开启
解锁 BootLoader 后会立即清空手机中所有数据,但这也是很多玩机操作必经的第一步,建议尽早开启。解锁 BootLoader 还意味着手机等私密设备的安全性大大下降,不少厂商也会在解锁政策上附加上不少条款
它是设备设置中开发者选项下的一个隐藏选项,它在安全性中也起着重要作用。我们无法在不解锁 OEM 的情况下强制重置设备、擦除所有数据,但擦除数据和强制重置是非常不同的任务
有两种方法可以在各种安卓设备上启用 OEM 解锁:
OEM解锁是什么意思?为防止对设备造成任何意外损坏,Android 设备制造商已锁定引导加载程序。因此,为了解锁 BootLoader 我们必须在 Android OS 的开发人员选项菜单中启用(原始设备制造商)OEM 解锁,此时设备才会允许您安装自定义恢复(例如 TWRP)、使用自定义 ROM 刷新设备、root 设备以及修改内核。设备制造商也是有意隐藏此功能,以防止普通用户意外弄乱自身使用的操作系统
OEM 解锁是 Android 设备附带的隐藏安全功能,以防止任何意外访问,主要用于在任何 Android 设备上启用引导加载程序。首先,要进行解锁引导加载程序之前要先 OEM 解锁。OEM 代表原始设备制造商
当您在开发者选项下打开“OEM Unlock
”开关时,它会将“unlock_ability
”标志设置为:“1”。即使,重新启动设备或执行恢复出厂设置,此标志也会保持不变。除非手动将其关闭,否则此选项将保持启用状态
启用 OEM 解锁允许您自定义 Android 操作系统,并最终允许您解锁智能手机上的引导加载程序。解锁OEM后我们能干什么?
注:通常启用“OEM 解锁”只是在开发者选项中打开一个开关(如果开发者选择中没有OEM解锁按钮,可利用fastboot工具来解锁),但除非您解锁引导加载程序(这是解锁 OEM 后的下一步操作),否则您无法对您的 Android 设备进行任何刷入新的固件等操作。需要注意解锁引导加载程序会使您的设备保修失效,但在Android 5.0 及更高版本中引入了一项新的功能,就是选项按钮开关,这为了防止未经授权的访问解锁引导加载程序。且就算启用此选项也不会使设备的保修失效,但如果继续操作并解锁设备的引导加载程序,那么你的设备保修可能会失效(不同的制造商对引导加载程序解锁有不同的政策,对于大多数制造商来说,解锁引导加载程序就代表着保修失效)
OEM 解锁用于开发目的和安全原因:
OEM解锁的主要原因:是解锁引导加载程序,引导加载程序用于授予对设备的访问权限以对我们的设备进行 Root 或安装恢复和闪存(ROM)
如果您忘记了启用 OEM Unlock 的 Android 密码,可尝试iToolab UnlockGo (Android)
工具。这是一个无需输入密码即可移除任何锁的神奇工具,而且适用于所有 Android 版本和许多品牌的手机,包括摩托罗拉、小米、华为、三星等
iToolab UnlockGo
(Android):Android OEM解锁器
UnlockGo for Android
是一款专业工具,它有助于绕过 FRP 安全功能、图案、PIN 或任何屏幕锁定,然后即可启用 Android OEM
解锁选项。它可以有效地删除密码并节省大量时间,下载地址:https://itoolab.com/android-phone-unlocker/
使用iToolab UnlockGo
删除OEM密码,以便我们开启 OEM 解锁选项的步骤
1)第 1 步:将Android设备连接到 PC
首先,通过 USB 充电线将您的 Android 设备连接到您的 PC。然后,启动 iToolab UnlockGo (Android)
软件并在该工具的主界面上单击解锁屏幕锁定选项
2)第2步:确认Android设备信息
进行下一步操作之前,请从下拉菜单中选择你的 Android 设备的品牌,然后单击解锁按钮
3)第 3 步:将Android设备置于恢复模式
接下来,你将按照屏幕上显示的说明将设备置于恢复模式。这些步骤会有所不同,具体取决于您的 Android 手机上是否有主页按钮
4)第 4 步:完成解锁过程
按照说明绕过 Android 上的锁定屏幕。最后重启你的设备,这将允许你在你的Android设备上设置一个新的OEM密码
一般情况下,Android手机设备商为了防止其设计的界面被人随意更改,会给设备在bootloader上加锁,安装任何系统时需要进行认证,这导致了用户不能够安装第三方的系统,即自定义ROM
首先解锁开发人员选项下的OEM选项:
有些Android 设备上在Android 设备开发者模式中有OEM Unlock
,此时即可进行如下操作解锁bootloader:
OEM Unlock
adb reboot bootloader
安装第三方系统,通常情况下有两种方法:
fastboot oem unlock
对于其它手机,通常情况下可通过更换SPL(Second Program Loader
)的方式来解锁bootloader【进行解锁,部分厂商需要在此附上解锁码】fastboot flashing unlock
fastboot oem unlock
解锁 BootLoader 后会立即清空手机中所有数据,但这也是很多玩机操作必经的第一步,建议尽早开启。解锁 BootLoader 还意味着手机等私密设备的安全性大大下降,不少厂商也会在解锁政策上附加上不少「条款」:三星设备解锁后会永久性熔断 KNOX 安全认证;大部分手机的版权认证 DRM 等级也会从 L1 下降至 L3、无法通过 Play 商店认证等
注:
Android 10(Android Q)
及其以后的安卓版本,除了软件为Debug,还需要解锁,才能开放控制权限Android 9(Android 9)
及其以前的版本,软件为Debug,不需要解锁,就有控制权限ro.oem_unlock_supported
属性应在构建时根据设备是否支持刷写解锁来设置,如下:
ro.oem_unlock_supported
设置为 1ro.oem_unlock_supported
设置为 0如果设备支持刷写解锁,引导加载程序应通过将内核命令行变量 androidboot.flash.locked
设置为 1(如果已锁定)或 0(如果已解锁)来指示锁定状态。在 Android 12 中,必须在bootconfig
而不是在内核命令行中设置此变量
对于支持 dm-verity 的设备,请使用 ro.boot.verifiedbootstate
将 ro.boot.flash.locked
的值设置为 0;如果启动时验证状态显示为橙色,此操作可解锁引导加载程序
不同厂商终端设备出厂时,都存在自定制的OEM,这里以别的作者的分析文章为案例介绍,感兴趣的同学可以移步前往了解
Android平台OEM解锁分析:
oemlock hal:
Android 设备应支持锁定和解锁关键部分(指将设备启动到引导加载程序所需的任何部分)。这些部分可能包括 fuse、传感器中枢的虚拟分区、第一阶段引导加载程序等。如需锁定关键部分,您必须采用一种机制,阻止设备上运行的代码(内核、恢复映像和 OTA 代码等)故意修改任何关键部分。如果设备处于锁定关键部分状态,OTA 应无法更新关键部分
从锁定状态转换为解锁状态应需要与设备进行物理交互。此类交互的效果类似于运行fastboot flashing unlock
命令,但要求用户按下设备上的实体按钮。设备不应允许在没有进行物理交互的情况下以程序化方式从lock critical
状态转换为 unlock critical
状态,并且设备不应以 unlock critical
状态推出
开机后,处理器 ROM 加载程序使用 AHAB 和OTP SRK efuse
中的值验证 U-Boot 和 Trusty OS(引导加载程序映像身份验证概述)。ROM loader 只有在验证成功后才会执行 U-Boot 和 Trusty OS;否则,引导将中止
引导加载程序工件包括 U-Boot 和 Trusty OS。此映像必须在构建后使用PKI(公钥基础结构)树进行签名。请参阅签署引导加载程序映像
公钥的哈希值在设备上的 SRK OTP 位中编程(请参阅保护设备)。这允许 ROM 加载程序验证签名的引导加载程序映像中包含的公钥(请参阅引导加载程序映像身份验证概述)
注:数字签名是一种广泛使用的安全技术,用于确保数据的完整性和签名者的身份验证
片内引导程序(ROM SoC Bootloader
)是在芯片制造时被写入芯片内部只读 ROM 中的一段引导程序,出厂后无法修改,设备上电后最先执行此代码,以小米的MIUI 安全启动过程为例(如下图):
例如小米的设备上电后,片内引导程序执行基本的系统初始化,从 Flash 存储芯片中加载一级引导程序,并利用保存在主芯片内部 Fuse 空间的公钥对一级引导程序镜像的数字签名进行校验,验证成功后运行一级引导程序。随后,一级引导程序加载、校验和执行 TEE OS 镜像,TEE OS 运行起来后,由 TEEOS 和一级引导程序共同校验、加载和执行二级引导程序。以此类推,直到整个系统启动完成,从而保证启动过程的信任链传递,防止未授权程序被恶意加载运行
MIUI 系统的启动过程支持 Android 的 Verified Boot 2.0(AVB2.0)
功能。在设备启动过程中,从受硬件保护的信任根到引导加载程序,再到启动分区和其他已验证分区(包括 system、vendor和可选的 OEM 分区),无论是在哪个阶段,都会在进入下一个阶段之前通过加密认证方式验证代码可靠且没有任何已知的安全缺陷之后才会执行。AVB 有助于防止永久驻留的 Rootkit 恶意软件持有ROOT 权限危害设备,可确保设备在启动过程中的安全性
对于固件验证,最常见的方法是在制造过程中将公钥编程到设备的安全存储器中。安全存储保证公钥不能被更改并且由签名者编程。验证和启动签名固件映像的方案如下所示:
在引导加载程序验证和执行之后,Trusty 初始化“安全环境”和受信任的应用程序(avc、hwcrypto、trusty_gatekeeper
)。Trusty 检查对重放保护内存块 (RPMB) 安全存储的访问,以获取继续启动过程所需的数据
可信执行环境(Trusted Execution Environment(TEE)
, 可信执行环境)安全操作系统,它对代码和数据应用信任级别,保证它们的机密性和完整性。一般而言,TEE 提供了一个执行空间,可为设备上运行的受信任应用程序 (TA) 提供更高级别的安全性。TEE 可以构建一个隔离于主操作系统的小型操作系统,让具有安全、隐私诉求的应用隔离于 Android 系统运行于此。以小米的可信执行环境逻辑架构图,如下:
TEE 所能访问的软硬件资源是与主操作系统分离的,TEE 提供了可信应用的安全执行环境,同时也保护可信应用的资源和数据的保密性、完整性及访问权限。为保证 TEE 本身的可信根,TEE 在安全启动过程中需要通过验证并且与主操作系统隔离。在 TEE 中,每个可信应用是相互独立的,而且在未授权的情况下不能互相访问。TEE 内部 API 主要包含了密钥管理、密码算法、安全存储、安全时钟等资源服务,以及扩展的可信 UI 等
注:可信 UI 是指在关键信息的显示和用户关键数据(如口令)输入时,屏幕显示和键盘等硬件资源完全由 TEE 控制和访问,Android 系统中的软件不能访问
TEE操作系统通常由具有较高特权的内核和具有较低特权的多个应用程序(称为可信应用程序,TA,Trusted Applications
)组成。TA之间彼此隔离,且与TEE内核隔离,此时如果有应用程序被攻陷,它就无法危害到其他应用程序或TEE内核。一个强大的TEE机制可实现下述三类隔离:
为了达到这些安全需求,TEE需要硬件原语的支持,以强制进行隔离。硬件和软件之间的配合是至关重要的,并且需要持续配合
广义上来说,TEE由多个组件组成,具体包括:
Secure Boot
)链,用于初始化TEE软件Trusty 是一个安全的操作系统 (OS),它为 Android 提供了 TEE。Trusty OS 与 Android OS 在同一处理器上运行,但 Trusty 通过硬件和软件与系统的其余部分隔离。Trusty 和 Android 并行运行。Trusty 可以访问设备主处理器和内存的全部功能,但完全隔离。Trusty 的隔离保护它免受用户安装的恶意应用程序和可能在 Android 中发现的潜在漏洞的影响
在 ARM 处理器上,Trusty 依靠ARM Trustzone虚拟化主处理器并创建安全的可信执行环境
为确保Android 设备自身是可信的,设备制造商通常在设备出厂时在 TEE 中预置了设备证书,用于标识该设备的身份,TEE 的公钥统一存储在设备制造商或供应商的服务器中,可以采集设备信息返回给服务器并发起验证,以确定该设备的真实性
HUK(Hardware Unique Key
,设备唯一密钥)出厂时固化在手机主板上,每台手机的 HUK 都不相同且无法被篡改,仅有硬件加密引擎可以访问。HUK 为锁屏密码保护和文件系统加密功能所使用的密钥提供了设备唯一性保证
加解密操作是一个非常复杂的过程,需要强大的计算能力。但对于移动设备而言,速度、节能和安全都至关重要。Android 设备制造商,通常使用的加密引擎的主要算法如下:
3DES
AES-128、AES-256
SHA-1、SHA-256
HMAC-SHA1、HMAC-SHA256
RSA-1024、RSA-2048
ECDSA-256
RPMB
是 eMMC 设备中的一个独立物理分区,专为安全数据存储而设计。对 RPMB 的每次访问都经过身份验证,这允许系统以经过身份验证和重放保护的方式存储或检索数据。在访问 RPMB 之前,开发人员必须编写一个RPMB 身份验证密钥来进行身份校验
VBMeta
在构建过程中由主机使用AVB(Android 验证启动)私钥签名
AVB 密钥的公共部分需要可用于在运行时验证 VBMeta 图像。公钥存储在 RPMB 安全存储中
Trusty访问Replay Protected Memory Block (RPMB)
安全存储以获取AVB(Android 验证启动)公钥并使用它来验证 VBMeta 映像
U-Boot
在跳转到 Linux 内核之前使用VBMeta中的数据验证 Linux 内核(在引导分区中)和设备树(在dtbo分区中) 。它们通过将整个内容加载到内存中然后计算其哈希来验证。该计算的哈希值与预期的哈希值进行比较。如果值不匹配,Android 不会启动
Android 分区表有一个包含 VBMeta 映像的vbmeta分区。此映像包含验证数据(例如加密摘要),用于验证启动所需的 Android 映像(boot、dtbo
和vendor_boot
)
AVB 中使用的中心数据结构是 VBMeta 结构。该数据结构包含许多描述符和其他元数据。描述符用于图像哈希、图像哈希树元数据和所谓的链式分区
vbmeta分区包含:
验证 VBMeta 映像后,其内容用于验证其余启动映像。因为vbmeta分区中的 VBMeta 结构是加密签名的,所以U-Boot
可以检查签名并验证它是由 AVB 密钥的所有者(通过嵌入 AVB 密钥的公共部分)制作的,从而信任用于引导、系统的哈希和供应商
dm-verity
在挂载时检查分区的完整性。来自 Android 文件系统的数据访问将由dm-verity
验证以确保完整性
不适合内存的大型分区(例如文件系统)使用哈希树,其中验证是在数据加载到内存时发生的连续过程。在这种情况下,哈希树的根哈希是在运行时计算的,并根据预期的根哈希值进行检查。如果在某些时候计算的根哈希值与预期的根哈希值不匹配,则不会使用数据并且 Android 会进入错误状态
可信计算技术中最核心的部分,它是一个含有数字签名、身份认证、硬件加密、访问授权、信任链建立和完整性度量hash值存放、密钥管理等可信计算所必须的核心硬件模块,基于对用户身份、应用环境、网络环境等不同底层认证 ,彻底防止恶意盗取信息和病毒侵害,实现可信启动(对系统上电到操作系统启动进行度量,写入度量日志)并解决底层硬件设施的安全问题 。TCM是我国采用自主设计密码算法提出的TPM模块
从2.6.30开始,IMA被引入到Linux内核中,IMA是一个开源的可信计算组件。IMA维护一个运行时度量列表,在有硬件TPM芯片的情况下,能够把此列表的hash完整性度量值固定到TPM里,这样即使攻击能破坏度量列表,也能被发现;即使访问了恶意文件,该恶意文件的度量值(hash值)也会在访问该文件之前提交给TPM,而恶意代码无法删除此度量值(如果没有硬件TPM芯片,理论上来说,还是存在恶意代码不被发现的情况下伪造假的度量列表的可能)
整体上来说,IMA度量、鉴定和证实并不是保护系统的完整性,它的目标是当威胁攻击发生时/后至少能被发现,以便及时处置
注:可以用内核命令行参数开启IMA度量:ima_tcb=1
。默认ima_tcb度量策略是度量可执行文件、mmapped、库、kernel module、firmware和root用户打开的文件。这些度量、度量列表和聚合完整性值可用于证明系统的运行时完整性。基于这些度量,可以检测关键系统文件是否已被修改,或者是否已执行恶意软件。可以通过Linux Security Modules (LSM)
规则自定义设置measure(度量)或dont_measure(不度量)。将自定义IMA策略放在/etc/IMA/IMA policy
中。Systemd启动的时候将自动加载自定义策略;或者通过“cat”自定义IMA度量策略并将输出重定向到<securityfs>/IMA/policy
”。例如:日志文件一般不用度量,可以添加自定义规则:dont_measure obj_type=var_log_t
,这样就不会度量日志文件
TPM+Linux IMA
就构成了可信在Linux操作系统中的落地。下面是框架示意图:基于Linux TPM-IMA
可信计算框架底层实现示意图
系统大概分为三个主要安全目标:
最终期待的主要效果如下:
完整性是最基本的安全属性,没有完整性,真实性或机密性就无从谈起,因为真实性和机密性机制本身可能会受到损害。对于一个文件来说,完整性通常被理解为“不会变”,即一旦安装,文件不会因恶意或意外的修改而变动
从密码学上讲 hash校验可用于检测文件内容是否已变动,比对文件哈希前后是否一致,即可发现文件是否变动。在极端情况下,完整性不仅意味着不会变,而且意味着“不可改变”,任何操作都不能修改文件。例如BSD操作系统具有不可变文件的概念,只能在单用户管理模式下更改
现在流行的Android操作系统也是将其所有系统文件保存在一个分区中,该分区在正常情况下是只读使用,并且只能在引导期间由恢复程序修改。不可变的系统虽然提供了更大的完整性,却难以做到系统组件的正常更新安装或修补。IMA遵循可信计算组(TCG)的完整性开放标准,把hash校验和不可变更机制组合起来用于创建一个新的完整性解决方案。BSD和Android的方法是使文件本身不可变,而TCG的方法是把这些不可变文件的hash值存储在硬件上,如可信平台模块(TPM)、移动可信模块(MTM) 或类似的装置。IMA维护所有被访问文件的hash列表,如果存在硬件安全组件如TPM,即使软件攻击hash列表也不会成功。通过管理平台集中监视、判断、告警它们是否被改变或破坏
真实性是完整性概念的延伸。不仅仅是告诉具有完整性,而且文件的出处也是已知的。例如,我们不仅知道一个文件没有被恶意修改,而且还知道文件是由真实供应商提供的原始文件。简单的hash不足以保证真实性。而数字签名技术能保障文件的真实性, 使攻击者无法伪造出处的证据。通常是公钥签名,如 RSA用于真实性,但也可以使用对称密钥hash,如HMAC
公钥签名的一个优点是,中心机构是唯一必须保护私钥机密性的实体,而所有其他系统只需要保护用于验证的公钥的完整性
公钥签名的缺点是,它们只适用于从不变更的文件,如果文件发生变更,本地系统将无法对其重新签名。而系统上的许多安全关键文件需要不定期变更,因此这些文件实际上只能使用基于本地对称密钥的签名进行保护。用于身份验证的本地对称密钥需要妥善保管,否则攻击者可能盗取本地对称秘钥并用它在恶意文件上伪造本地签名
在Linux中,一个新的IMA鉴定扩展和一个新的扩展验证模块(EVM) 使用对称密钥HMAC 一个文件的数据和元数据,使用本地对称密钥签名的方式来保障可允许更改文件的真实性。对于不希望更改的文件,IMA鉴定签名扩展名将存储一个授权的RSA公钥签名。带有RSA签名的保障文件便不会被允许更改(但仍可被删除)
大家往往误解是加密技术既能做到保密性,又能保护文件的完整性。本质上来说,加密本身并不能保证完整性。比如流密码RC4,它常常被用于无线和互联网(https)通信中的标准加密,但是攻击者还是较为容易在加密流中进行“比特旋转”,使完整性收到破坏
使用块密码的情况下,攻击者也能在文件和会话之间被剪切、粘贴和重放加密块,而且成功率不低。另外加密系统文件会带来很大的性能损失
```Linux kernel``````里已经实现了安全密钥管理机制:
dm-verity
是一个内核扩展,在挂载分区时和运行时运行。但是,Android Verified Boot
进程会在内核加载之前启动。更准确地说,你设备的 ROM 引导加载程序会在加载内核 (boot.img) 之前验证它的完整性,从而防止内核被损坏
Device Mapper verity (dm-verity)
内核功能支持块设备的透明完整性检查。这允许用户确保在启动设备时,它处于与编程时相同的状态。vbmeta分区包含对system、system_ext、vendor
和product分区进行 dm-verity 检查所需的元数据(哈希树描述符:根哈希、盐和 hast 树的偏移量) 。启用 dm-verity 后,任何破坏分区中编程的映像一致性的操作都会导致 dm-verity
检查失败,从而导致系统启动失败
设备在制造时,厂商会做一些加固,包含如下部分:
注:Android启动时对除userdata.img
之外的三个镜像(bootloader.img、boot.img、system.img
)应该进行安全启动,即可检测到系统区域有没有被篡改;userdata.img
是存储用户添加的数据的地方,一般不用进行安全启动
三个镜像(bootloader.img、boot.img、system.img
)应该进行安全启动的镜像中,system.img
在大多数终端中实际上是不安全启动的,原因如下:
boot.img
的 100 倍,在某些情况下可以达到几 GB),因此使用安全启动方法对其进行验证会消耗大量内存资源并对系统启动速度有影响Over The Air
)更新,即更新补丁是在文件级别进行的,更新后的system.img无法保持位级别的身份(文件内容为偶数)如果它们相同,则元数据可能不同),并且无法实现需要完整身份的安全启动为了解决上面说的与 system.img
验证相关的两个问题,从 Android 6.0 作为强制功能引入的技术是“ dm_verity
”。dm_verity 将system.img
划分为每个 4 KB 的块,并以树的形式预先计算出一个由每个块的哈希值组成的“哈希树”。并且通过仅对从此哈希树创建的小元数据 (dm_verity_table
) 的一部分进行安全启动验证,与验证整个 system.img
相比,启动时间在实际时间内,如下图:
另外,Hash Tree
本身在 Android 启动时不会被验证,但是当 Android 运行时加载文件系统时,会动态计算并检查Hash Tree
的完整性,这项功能方便安全人员检测系统篡改
注:在应用 dm_verity
的系统上,由于读取块的哈希验证失败,用户可以检测到恶意软件对 /system 的简单文件重写以及I/O
错误。另一方面,如果恶意软件在假设 dm_verity 的情况下以二进制级别重写与块对应的哈希树,则可以通过在启动时验证根哈希的签名来检测篡改。由此,从Android 6 版本时,便可通过dm_verity
和安全启动,不仅可在Linux内核中验证篡改,还可在Android 系统层验证篡改
信任根是任何现代安全协议的基石。这是一系列严格的制衡,从硬件层面而不是软件层面开始。此功能为设备增加了一定程度的安全性,使其难以受到攻击,因为硬件的可变性不如软件
信任根解决了许多复杂的安全问题,例如:
A/B
系统是在Android N中推出的一个新特性,主要目的是优化OTA升级的过程,实现无缝升级(seamless update
)
在使用A/B
之前,系统的OTA升级过程如下:
/system/etc/security/otacerts.zip
,校验通过后提示用户可以进行升级/cache/recovery/command
中的内容找到OTA包recovery
再次使用公钥/res/keys校验签名值得一提的是,对于开启了dm-verity
校验的文件系统进行文件修改会导致校验失败,也就说在OTA之后设备将无法正常启动;为了解决这个问题需要将file-based OTA
改为block-based OTA
在非AB系统的升级过程中,如果升级失败,则系统无法继续正常启动,解决的唯一办法只有重新升级(线刷或卡刷)。AB系统正是为此而生的。在AB系统中,系统分为两套分区(slot),通常是slot A和slot B。这样的好处是在OTA中无需修改当前slot,以便在升级失败后可以回退到正常可启动的分区。
每个slot都有下面三个属性:
升级过程可以分为以下几步:
payload metadata
,包含OTA的操作指令payload extra data
,对应metadata命令中涉及到的数据,并进行对应更新(支持流式更新)post-install
,即新系统的某个可执行文件,如/postinstall_mount/usr/bin/postinstall
post-install
失败后需要重新尝试其他payload,成功后则将unused slot
标记为active并重启update_verifier
执行dm-verity
验证(在zygote之前),验证成功后将当前slot标记为successful
,完成升级A/B
系统带来的好处不言而喻,可直觉上对每个分区都分成两份似乎造成了很大的空间浪费。由于实施了A/B
分区,也减少了一部分磁盘的开销,比如:
cache
分区A/B
中的boot分区也就相当于以前的recovery分区。以Pixel手机为例,Google给出的实际A/B额外开销只有300多MB,如下所示:
Pixel partition sizes | A/B | Non-A/B |
---|---|---|
Bootloader | 50*2 | 50 |
Boot | 32*2 | 32 |
Recovery | 0 | 32 |
Cache | 0 | 100 |
Radio | 70*2 | 70 |
Vendor | 300*2 | 300 |
System | 2048*2 | 4096 |
Total | 5000 | 4680 |
显然,A/B
系统需要bootloader支持。通常bootloader对于各个Vendor而言是不同的,而且通常是闭源的。Google需要厂商实现HAL接口boot_control
以支持A/B系统,接口文件为:https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/boot_control.h
同时也需要实现bootloader中AB升级相关的状态机:
值得一提的是,system-as-root
并不是只有AB系统能用,非AB系统通过更新分区实现,见 :https://source.android.com/devices/bootloader/system-as-root#about-system-as-root
Android recovery
,是一种Android可以对内部进行修改的模式,可以进行系统的备份、升级或者恢复出厂设置
over-the-air technology
,即空中下载技术,可以实现远程对android 设备进行批量、全量、定向的升级。主要过程分为:申请 ota 升级,下载升级包,校验、安装升级包bootloader control block
启动控制信息块,位于misc 分区,从代码上看,就是一个结构体Android 启动流程大致步骤:
Boot ROM
))开始执行,然后加载引导程序到RAM (该程序指令会将BootLoader程序加载到内存中开始执行)中执行Android kernel
的加载过程与Linux Kernel
加载过程类似,随着内核启动,开始设置缓存、受保护内存、计划列表、调度和加载驱动程序。当内核完成这些系统设置后,它首先在系统文件中寻找”init
”文件(/system/core/init
),然后启动root进程或者系统的第一个进程/sys,/dev,/proc
等文件目录init.rc
脚本。比如解析运行init.rc
中的相关配置,解析init.rc
后主要完成了以下几件事情:
ServiceManager、VndServiceManager
等本地守护服务Native service
启动:在此阶段,会启动Android Native Service
包括 Zygote、sufaceFlinger、media server、bootanimation
等Android 启动的三种模式:
Recov-ery
模式更底层的刷机模式,当手机的系统无法进入恢复模式时,可以通过Fastboot进行重新刷机,恢复设备下图是一个比较粗糙的,各个启动阶段,软硬件组件之间的关系。这只是我接触比较多的一种架构,当然还有别的不同的架构,因为接触得不多这里就不列举了
所有支持 Secure Boot
的 CPU 都会有一个写死在 CPU 中的 bootROM 程序。CPU 在通电之后执行的第一条指令就在 bootROM 的入口。bootROM 拥有最高的执行权限,也就是 EL3。它将初始化Secure Boot
安全机制,加载Secure Boot Key
等密钥、从 eMMC
加载并验证 First Stage BootLoader(FSBL)
,最后跳转进 FSBL 中
bootROM 是完全只读的,这个在 CPU 出厂时就被写死了,连 OEM 都无法更改。bootROM 通常会被映射到它专属的一块内存地址中,但是如果你尝试向这块地址写入内容,一般都会出错或者没有任何效果
有些芯片还会有一个专门的寄存器控制 bootROM 的可见性,bootROM 可以通过这个寄存器禁止别的程序读取它的代码,以阻止攻击者通过逆向 bootROM 寻找漏洞
为了避免使用外部 RAM 芯片,支持Secure Boot
的 CPU 上都会内置一块很小的 RAM,通常只有 16KB 到 64KB (称之为 iRAM)。这块 iRAM 上的空间非常宝贵,bootROM 一般会用 4KB 的 iRAM 作为它的堆栈。FSBL 也会被直接加载到 iRAM 上执行
所有支持Secure Boot
的 CPU 都会有一块很小的一次性编程储存模块 (称之为 FUSE 或者 eFUSE),因为它的工作原理跟现实中的保险丝类似:CPU 在出厂后,这块 eFUSE 空间内所有的比特都是 1,如果向一个比特烧写 0,就会彻底烧死这个比特,再也无法改变它的值,也就是再也回不去 1 了
一般 eFUSE 的大小在 1KB 左右,OEM 从 CPU 厂家购买了芯片,组装了产品后,一般都要焼写 eFUSE 的内容,包括产品的运行模式:测试、开发、生产等。面向终端消费者的产品都会被焼写为生产模式。这个模式下 bootROM 会禁用很多权限,更大面积地限制用户的能力
另外一个很重要的焼写内容就是根密钥了,一般有两种根密钥:一个是加密解密用的对称密钥 Secure Boot Key
,一般是 AES 128 的,每台设备都是随机生成不一样的;另一个是一个 Secure Boot Signing Key
公钥,一般用的 RSA 或 ECC,这个是每个 OEM 自己生成的,每台设备用的都一样,有些芯片会存公钥的 Hash 来减少 eFUSE 的空间使用
只有Secure World
才能访问 eFUSE 的寄存器。除了读写 eFUSE 的基础寄存器之外,还有一些控制寄存器可以禁止别的程序访问 eFUSE,来保护其中的密钥。因此 eFUSE 中的根密钥以及 bootROM 将作为Secure Boot
的根信任
有些 CPU 中还会有一个专门负责加密解密的模块(称之为 Security Engine
)。这个模块也是只有在Secure World
中才能访问。这个模块通常会有若干个密钥槽(Keyslots),可以通过寄存器将密钥加载到任意一个 Keyslot 当中,Keyslot 的加载操作将复盖之前加载过的密钥。通过寄存器操作 DMA 读写,可以使用 Keyslot 中的密钥对数据进行加密、解密、签名、HMAC、随机数生成等操作,但是没有办法从一个 Keyslot 中读取已经加载的密钥值
FSBL 的作用是初始化 PCB 板上的其他硬件设备,给外部 RAM 映射内存空间,从 eMMC 的 GPT 分区上加载验证并执行接下来的启动程序
CPU 通电后执行的第一行指令就是 bootROM 的入口,bootROM 将初始化各种 CPU 内部的模块,但最主要的是,它会读取 eFUSE 上的内容,首先它会判断当前的运行模式是不是生产模式,是的话会开启Secure Boot
功能,然后把 Secure Boot Key
加载到一个 Security Engine
的 Keyslot 当中,有时候它还会通过 Key Derivation
从Secure Boot Key
或别的 eFUSE 内容生成多几个不同用途的密钥,分别加载到不同的 Keyslots 中。然后它会从 eMMC 上加载 FSBL,FSBL 里面会有一个数字签名和公钥证书,bootROM 会验证这个签名的合法性,以及根证书的 Hash 是否和 eFUSE 中的Signing Key
的 Hash 相同。如果验证通过,说明 FSBL 的的确确是 OEM 正式发布的,没有受到过篡改。于是 bootROM 就会跳转到 FSBL 执行接下来的启动程序。有些 CPU 在跳转之前会把 bootROM 的内存区间设为不可见,防止 FSBL 去读取 bootROM。有些 CPU 还会禁止 eFUSE 的读写,或者至少Secure Boot Key
区域的读取权限,来防止 FSBL 泄漏根信任的解密密钥。还有要注意的是,FSBL 是被加载到了 iRAM 上执行的,而且 FSBL 仍然拥有 EL3 级别的权限
FSBL 会进一步初始化 PCB 板上的别的硬件,比如外部的 RAM 芯片等等,使其不再受限于 iRAM 的内存空间。然后它会进一步加载 eMMC 上的内容到 RAM。我们接下来会着重讲讲跟 Secure Boot 密切相关的启动内容
一般 FSBL 都非常靠近 eMMC 的第一个扇区,bootROM 一般不会管 eMMC 有没有用 GPT 分区,而是简单的从第一个扇区读取一些头信息然后直接找到 FSBL 的扇区进行加载的。所以一般我们要做 GPT 分区的话都会放在 FSBL 后面。FSBL 加载一个 GPT 分区也是要跳过 eMMC 前面的非 GPT 扇区再进行加载
从 FSBL 开始我们就要引入 TrustZone 的技术概念了。TrustZone 是 ARM 家的 Trusted Execution Environment(TEE)
实现。相对应的,Intel 家的叫做 Software Guard Extensions(SGX)
,AMD 家的叫做 Platform Security Processor(PSP)
TrustZone 将 CPU 的执行环境划分为了 Secure World
和 Normal World
,Secure World
拥有更高的权限,可以访问 Normal World
的内存、eFUSE 寄存器、Security Engine
寄存器等等。但是 Normal World
中的最高权限却无法访问Secure World
的内存
但是 Normal World
可以通过 SMC 指令调用Secure World EL3
中注册的命令,然后 EL3 程序再将 Normal World
的请求转发给 Secure World
,从而达到两个世界之间的通讯
这是一个运行在 Secure World EL3
权限中的程序,Secure Monitor
的主要作用就是注册 SMC 指令的回调,转发两个世界之间的消息
这是一个通常运行在 Secure World EL1
权限中的内核程序,比较常见的是基于开源的ARM Trusted Firmware
进行扩展修改的,别的实现还有基于 Little Kernel
的,以及一些芯片厂家自己的实现。它的主要作用是给 Secure World
中运行的程序提供一个基本的系统内核,实现多任务调度、虚拟内存管理、System Call 回调、硬件驱动、IPC 通讯等等
这些是在 Secure World EL0
中运行的程序、Daemon。根据不同的 Trusted OS 的实现,TA 的格式、运行模式也会有所不同,比如 ARM Trusted Firmware
的 TA 使用的是 ELF 格式,而高通的 TA 用的是自家的格式
因为 eFUSE 的大小有限,而且不可更改,有些体积比较大的,或者有可能更新的密钥数据,包括像各种 DRM 系统、HDCP、Attestation 等等的密钥,都会用Secure Boot Key
或者一个 Derived Key
进行加密后储存在 eMMC 的一个 GPT 分区上,因此基本上没什么大小限制。FSBL 一般会将这个分区加载到 RAM 中,然后 TA 再通过Security Engine
中已经载入的 Keyslot 对其进行解密获得相应的密钥
SSBL 的作用是给Normal World
做初始化,加载验证并执行Linux/Android
内核。常见的 SSBL 是基于 U-Boot 项目改的,通常这里已经支持像 Fastboot、Recovery boot
等等的常见启动对象了
FSBL 的下一阶段一般包含三个程序:Secure Monitor、Trusted OS、Second Stage Bootloader
。FSBL 会分别从 eMMC 加载验证这些程序,最后跳转到Secure Monitor
执行
Secure Monitor
会初始化 TrustZone 环境,设置 SMC 回调,然后开始执行 FSBL 已经加载好的 Normal World
中的 Second Stage Bootloader
和 Secure World
中的 Trusted OS
Trusted OS
会初始化 Secure World
中的系统内核环境,然后从 eMMC 加载各种 Trusted Applications(TA),认证它们的数字签名,然后执行它们。每个 TA 都会有自己独立的虚拟内存空间。TA 如果要访问特定的硬件,比如 Security Engine
,会在一个描述 TA 的头信息中申请,TA 的签名也会涵盖这部分头信息。Trusted OS
如果同意 TA 访问这些硬件,会把对应的寄存器地址 mmap 映射到 TA 的虚拟内存空间中
Second Stage Bootloader
也就是我们通常说的 Android Bootloader
,它会加载验证然后执行Android Kernel
可以看出来,从 bootROM 到 Normal World
的 Kernel,到 Secure World
的 TA,每一步的加载都是要经过数字签名认证的,而所有这些签名认证的根证书,是要跟 eFUSE 中的 Signing Key
匹配的。这就形成了一个信任链
现代 Android 设备采用了 Verified Boot
技术来保证系统引导的安全性。设备在出厂时附带厂商的公钥,作为信任根(Root of Trust
),在设备启动时,引导加载程序(固化在 ROM 中)会对操作系统的完整性进行检验。被检验的数据包括 boot 分区(Linux 内核和引导所需文件)、system 分区(Android 系统)和 vendor 分区(设备厂商提供的系统文件)等。对于 boot、vendor 等较小的分区,引导加载程序会在引导时进行验证,对于较大的 system 分区,系统会保存其默克尔树(Merkle Tree
),在使用时动态的验证被访问到的部分,如果验证不通过则产生 I/O
错误
Android 引导加载程序往往是被锁定(LOCKED
)的。位于锁定状态下的引导加载程序仅接受厂商在 ROM 中内置的信任根,而拒绝加载未经厂商验证的操作系统,这使得攻击者即使获得物理访问或者 root 权限,也无法对系统进行持久化的修改,因为任何修改都会使得自底向上信任链失效,进而使设备拒绝引导/工作
另一方面,Android 引导加载程序往往允许用户进行解锁。位于解锁(UNLOCKED
)状态下的引导加载程序允许用户自定义被加载的操作系统。一些实现允许用户将自己的公钥作为信任根,并安装自行签名的操作系统;用户也可完全关闭引导验证功能,让引导加载程序加载任何操作系统。攻击者在拥有设备的物理访问后,可通过解锁引导加载程序来修改操作系统,进而完全控制设备并窃取用户数据,考虑到这一安全隐患,引导加载程序在解锁时会清空所有用户数据。同时,为了避免用户的设备在不知情的情况下被解锁并植入恶意软件,已解锁的引导加载程序会在设备启动时显示警告信息,告知用户其设备正在加载自定义操作系统
Android 设备往往使用 Recovery 环境更进行系统更新与还原,该模式位于 recovery 分区中,包含一个由厂商预先写入的小型操作系统,同时,该分区同样受 Verified Boot
的保护。Recovery 模式往往仅接受由厂商验证过的操作系统。为了防止降级以利用旧版本的安全漏洞,有些厂商也会拒绝安装比现有版本更低的操作系统。在解锁引导加载程序后,用户也可替换原有的 Recovery 环境,方便进行自定义操作系统的安装与维护
Android 验证启动(Verified Boot
)实现基于 dm-verity
设备块(device-mapper
)完整性检测目标(target),旨在保证设备软件(从硬件信任根直到系统分区)的完整性。在启动过程中,无论是在每个阶段,都会在进入下一个阶段之前先验证下一个阶段的完整性和真实性。device-mapper
是一个 Linux 内核框架,提供了一个通用方法实现虚拟块设备。它是 Linux 的逻辑卷管理器(LVM)的基础,也可被用来实现全盘解密、RAID 阵列和分布式冗余存储
Android 验证启动(Verified Boot
)是Android一个重要的安全功能,主要是为了访问启动镜像被篡改,提高系统的抗攻击能力,简单描述做法就是在启动过程中增加一条校验链,即 ROM code 校验 BootLoader,确保 BootLoader 的合法性和完整性,BootLoader 则需要校验 boot image,确保 Kernel 启动所需 image 的合法性和完整性,而 Kernel 则负责校验 System 分区和 vendor 分区
由于 ROM code 和 BootLoader 通常都是由设备厂商 OEM 提供,而各家实际做法和研发能力不尽相同,为了让设备厂商更方便的引入 Verified boot
功能,Google 在 Android O
上推出了一个统一的验证启动框架 Android verified boot 2.0
,好处是既保证了基于该框架开发的verified boot
功能能够满足 CDD 要求,也保留了各家 OEM 定制启动校验流程的弹性
device-mapper
的功能本质上是将一个虚拟块设备映射到一个或多个物理块设备上,并可在传输时选择性修改传输数据
设备启动安全级别状态,用绿黄橙红四种颜色表示:
OEM key
认证成功,启动bootloader显示警告和使用的公钥的摘要信息(fingerpring)Device state
设备状态分为:
dm-verity
:Linux 内核驱动,用来作分区完整性检查OEM key
:OEM提供的一个固定的不可被篡改密钥,在bootloader中可见,用来验证boot镜像设备处于“绿色”启动状态时,除了正常设备启动所需的用户互动外,用户应该不会看到任何其他用户互动。设备处于“橙色”和“黄色”启动状态时,用户会看到一条至少持续 5 秒的警告。如果用户在这段时间内与设备互动,该警告持续显示的时间至少会延长 30 秒,或者直到用户关闭该警告。设备处于“红色”启动状态时,该警告会显示至少 30 秒,之后设备将会关机
要实现完整的信任链,需要启动分区上的引导加载程序和软件支持,这个引导加载程序需要完成:
ROOT OF TRUST
在启动分区验证和TEE初始化完成后,引导加载程序会将启动分区签名时的公钥和当前设备状态信息传递给TEE,绑定keymaster信任根
如下内容来自:https://blog.csdn.net/u010206565/article/details/109888855
介绍信任链的时候我们说到,每次加载新的代码或数据之前都需要对其进行验证。对于比较小的分区,如boot或者dtbo,可以直接加载到内存并计算他们的hash,然后将其与预置的hash进行比对。预置的hash通常存放在对应分区文件的头部或者尾部,或者存放在独立的分区中。不论他们的位置在哪,都是会使用信任根进行直接或间接签名的
但是对于较大的分区,比如system分区,实际上包含了整个文件系统,是无法全部读取到内存里的。这时就需要其他的方法,在Android中使用的是hash tree
。当数据加载到内存时,系统就会计算该hash tree
的root hash
,并与预置的root hash
进行比对验证
Dm-verity 使用加密散列树提供块设备的透明完整性检查,每个块以 4k 的大小来划分,都有一个 SHA256 的值。树中的每个节点是加密 hash,其中叶节点包含物理数据块的 hash,并且中间节点包含其子节点的 hash。因为根节点中的哈希是基于所有其他节点的值,所以只有根哈希需要被信任才能验证树的其余部分。对任何一个节点块的改动都破坏整个加密 hash。整个哈希树的结构如图所示:
验证时使用包含在 boot 分区中的 RSA 公钥来执行。设备块在运行时通过计算读取的块的哈希值并将其与散列树中的记录值进行比较来检查。如果值不匹配,则读取操作将导致I/O
错误,指示文件系统已损坏。因为所有的检查都是由内核执行的,所以启动过程需要验证 boot.img
的完整性,以便验证引导工作
在 Android 中被校验的分区始终挂载为只读状态,只能在 OTA 块设备升级时才可做更改。其它任何对分区的操作都会破坏分区的完整性,比如 root 等操作
注:Android 是使用 dm-verity 来保护系统分区的完整性。Dm-verity 使用分区中每个 4KB 块内容的 SHA-256 哈希树。树中的中间节点包含它们下面的节点的哈希值(可能是块节点或其他较低的中间节点),直到根节点,它具有代表整个磁盘的哈希值。该哈希使用来自引导映像的 ramdisk 的密钥进行签名
更多内容请移步(Android 安全架构深究):https://github.com/firmianay/Life-long-Learner/blob/master/Android-Security-Internals/README.md
Dm-verity device-mapper
目的最初是为了在 Chrome 操作系统中实现验证启动而开发的,并且已经在 Linux 内核的 3.4 版本中集成。它使用CONFIG_DM_VERITY
内核配置项来进行开关
但 Android 的具体实现方式和 Chrome 有所不同。用于验证的 RSA 公钥在 boot 镜像的 ramdisk 中,文件名是 verity_key,用于验证目标设备的 root hash
签名。被验证的目标分区,有着一个包含了哈希表和它自身签名的元数据块,被附加到镜像的最后。如果要启用对某一分区的校验,需要在 ramdisk 中的 fstab 文件中对特定设备添加 verify 标签
当系统启动过程中,检测到该标签,则会使用verity_key
公钥加载校验该分区最后附加的元数据。如果签名验证通过,则文件系统管理器解析 dm-verity 映射表,并将其传递给 Linux 设备映射器,设备映射器使用映射表中包含的信息来创建虚拟的 dm-verity 块设备。然后将该虚拟块设备安装在 fstab 中指定的安装点上,代替相应的物理设备。因此,所有读自底层物理设备的数据都会用预先生成的散列树进行透明验证。对设备任何修改或添加文件,甚至将分区重新挂载为读写都会导致完整性验证和I/O
错误。虚拟设备的挂载如下所示:
$ mount | grep system
/dev/block/dm-0 /system ext4 ro, seclabel, relatime, data=ordered 0 0
但因为具体的实现方式原因,用于校验的 RSA 公钥 verity_key,直接被放在了 ramdisk中。这给了替换该公钥文件进行攻击的可能性。而且对目标设备是否进行校验,也直接用明 verify 签进行判断,这也是一个明显的安全缺陷
在谷歌的官方文档描述中,要完全启用verified boot
,除了要配置整个编译系统开启相关选项,还需要引导加载程序实现相关对boot镜像的完整性校验
AOSP 源代码中,开发 key 包括公钥和私钥,它们位 build/target/product/security/
目录。用来给 boot/recovery/system
镜像签名,以及验证 system 分区的真实性元数据块表。在启用 verified boot
时需要生成自己的公私钥,但某些机型设备依然是使用的默认的密钥,这相当于是导致了密钥的泄露,对设备来说没有任何安全性可言了
在介绍dm-verity
之前,先了解其中的dm,即Device Mapper
的作用。Device Mapper
是Linux内核中提供的一个映射框架,可以方便用户程序通过ioctl自行创建和管理设备之间的映射。其中涉及到3个核心元素:
Mapped Device
Target Driver
Target Device
注:
Merkle tree
,系统在初始化的时候只需验证Top Hash
可信,则整个Merkle tree
可信。在块设备上的每个块(通常为4K)被访问的时候,系统验证该块的完整性,不一致则拒绝访问。但要使用基于块(dm-verity
)则必须满足三个条件,如下:
mount |grep data
查看挂载的分区里是否有dm-x的内容,如下:/dev/block/dm-0 on /vendor type ext4 (ro,seclabel,relatime,data=ordered)
或 /dev/block/dm-1 on /vendor type ext4 (ro,seclabel,relatime,data=ordered)
/dev/block/msdadw35 on /vendor type ext4 (ro,seclabel,relatime,data=ordered)
或 /dev/block/msdadw36 on /vendor type ext4 (ro,seclabel,relatime,data=ordered)
vbmeta, boot, system ,vendor
分区等是否在write protect
区间里来判断DM-verity 是否关闭,若在write protect
区间里则是开启,否则就是关闭IMA+EVM
)
dm-verity
)来做的话就只需验证Top Hash
的数字签名即可其中Mapped Device
是创建的虚拟设备,通过Target Driver
描述的映射关系,创建到Target Device
的映射。Target Device
可以是最终的物理设备,也可以是其他的Mapped Device
,也就是说映射关系是可以级联的
BIO是对于块设备的基本IO操作单位,Device Mapper
拓展的核心就是提供了BIO的具体映射,包括线性映射dm-linear,测试映射dm-flakey、dm-error、dm-delay
以及加密映射dm-crypt等等
基于Device Mapper
框架实现的应用有逻辑卷管理器LVM、软件阵列RAID以及Docker(COW)等。当然,dm-verity也是其中一个
dm-verity
的代码在内核中为drivers/md/dm-verity.c
(以Linux4.4为例,在upstream中进行了重构),主要作用是用来验证文件系统中data block
的完整性,主要验证的调用链路如下:
verity_map
verity_end_io
verity_work
verity_verify_io
crypto_shash_final(desc, result)
memcmp(result, io_want_digest(v, io), v->digest_size)
v->hash_failed = 1
当block验证失败后,内核会根据v->mode
选择是打印错误(DM_VERITY_MODE_LOGGING
)还是重启系统(DM_VERITY_MODE_RESTART
)
预置的root hash
则是在mapped device
的构造函数verity_ctr
中传入的,如下所示:
/* * Target parameters: * <version> The current format is version 1. * Vsn 0 is compatible with original Chromium OS releases. * <data device> * <hash device> * <data block size> * <hash block size> * <the number of data blocks> * <hash start block> * <algorithm> * <digest> * <salt> Hex string or "-" if no salt. */ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) { // 处理arg[0-7] ... v->root_digest = kmalloc(v->digest_size, GFP_KERNEL); if (!v->root_digest) { ti->error = "Cannot allocate root digest"; r = -ENOMEM; goto bad; } if (strlen(argv[8]) != v->digest_size * 2 || hex2bin(v->root_digest, argv[8], v->digest_size)) { ti->error = "Invalid root digest"; r = -EINVAL; goto bad; } // ... }
dm-verity将系统镜像切分为4k的块(block)大小,并对每一个块计算hash,这些hash以树状结构组合,称为hash tree
,即哈希树。哈希树中的每个结点都是一个哈希,对于叶子结点值是对应块的hash,对于中间结点其值是所有子结点的hash。因此中间结点所包含的子节点(hash)容量也是一个块,和所采用的hash算法以及对应块大小有关。一个含有32768个块,块大小为4096字节且采用sha246 hash
算法的哈希树结构示例如下:
alg = sha256, num_blocks = 32768, block_size = 4096
[ root ]
/ . . . \
[entry_0] [entry_1]
/ . . . \ . . . \
[entry_0_0] . . . [entry_0_127] . . . . [entry_1_127]
/ ... \ / . . . \ / \
blk_0 ... blk_127 blk_16256 blk_16383 blk_32640 . . . blk_32767
由此可见,任意一个块结点的修改都会导致其hash变化,从而导致root hash
变化,因此验证hash tree
的完整性可以通过验证root hash来实现
在AOSP构建环境中,生成hash tree
的工具为build_verity_tree
,代码在system/extras/verity/build_verity_tree.cpp
$ build_verity_tree -h
usage: build_verity_tree [ <options> ] -s <size> | <data> <verity>
options:
-a,--salt-str=<string> set salt to <string>
-A,--salt-hex=<hex digits> set salt to <hex digits>
-h show this help
-s,--verity-size=<data size> print the size of the verity tree
-v, enable verbose logging
-S treat <data image> as a sparse file
输出verity哈希树镜像文件verity.img
,并在标准输出打印哈希树的root hash
以及使用的salt
Verity Table
也称为dm-verity mapping table
,该映射表包含目标设备的位置、对应hash表的位置、hash tree
的root hash
值和salt等。其值是一个字符串,在AOSP中通过build_verity_metadata.py
脚本生成
$ ./system/extras/verity/build_verity_metadata.py build -h usage: build_verity_metadata.py build [-h] [--signer_args SIGNER_ARGS] blocks metadata_image root_hash salt block_device signer_path signing_key positional arguments: blocks data image blocks metadata_image metadata image root_hash root hash salt salt block_device block device signer_path verity signer path signing_key verity signing key optional arguments: -h, --help show this help message and exit --signer_args SIGNER_ARGS verity signer args
一个完整的verity table
字符串以及每个字段的含义示例如下:
0 417792 verity 1 /dev/sdb /dev/sdc 4096 4096 52224 1 sha256 2aa4f7b7b6...f4952060e8 762307f4bc8...d2a6b7595d8..
| | | | | | | | | | | | |
start| | | data_dev | data_block | #blocks | hash_alg root_digest salt
size | version hash_dev | hash_offset
target hash_block
可以看到从version开始后面的内容和传递到内核dm-verity驱动构造函数中的参数是一致的,在上面有介绍到。每个参数的详细含义除了源码也可以参考内核的文档Documentation/device-mapper/verity.txt
如下内容来自:https://blog.csdn.net/u010206565/article/details/109888855
Verified Boot
中对于不同的磁盘镜像有不同的校验方式。比如对于较小的镜像,如boot、recovery,可以直接加载到内存中进行校验;而对于较大的镜像,比如system、vendor等,则无法一次性载入内存计算hash,因此需要借助dm-verity
实现块级别的校验。下面分别介绍两种类型校验的实现
在Android中基于dm-verity实现可信启动的步骤如下:
verity table
字符串)verity metadata
)这些操作可以用下图来表示:
前3步在上面已经有介绍了,第4步中对verity表签名使用的是RSA-2048算法,公钥在最终烧写在目标机器的根目录下/verity_key。值得一提的是,其私钥在AOSP中的build/target/product/security
目录里,该目录除了包括verity_key,还有testkey、platform、shared、media
相关的key。不同之处是后面4个key使用development/tools/make_key
脚本生成,而verity可以用make_key也可以用out/host/linux-x86/bin/generate_verity_key
生成(需要先编译make generate_verity_key
)
# 生成verity_key.pub
generate_verity_key -convert verity.x509.pem verity_key
mv verity_key.pub verity_key
其中verity.x509.pem
是公钥的x509格式,转换的内部实现摘要如下:
// system/extras/verity/generate_verity_key.c
static int convert_x509(const char *pem_file, const char *key_file) {
f = fopen(pem_file, "r");
cert = PEM_read_X509(f, &cert, NULL, NULL);
pkey = X509_get_pubkey(cert);
rsa = EVP_PKEY_get1_RSA(pkey);
write_public_keyfile(rsa, key_file)
}
verity_key
包含RSA公钥信息,使用的是Android的特殊编码方法android_pubkey_encode
前面说过对于较大的磁盘镜像如system.img
需要通过dm-verity
在运行时访问磁盘block的过程中进行校验,但是对于较小的镜像,则可以直接加载到内存中进行校验。比如boot.img
和recovery.img
。对于二者的签名和校验可以通过boot_signer
工具完成:
$ boot_signer -verify out/target/product/angler/boot.img
Signature is VALID
# 相当于使用verity key进行校验
$ boot_signer -verify out/target/product/angler/boot.img -certificate build/target/product/security/verity.x509.pem
NOTE: verifying using public key from build/target/product/security/verity.x509.pem
Signature is VALID
boot_signer
是一个使用Java写的小工具,其实现代码为system/extras/verity/BootSignature.java
,从代码中可以看到boot.img
的签名是保存在原镜像末尾的
签名数据的格式使用ASN.1
定义如下:
AndroidVerifiedBootSignature DEFINITIONS ::=
BEGIN
formatVersion ::= INTEGER
certificate ::= Certificate
algorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
authenticatedAttributes ::= SEQUENCE {
target CHARACTER STRING,
length INTEGER
}
signature ::= OCTET STRING
END
在verified boot 1.0
中,boot.img
的校验通过其头部的证书和签名信息进行验证。boot镜像中包括ramdisk
文件系统,其中在根目录下就包含了校验其他镜像所用到的/verity_key
。boot.img
由内核进行校验和挂载,内核负责启动其中的init进程
系统启动后通过fs_mgr
对system.img
中的hashtree进行校验(root hash
),获取verity table
,使用其中的信息初始化dm-verity
驱动并挂载镜像,从而实现运行时block级别的校验
如下图所示:
对于AB系统则略有不同,因为boot.img中不再包含根文件系统(而是在system.img
),因此使用内核中的keyring保存verity的公钥信息。而dm-verity
驱动的参数则通过DTB进行保存,DTB可以保存在内核镜像之后,也可以作为独立的镜像文件保存。后续对于system分区的校验则是类似的
注:这里是内核负责获取system镜像的metadata,提取dm-verity参数并初始化dm-verity驱动
如下内容来自:https://blog.csdn.net/u010206565/article/details/109888855
AVB是Android 8
之后对于Verified Boot
的一个参考实现,也称为Verified Boot2.0
。在AVB中一个重要的数据结构就是VBMeta,其中包括了一系列描述符和元信息,并且其中所有的信息都是签名的。描述符包括hash描述符(boot.img、dtbo.img
等小镜像)以及hashtree描述符(system.img、vendor.img
等大镜像)。除了签名,VBMeta中还包含版本信息以及Rollback Index
,从设计上就考虑了降级攻击的安全威胁风险
在大部分AVB实现中,都有一个独立的vbmeta.img
镜像文件,这个文件格式的定义在 external/avb/libavb/avb_vbmeta_image.h
中,截取部分代码如下:
typedef struct AvbVBMetaImageHeader { /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ uint8_t magic[AVB_MAGIC_LEN]; /* 4: The major version of libavb required for this header. */ uint32_t required_libavb_version_major; /* 8: The minor version of libavb required for this header. */ uint32_t required_libavb_version_minor; /* 12: The size of the signature block. */ uint64_t authentication_data_block_size; /* 20: The size of the auxiliary data block. */ uint64_t auxiliary_data_block_size; /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */ uint32_t algorithm_type; ... }
以Pixel 4XL
最新的原厂固件为例进行分析,其中的vbmeta.img
文件如下:
$ head -c 200 vbmeta.img | xxd
00000000: 4156 4230 0000 0001 0000 0000 0000 0000 AVB0............
00000010: 0000 0240 0000 0000 0000 1000 0000 0002 ...@............
00000020: 0000 0000 0000 0000 0000 0000 0000 0020 ...............
00000030: 0000 0000 0000 0020 0000 0000 0000 0200 ....... ........
00000040: 0000 0000 0000 0be8 0000 0000 0000 0408 ................
00000050: 0000 0000 0000 0ff0 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0be8 ................
00000070: 0000 0000 5eb0 ac80 0000 0000 0000 0000 ....^...........
00000080: 6176 6274 6f6f 6c20 312e 312e 3000 0000 avbtool 1.1.0...
00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 ........
使用avbtool工具可以查看镜像的详细信息:
$ avbtool info_image --image vbmeta.img Minimum libavb version: 1.0 Header Block: 256 bytes Authentication Block: 576 bytes Auxiliary Block: 4096 bytes Algorithm: SHA256_RSA4096 Rollback Index: 1588636800 Flags: 0 Release String: 'avbtool 1.1.0' Descriptors: Chain Partition descriptor: Partition Name: vbmeta_system Rollback Index Location: 1 Public key (sha1): 8c44014b96f0f41f3daa3825d4af410233372b65 Prop: com.android.build.product.fingerprint -> 'google/coral/coral:R/RPP4.200409.015/6455311:user/dev-keys' Prop: com.android.build.product.os_version -> '10' Prop: com.android.build.product.security_patch -> '2020-05-05' Prop: com.android.build.vendor.fingerprint -> 'google/coral/coral:R/RPP4.200409.015/6455311:user/release-keys' Prop: com.android.build.vendor.os_version -> '10' Prop: com.android.build.vendor.security_patch -> '2020-05-05' Prop: com.android.build.boot.fingerprint -> 'google/coral/coral:R/RPP4.200409.015/6455311:user/release-keys' Prop: com.android.build.boot.os_version -> '10' Prop: com.android.build.boot.security_patch -> '2020-05-05' Prop: com.android.build.dtbo.fingerprint -> 'google/coral/coral:R/RPP4.200409.015/6455311:user/release-keys' Hash descriptor: Image Size: 34037760 bytes Hash Algorithm: sha256 Partition Name: boot Salt: a5d378a2cf0b56ad731bc531760791a68eda4c11903388d92a872c0610c011fb Digest: f9968f0e26ede13f1e8769163e22a0cb53e747af8ea67915fc6a3ccc4b239744 Hash descriptor: Image Size: 3330722 bytes Hash Algorithm: sha256 Partition Name: dtbo Salt: 7cfa6cab9ee5db15f872b86afc8767b4a440e8d3411096fe5effd3e9ccf3c35b Digest: 215c5440b139eac525ece71f2decfca1c6b553906b188fad12adb2b3048edf3d Hashtree descriptor: Version of dm-verity: 1 Image Size: 1976545280 bytes Tree Offset: 1976545280 Tree Size: 15568896 bytes Data Block Size: 4096 bytes Hash Block Size: 4096 bytes FEC num roots: 2 FEC offset: 1992114176 FEC size: 15753216 bytes Hash Algorithm: sha1 Partition Name: product Salt: 9cc26ca7a5b14b40af3dc0afffd29748a5f56fec335ec3974572ce665d2cb22b Root Digest: 7511feaf0fbc611576daac502cbfc328d931604f Hashtree descriptor: Version of dm-verity: 1 Image Size: 764170240 bytes Tree Offset: 764170240 Tree Size: 6025216 bytes Data Block Size: 4096 bytes Hash Block Size: 4096 bytes FEC num roots: 2 FEC offset: 770195456 FEC size: 6094848 bytes Hash Algorithm: sha1 Partition Name: vendor Salt: 9cc26ca7a5b14b40af3dc0afffd29748a5f56fec335ec3974572ce665d2cb22b Root Digest: dfca98b6e4014f2fe6b3d12402368225c47783b1
从中可以看出vbmeta
中包含了boot、dtbo
镜像的签名,以及product、vendor
镜像的hashtree签名。而system和system_ext的签名信息则保存在vbmeta_system.img
中
在AVB 2.0中,bootloader
必须集成libavb
,负责处理hashtree描述符,并转换为dm-verity
参数。通过将参数写入内核cmdline
启动内核时初始化dm-verity
驱动。/system
的hashtree
描述符可以在/system
中,也可以在/vbmeta
中
bootloader中集成的OEM公钥负责用来校验vbmeta和内核(即boot.img
),随后vbmeta中的其他公钥用于校验对应的分区
除了使用预置的公钥,新版的AOSP也支持设置用户信任根(user-settable root of trust
):
avbtool extract_public_key --key key.pem --output pkmd.bin
fastboot flash avb_custom_key pkmd.bin
fastboot erase avb_custom_key
启动校验流程如下:
Secure Boot
是保障系统完整性和内部软件安全的一个重要屏障,本文主要针对Android智能设备的Secure Boot
实现进行梳理和分析。Android Secure Boot
实现主要有两个版本,一个是Verified Boot 1.0
,另一个是Verified Boot 2.0
,也称为AVB。前者主要通过在镜像末尾添加证书和签名等元信息,而后者将这些信息统一成VBMeta
,并根据实现可置于独立分区中。由于两种不同的分区策略(AB和non-AB
),两种Secure Boot
的具体校验流程也略有不同,但整体大同小异
虽然设计在理论上比较完善,但设备厂商的具体实现也可能存在缺陷,比如使用了错误的秘钥、eFuse不完全、或者bootloader中添加了隐藏的功能等等,这都将导致系统的完整性遭到破坏,从而影响产品的整体安全性。因此,设备厂商也应该遵循合理的安全开发流程,在发版之前由安全工程师进行审计或者使用自动化工具进行测试验证,使系统的信任根和信任链路得以充分安全实现
将备份的vbmeta.img
重新刷入并关闭验证即可:
fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
安全启动其实就是一种常见的 Android 机制,用于防止 Android 设备启动未经批准的软件。与大多数计算机一样,Android 设备有一个非常小的基于 ROM 的主引导加载程序,用于进行基本的硬件初始化,找到一个包含更多引导软件的文件系统,然后加载并跳转到该辅助引导软件
该辅助引导加载程序可能会加载 Android 操作系统,或跳转到另一个引导加载程序,具体取决于所选的硬件和软件。按照惯例,操作系统之前的最后一个引导加载程序通常称为 aboot
Secure Boot
安全机制的原理:旨在将最为核心的安全机制整合到最关键的主 CPU 中。因此就算攻击者可以监听电路板上的线路,甚至拆装个别芯片单独调试,也无法破坏Secure Boot
的安全机制
安全启动的目的:安全启动的根本目的是为了防止消费者从软硬件层面对产品的部分关键系统进行读写、调试等高权限的操作,确保设备仅运行授权和受信任的软件对于最终用户、设备制造商 (OEM) 和运营商等都至关重要,因为OEM 可能希望保护它们的设备免于运行未经授权的软件。不真实的软件可能会降低运营商网络或设备的性能,以及恶意应用程序可能会危害从用户的私人或财务数据到无法挽回地损坏物理设备本身的任何内容,甚至执行不受信任的恶意应用程序存在许多风险和潜在后果(当然,厂家是不会这样宣传 Secure Boot
的,要不然自己的产品咋卖出去?通常它们的文案都是通过这项技术保护用户的隐私,防止恶意软件修改系统软硬件等等。不论文案如何,随着 ARM 架构的广泛授权,基于 TrustZone
的Secure Boot
也越来越普遍了),例如:
注:实施“安全启动”链,旨在确保这些映像中的每一个都未被修改,并且是阻止恶意或危险软件执行的一种方法。安全启动被定义为一个启动序列,其中每个可执行软件映像都由先前验证的软件进行身份验证。此序列旨在防止未经授权或修改的代码运行。我们根据这个定义构建我们的信任链,从第一个用完只读存储器 (ROM) 的不可变软件开始。第一个 ROM 引导加载程序以加密方式验证链中下一个引导加载程序的签名,然后该引导加载程序以加密方式验证下一个或多个软件映像的签名,依此类推(如下图)
上图描述了安全启动序列的示例:操作系统验证的三个映像已通过信任链进行身份验证,该信任链返回到硬件中的第一个 ROM 引导加载程序。此链中的每个图像都已通过锚定到根证书的证书链进行加密验证,根证书也锚定在硬件中。任何将潜在有害代码注入图像的尝试都将被阻止
具有安全启动技术的 Android 手机使用数字证书来确保在操作系统之前加载的软件是可信的。这意味着它由设备供应商进行了数字签名,并以加密方式防止篡改。因此,主引导加载程序不只是找到并运行辅助引导加载程序文件;相反,它会读取辅助引导加载程序并验证数字签名以确保其未被篡改。如果验证失败,则引导过程停止
如下内容来自:https://bbs.pediy.com/thread-260399.htm
Secure Boot
的安全模型建立在消费者是攻击者这一假设上。消费者在物理上拥有产品硬件,可以对产品进行物理连接、拆机、改装等等物理上的操作。可以说跟传统的安全模型中的攻击者相比根本不在一个层面上
消费者作为攻击者的目的,一般常见的有刷机安装自定义的操作系统(Mod)、绕过厂家封闭的支付平台(IAP)和应用商城安装自定义的应用程序、绕过版权保护系统(DRM)达到复制厂家保护的数字产品内容等等。这些操作往往都会直接影响厂家的利益,因此需要一种能抵抗消费者攻击的安全机制
上面提到了,消费者可以直接拆机干涉产品的硬件模块。比如比较专业的消费者甚至可以使用数字示波器监听 CPU 和 RAM 、eMMC 之间的数据传输来读取非常底层的数据传输。如下图所示,我拿某厂的电视盒子的 PCB 拍了张照方便大家理解,如图中圈出来的,CPU 、RAM 、eMMC 都是分开的芯片,中间的连接电路是有可能被监听的,有些研究人员可以焊接极细的导线到电路上,来监听、拦截、甚至篡改不同芯片之间数据的传输
而且像 eMMC 这种芯片通常都是业界标准化的,攻击者甚至可以把芯片拆下来,然后用市面上现成的通用 eMMC 编程工具来读写上面的内容
不过业界还是给攻击者的能力设置了一个上限。这个上限通常是认为攻击者不至于能够剥离芯片的封装,然后用电子显微镜等纳米级别精度的显像设备来逆向芯片的内部结构。或者说能成功攻破芯片安全机制的一次性投资成本至少需要在十万美元以上才可以认为是安全的
Secure Boot
安全机制的原理,就是将最为核心的安全机制整合到最关键的主 CPU 中。因此就算攻击者可以监听电路板上的线路,甚至拆装个别芯片单独调试,也无法破坏 Secure Boot
的安全机制
安全引导是通过每个引导加载程序以加密方式依次验证下一个引导加载程序的签名来实现的,使用证书链,其信任根驻留在硬件中。如果验证在任何步骤失败,则引导过程终止
虽然Secure Boot
可以有效防止未经授权的引导加载程序,但它无法区分不同的授权二进制版本。例如,安全启动无法区分具有已知漏洞的引导加载程序和后来的修补版本,因为这两个版本都有有效的签名。然而,引入可信引导来验证相同的引导加载程序、内核和平台构建即可解决这个问题
一台 Android 设备是由硬件和软件组成,当按下开机键时系统从硬件到软件,在到最后进入 Android 系统,是一个完成的引导过程。以高通为例,在一个常规的引导过程中,CPU 引导芯片代码 PBL(Primary Boot Loader
,类似于 x86 的 BIOS,有时也被成为 BootROM)从预定义的地方(固化在 ROM)开始执行,PBL由高通做好后烧写在芯片中,不可更改,是 RoT(Root of Trust
,信任根)。使用烧录在fuse中的根公钥校验并加载引导程序 SBL1(Secondary Boot Loader
),跳转到 sbl1 执行,SBL1 加载校验 APPSBL(aboot)
,最后 APPSBL 加载校验 boot 分区。内核启动后,会通过内核中的 dm-verity
功能模块校验系统分区的完整性。这样就完成了整个系统的安全引导。整个流程如下所示:
Android 完整性校验过程,分为两部分:
verified boot
,由内核中的 dm-verity
来确保 system 分区没有经过被篡改如下内容来自:https://blog.omitol.com/2017/09/30/Bypass-QCOM-Secure-Boot
这个过程是一个安全认证校验链,都是由上一阶段的程序加载校验下一阶段的要执行的程序,通过签名校验机制,来确保系统不被经过任何形式的篡改,只执行制造商的固件。此过程是特定于设备的,通常通过使用不可更改的特定于硬件的密钥来实现被“烧录”(写入只写存储器)到设备中。该密钥用于验证每级的引导加载程序到最终boot镜像的完整性
高通的 bootloader 是开源项目,在 Android 代码树的 bootable/bootloader/lk
下可以看到它的代码。是针对特定的主板与芯片编写的,并不是Android操作系统的一部分。由于 SBL 代码是闭源代码,分析起来是一个复杂的过程。论文在分析研究引导加载程序的安全引导过程中只从 APPSBL
开始进行分析
BootLoader
是 OEM 厂商或者运营商加锁和限制的地方。当 bootLoader
上锁后就不允许在非解锁状态下对手机固件进行修改或者刷第三方系统。这些限制取决于 OEM 和运营商的具体决策,可能会有所不同,但普遍都会采用密码学的签名校验机制来阻止设备被刷机或者执行未经合法签名的代码。如果用户想要刷机就需要先对 bootloader 进行解锁。现 OEM 都会采用专门的机制,比如需向官方申请解锁码,申请通过后得到解锁码才可以解锁设备。设备解锁后 bootloader 将不再对 boot 和 recovery 分区进行签名校验,也就是不在进行安全引导,允许进行刷机和清除用户数据等操作机制进行解剖分析,以及研究具体的安全保护措施,分析存在的安全缺陷和隐患
从Android 4.4
起,Android 支持使用 Linux 的 Device-Mapper
框架中的 dm-verity
功能进行验证启动。dm-verity
是为块完整性检查而设计开发,使用加密散列树提供块设备的透明完整性检查。它可以验证每个设备块在从磁盘读取时的完整性,如果块检出,则读取成功
如果没有,读取会产生I/O
错误,就好像块被实际损坏了一样。在 Android 中用来保护系统重要分区如 system 分区或 vendor 分区的完整性。系统分区被挂载为只读模式,不再允许被挂载为读写模式。校验系统分区时使用的密钥在 boot 镜像的 ramdisk 中
Secure Boot
功能是负责在SOC启动时验证bootloader 二进制的合法性。BootLoader
二进制是由SOC的Rom Code
启动的
bootloader的合法性认证由Rom Code
实现,那么bootloader认证使用的公钥存储在哪?
Secure Boot
功能完全有SOC硬件实现的,如果设备系统有Secure Boot
需求,首先查看SOC的datasheet
看芯片支不支持这个功能,而市面上从2016年开始的SOC基本都支持Secure Boot
(比如车载信息娱乐系统(IVI) SOC
)
注:Secure Boot
负责校验上电之后运行的第一个用户二进制文件,比如u-boot
如下内容来自:https://blog.omitol.com/2017/09/30/Bypass-QCOM-Secure-Boot
BootLoader 序是一种专门的,特定于硬件的程序,当设备首次通电(ARM 设备复位时)执行。其目的是初始化设备硬件,提供最小的设备配置接口,然后找到并启动操作系统。引导设备通常需要经历不同的阶段,这涉及每个阶段的单独的引导加载程序,本文只分析 APPSBL(aboot)
加载引导程序。Android 引导加载程序通常是专有的,特定于芯片 SoC 的系统。设备和 SoC 制造商在其引导加载程序中提供不同的功能和级别的保护
在整个校验链中由aboot来提供验证 boot.img 的完整性,其开源代码 LK 可在Code Aurora Forum
下载。在 LK 中有两个可用于校验的不同的密钥:
oem_keystore
,被编译到 aboot 中,定义在 platform/msm_shared/include/oem_keystore.h
user_keystore
存储在 keystore 分区中引导过程中始终尝试使用OEM keystore
来验证boot.img 和 recovery.img
。但在 keystore 分区不为空的时候,会使用 OEM keystore
对其签名进行验证,如果验证通过,将从里面读取 user_keystore
,然会用其验证 boot.img 和 recovery.img
user_keystore
包含了用于验证的 RSA 公钥。以 CAF 代码 LA.BR.1.3.2_rb3.14
分支为例,整个基本函数和逻辑执行如图所示:
最终调用的verify_image_with_sig()
采用的是user_keystore
中的公钥进行校验。而 user_keystore
的值由boot_verifier_init
调用 read_oem_keystore
,将
oem_keystore
赋值 user_keystore
。接着对 keystore 分区进行验证,如果验证通过,则将分区中的数据赋值 user_keystore
。这样就完成了对 user keystore
的利用
但是read_user_keystor()
方法中调用verify_keystore
验证 user keystore
时,在if-else
判断中的 385 行因缺少花括号,导致无论验证成功与否,都会user_keystore
进行赋值。具体代码如图所示:
这样就造成了一个明显的安全漏洞,user keystore
不用经过 OEM 的签名也可以用于校验 boot 或 recovery 镜像。我们只需要自己签名生成keystore.img
通过其它漏洞写入手机就可以绕过安全引导机制
在高通的分区表中,有一个名为 devinfo 的分区,大小 1024K。在 app/aboot/devinfo.h
中定义了其数据结构,包括了is_unlocked
解锁状态标记位;is_tampered
篡改标记位等。通过 fastboot oem device-info
命令可以获取相关信息
在 LK 启动时,通 aboot\_init()->read_device_info(&device)->read_device_info_mmc()
读取,若is_unlock
为 true,就跳过校验,允许执行 flash 命令等。使用fastboot oem unlock
命令后,会通过write_device_info_mmc(&device) 对 devinfo
分区的标记位进行操作
高通源代码中并为对该标记位进行加密签名等保护,直接修改标记位就可以使用对手机的解锁。但是在 OEM 的实现中,大多都会对该分区进行保护,修改分区名和使用加密签名等手段,保证分区不被非法篡改
但 Android 系统碎片化的存在,以及厂商技术水平的参差不齐,依然有很多设备未对该部分进行修改,留下了安全隐患
高通有着自己的下载协议,一般在设备生产的时候通过该协议烧录固件。在 lk 代码 aboot_init
中,通过监控按键等操作可以选择到进入到不同的模式,如 recovery 或fastboot 模式等。代码中默认当同时按下音量上下键时,则进入到 DLOAD 模式,也就是下载模式。然后通过高通专有的 sahara 或 firehose 协议工具进行固件的下载更新
同样在 kernel/drivers/power/reset/msm-poweroff.c
中相关代码由宏 CONFIG_MSM_DLOAD_MOD 控制,可开启或关闭是否可以通过 adb reboot edl/dload
命令重启进入到下载模式
高通的升级工具及协议在下载的过程中,并不会对固件进行任何的校验,如果下载了错误或损坏的固件,则直接会让设备变砖。但是,厂商为方便开发、生产、售后等需求,并不会完全关闭掉高通的下载模式,有的会留下隐蔽的接口来进入到该模式
Secure Boot
实现的技术目的 :
trust chain
,保证Android设备加载的Kernel 和Android系统不被篡改rootkit、bootkit
等软件对系统的攻击1)Secure Srom
是安全芯片内部一段电路逻辑,它会在芯片每次启动时被执行,它配合efuse存储的rsa public key
,验证外部存储设备(Nand /Emmc
)上的bootloader 完整性。Secure Brom
的不可被修改性和强制执行,保证了整个安全启动过程
2)Efuse
帮助存储验证使用到的Root RSA public key
。每个厂商保存自己的Root rsa private key
,在量产时候将对应Root rsa public key
刷入到芯片efuse指定区域。Efuse只能一次写入的特性,决定了芯片在量产刷写后,芯片Root rsa public key
就被厂商所控制 ,永远不会被第三方修改。而掌握了Root rsa key
的厂商,就掌握了芯片固件的控制权
3)Crypto engine
提供给固件验证算法支持和加速。目前使用到的硬件加速算法是RSA 非对称解密算法和 SHA数字摘要算法
TrustZone
技术是ARM开发的一种硬件体系结构,它允许软件在安全与非安全的两个域中执行。这是使用“NS”位来进行标识的,这一位可以指示master是在安全模式下还是非安全模式下运行。这里所说的master可以是CPU内核,也可以是硬件外设(例如DMA或加密引擎)。master是否安全,可以在设计中通过硬连线来定义,也可以通过配置定义。例如,可以通过调用SMC指令(稍后详细介绍)或切换SCR寄存器中的NS位来切换CPU内核的安全状态
现代,当我们启动任何设备时,从断电的处理器跳转到运行受信任软件的设备都需要硬件支持。在30 多年前老旧的基本输入/输出系统 (BIOS) 没有提供任何保护(它几乎无法加载操作系统)。从那时起,系统供应商一直在尝试在引导过程中构建更多的安全性。统一可扩展固件接口(UEFI)等行业标准方法奠定了基础并创造了最佳实践
当然,现代的Android 系统也需要同样的保护,最终的目标是确保智能手机运行受信任的软件。在这里有两个组件(为了定义slave(例如外围设备或内存)的访问限制,TrustZone通常包括两个组件,分别是TrustZone地址空间控制器(TZASC)和TrustZone保护控制器(TZPC)),有助于确保Android系统的可信引导进行安全引导,以及通过基于 TrustZone 的完整性管理架构 (TIMA) 进行内核完整性检查
为了定义slave(例如外围设备或内存)的访问限制,TrustZone通常包括两个组件,分别是TrustZone地址空间控制器(TZASC)和TrustZone保护控制器(TZPC)
TZASC可以用于定义DRAM中的安全范围。ARM提供了两种不同的实现方式,最新的是TZC-400。下图概述了其通常情况下在SoC中的实现方式,引自官方技术文档
TZASC概述:
从上图可看出,任何对DRAM存储器的访问都会首先通过TZASC,然后转发给内存控制器。TZASC可以基于一组内部规则来判断是否允许访问内存
TZASC包含一个始终启用的基础区域(区域0),能够跨越整个DRAM内存范围。此外,还定义了许多其他安全区域,可以限制对其的访问。详细来说,在其他区域可以设置以下内容:
TZPC实现了类似的概念,但适用于内部外围设备和SRAM,不适用于外部DRAM。其中包含一个寄存器(R0size),以4KB为单位指定安全分片上SPAM的大小。与TZASC相比,它不太灵活,因为它只允许定义一个安全区域和一个非安全区域,安全区域是从0开始直到指定的大小,剩余的SRAM直接被视为非安全区域
然后,还有很多其他的寄存器,用于为每个外围设备指定其安全性(只能由安全的master访问)。TZPC寄存器中的不同位对应哪些外设并没有定义,并且它是完全针对不同的SoC
通常,TZASC和TZPC的大多数设置都是在初始化期间配置的,并且永远不会更改。但是,其中有一些需要在运行时动态修改。这里的一个示例是用于执行安全付款的可信用户界面(TUI)。以S10手机的三星支付为例,当用户需要输入PIN来授权付款时,TEE将会接管,并直接控制显示屏和触摸传感器。这里的底层逻辑是,由于PIN是一个敏感数据,因此交由TEE来处理整个过程,而不再使用不受信任的Android OS
。因此,必须使用TZPC将显示器和触摸控制器重新配置为“安全”,这样一来,即使是在Android中运行内核级代码的攻击者也无法获取到PIN。要在屏幕中显示图像,需要在DRAM中存储一个安全的帧缓冲区,因此TEE还会使用TZASC将DRAM中的一部分重新配置为“安全”,并将其作为帧缓冲区。在用户输入完PIN后,TZASC和TZPC将其恢复为之前的值,然后Android再次接管
安全和非安全模式之间的转换由名为“安全监视器”(Secure Monitor
)的组件来管理。这个监视器是TEE和REE之间的主要接口,并且是唯一可以修改内核安全状态的组件
与在REE中一样,TEE在内核和TA之间保持用户模式与内核模式之间的隔离。TEE OS
还负责加载TA,并在REE和TA之间传递参数。TA在安全区域的用户空间中运行,并为REE提供服务
ARMv8-A CPU
在每个区域中支持四个特权级别,也将其称为异常级别,分别是:
(S-)EL0
:用户模式/APP(S-)EL1
:内核EL2
:管理程序(Hypervisor)EL3
:安全监视器(Secure Monitor
)在REE中,我们的Android应用程序在EL0上运行,而Linux内核则在EL1上运行
EL2仅以非安全模式存在(在ARMv8.4-A版本之前),称之为管理程序(Hypervisor)。它最初被设计为一种处理以较低特权级别并行运行的多个虚拟环境的方法,但是在Android环境中,通常将其用作内核加固机制。例如在三星手机中也是如此,管理程序组件被称为实时内核保护(RKP,Real-time Kernel Protection
),除了这些用途之外,它还限制了内核可以访问的内存,并将某些内核结构设置为只读,从而增加了内核漏洞利用的难度
最后,来分析安全组件,我们研究的目标是EL3(始终以安全模式运行)、S-EL0和S-EL1。关于TEE的实现方式,有多种方式,但是目前最常见的示例是:在EL3上运行一个非常小的组件,负责在两个区域之间进行切换;在EL1上运行一个成熟的内核;在EL0上运行多个TA。三星的TEE OS TEEGRIS也采用了这样的设计方式
尽管完全隔离的环境非常安全,但在使用的过程中,它还是需要与Android中运行的其他不受信任的组件进行通信。REE和TEE之间的通信使用名为“安全监视器调用”(SMC)的专用指令触发。两个指令都可以在EL > 0
时调用该指令,这意味着Android应用程序无法直接启动与TEE的通信。通常的情况是Linux内核充当代理并公开驱动程序,应用程序可以使用该驱动程序与TEE进行交互。这种设计的优势在于,可以将访问限制策略(例如使用SELinux)应用于访问驱动程序的场景中,以确保只有部分应用程序可以与TEE通信,从而收敛了攻击面。对于S10手机来说,情况也是如此,仅允许有限的应用程序和服务与TEE通信
假设攻击者具有与TEE进行通信的能力。在使用Magisk这样的工具对手机进行root时就是这种情况,或者,也可以获取Linux内核的运行时控制,还可以获取允许与TEE通信的Android应用/服务的运行时控制。一旦执行了SMC指令,就会在EL3中运行的安全监视器中生成一个中断。SMC处理机制会将SMC路由到相应组件。如果监视器可以直接处理SMC,那么就进行处理并立即返回。否则,会将请求转发到TEE内核(在S-EL1运行),然后在其内部进行处理,或者继续将其转发到在S-EL0运行的TA
再回过头来,说说安全启动。安全启动其实就是一种常见的 Android 机制,用于防止 Android 设备启动未经批准的软件。与大多数计算机一样,Android 设备有一个非常小的基于 ROM 的主引导加载程序,用于进行基本的硬件初始化,找到一个包含更多引导软件的文件系统,然后加载并跳转到该辅助引导软件
该辅助引导加载程序可能会加载 Android 操作系统,或跳转到另一个引导加载程序,具体取决于所选的硬件和软件。按照惯例,操作系统之前的最后一个引导加载程序通常称为 aboot
安全启动的目的:安全启动的根本目的是为了防止消费者从软硬件层面对产品的部分关键系统进行读写、调试等高权限的操作,确保设备仅运行授权和受信任的软件对于最终用户、设备制造商 (OEM) 和运营商等都至关重要,因为OEM 可能希望保护它们的设备免于运行未经授权的软件。不真实的软件可能会降低运营商网络或设备的性能,以及恶意应用程序可能会危害从用户的私人或财务数据到无法挽回地损坏物理设备本身的任何内容,甚至执行不受信任的恶意应用程序存在许多风险和潜在后果(当然,厂家是不会这样宣传 Secure Boot
的,要不然自己的产品咋卖出去?通常它们的文案都是通过这项技术保护用户的隐私,防止恶意软件修改系统软硬件等等。不论文案如何,随着 ARM 架构的广泛授权,基于 TrustZone 的 Secure Boot
也越来越普遍了),例如:
注:实施“安全启动”链,旨在确保这些映像中的每一个都未被修改,并且是阻止恶意或危险软件执行的一种方法。安全启动被定义为一个启动序列,其中每个可执行软件映像都由先前验证的软件进行身份验证。此序列旨在防止未经授权或修改的代码运行。我们根据这个定义构建我们的信任链,从第一个用完只读存储器 (ROM) 的不可变软件开始。第一个 ROM 引导加载程序以加密方式验证链中下一个引导加载程序的签名,然后该引导加载程序以加密方式验证下一个或多个软件映像的签名,依此类推(如下图)
上图描述了安全启动序列的示例:操作系统验证的三个映像已通过信任链进行身份验证,该信任链返回到硬件中的第一个 ROM 引导加载程序。此链中的每个图像都已通过锚定到根证书的证书链进行加密验证,根证书也锚定在硬件中。任何将潜在有害代码注入图像的尝试都将被阻止
具有安全启动技术的 Android 手机使用数字证书来确保在操作系统之前加载的软件是可信的。这意味着它由设备供应商进行了数字签名,并以加密方式防止篡改。因此,主引导加载程序不只是找到并运行辅助引导加载程序文件;相反,它会读取辅助引导加载程序并验证数字签名以确保其未被篡改。如果验证失败,则引导过程停止
签名验证和篡改检查是一种标准的公钥基础设施 (PKI) 操作:被验证的文件经过哈希处理,并使用公钥/私钥对对哈希进行签名。例如三星设备,此公钥/私钥对由三星控制,并通过一系列证书到达三星安全启动证书,该证书作为平台硬件信任根的一部分加载
链中的每个引导加载程序,一直到操作系统,都负责验证软件是否已经过数字签名并且不可篡改。一些设备供应商允许禁用安全启动功能,或者是为了开发人员(他们可能需要加载未签名的实验软件),或者是因为他们希望鼓励爱好者运行他们自己的软件和操作系统
安全启动可确保引导加载程序链未被篡改,并由受信任的机构(通常是设备供应商)签名。三星 Knox添加了一项名为 Trusted Boot
的增强功能,它通过在启动过程中拍摄快照并将结果存储在 TrustZone 可信执行环境 (TEE) 中更进一步
受信任的引导的目标是确保作为回滚预防过程的一部分,不能使用可能存在安全漏洞的旧的、受信任的引导加载程序。在系统启动时,TrustZone Trustlets
检查快照。如果他们确定使用了较旧的引导加载程序,则可以阻止某些安全关键操作
Android 原生的 SELinux
特性,对系统中的进程、文件、目录等所有资源的操作均实施强制访问控制,任何进程想在 SELinux 系统中执行操作,都必须先在安全策略配置文件中赋予权限,而访问控制的策略在设备启动过程中会被保护起来,无法被第三方更改。通过 SELinux,可阻止系统进程读写受保护的数据,以及阻止系统进程绕过内核的安全机制或攻击其他进程
UEFI镜像(image)文件:指UEFI二进制文件,如,Grub.EFI
以及Rom.efi
等。UEFI镜像文件中至少包含原始镜像内容。签名过的UEFI镜像文件中,还包含镜像签名信息(AuthData)。镜像签名信息是使用所有者的密钥和证书对原始镜像内容进行一系列密码运算操作生成的一段数字签名数据,用于在加载UEFI镜像文件前,对UEFI镜像文件进行签名验证,以判断UEFI镜像文件是否合法。镜像签名信息至少包括算法标识信息、摘要以及加密后的摘要。算法标识信息包括哈希算法标识和加密算法标识
固件启动方法,包括:在UEFI安全启动过程中,若判断出UEFI镜像文件中不包含镜像签名信息则产生告警
注:简而言之,就是计算受保护文件的摘要值,将其与数据库中的值进行比较,若摘要值不同,说明该受保护文件被修改,则产生告警;若摘要值相同,不做任何操作
判断Android 系统的完整性,包括:
init文件,init.rc文件,system/bin/
下的文件等需要保护的文件指那些不轻易改变的文件;若文件经常改变,系统无法分辨是来自于恶意软件的修改还是系统本身的修改在UEFI安全启动过程中,判断出待加载的UEFI镜像文件是否符合要求(如下),不符合即产生告警
注:镜像加载条件为:UEFI镜像文件的镜像文件类型为指定类型。签名验证条件为UEFI镜像文件的镜像文件类型不为指定类型,且UEFI镜像文件中包含的格式字段为指定格式。指定类型可以为UEFI固件卷(Firmware Volume,FV
)文件。指定格式可以为PE32格式
更多固件启动方法、装置、计算机设备及可读存储介质的内容,请移步:https://patents.google.com/patent/CN114499892B/zh
为避免系统启动时被恶意程序篡改,在统一可扩展固件接口(Unified Extensible Firmware Interface
,UEFI)安全启动过程中,通常采用公钥加密算法(Rivest Shamir Adleman
,RSA)等算法,对UEFI镜像文件进行签名验证,以加载验证通过的UEFI镜像文件,实现UEFI的安全启动,但这种验证方式速度较慢,且影响系统启动速度
UEFI Secure Boot
链可应用于 1987 年制定的Clark-Wilson 完整性策略。 Clark Wilson
模型包括以下概念:
该模型基于经过身份验证的主体、程序和数据项之间的关系。这种关系的元素被称为“Clark-Wilson Triple
”(用户、TP、{CDI}
)。Clark-Wilson
模型显示了满足完整性安全属性所需的规则:(来自Blake)
Clark-Wilson
模型,如下:
名称 | 描述 | 规则 |
---|---|---|
Integrity | 保证只能以受限制的方式修改 CDI 以生成有效的 CDI | C1、C2、C5、E1、E4 |
Access Contro l | 控制对资源的访问的能力 | C3、E2、E3 |
Auditing | 能够确定对 CDI 所做的更改并确保系统处于有效状态 | C1、C4 |
Accountability | 将用户与其操作唯一关联的能力 | E3 |
由于 Clark-Wilson
侧重于职责和交易,因此更适用于业务和行业流程。目前,一些论文描述了如何将Clark-Wilson
完整性模型应用于现有系统,例如Windows、Java或可信计算组 (TCG) 安全性
更多关于UEFI 安全启动链的内容,请移步:
如下内容来自:https://blog.omitol.com/2017/09/30/Bypass-QCOM-Secure-Boot/
前面分析了存在安全缺陷和漏洞。利用自签名的 user keystore
和boot/recovery
镜像,并且在 boot 的 ramdisk中移除对 system 分区的进行校验的 verify 标记。或者替换 ramdisk 中的verity_key,并对 system 镜像进行签名。刷写到手机中,就能实现绕过某些机型的安全引导机制,对设备进行自由修改
但是在设备处于LOCKED
状态时,是无法通过 fastboot 进行刷写操作的。但是 OEM 一般都会预留自己的下载模式,比如三星的 ODIN,联发科的SP Flashtool
。而高通 SoC 的dload/edl
模式,该模式在固件镜像下载过程中并不做任何的校验,直接能刷写进去
案例:测试机器为红米Note3 全网通版,系统的版本为V7.2.3.0
,Android 6.0
版本,内部开发代号 kenzo。Kenzo 在几次的升级后,逐渐关闭了按键进入,adb reboot dload/edl
重启进入下载模式的途经,开启了dm-verity
,来保护手机不被破解和刷机。但是通过IDA Pro
逆向分析 aboot 分区中的 emmc_appsboot.mbn
引导加载程序镜像时,发现了 reboot-edl
的命令。如图所示:
正如其命名一样,是标准fastboot
协议是不支持此命令的,为此需要修改 fastboot 源码。fastboot 源代码在 AOSP 源码树system/core/fastboot
中。分析 fastboot 源码,命令最后是通过fb_queue_command
发送给 bootloader,修改代码添加对该命令的支持。然后就能成功的重启到 edl 模式。核心代码示例如图所示:
整个测试过程是为了验证本文对安全引导机制进行分析研究后挖掘出的相关安全漏洞,达到在设备处于 LOCKED
状态时,篡改并修改设备,绕过 Android 安全引导机制。过程如下:
keystore.img
boot.img
重新打包,移除 system 分区 verify flag
boot.img
进行重新签名fastboot reboot-edl
进入下载模式keystore.img boot.img
若设备能成功开启,则证明完全绕过了 Android 的安全引导机制。System 分区也不在不挂载为虚拟设备,而是真实的物理设备块。如下所示:
$ mount | grep system
/dev/block/sde20 on /system type ext4 (ro, seclabel, noatime, discard, data=ordered)
如下内容来自:https://bbs.pediy.com/thread-260399.htm#msg_header_h1_3
回顾前面定义的威胁模型,如果攻击者的目的是刷自定义 ROM,那至少要同时拿到Normal World
和 Secure World
的 EL1 权限才能勉强让一个自定义 ROM 正常运作。如果攻击者的目的是破坏由TrustZone
保护的 IAP 支付机制,或者 DRM 保护机制,则至少要拿到实现这些保护机制的 TA 的权限才行,也就是至少要拿到 Secure World EL0
的权限
目前接触到的攻击思路,基本上分为两类:Top Down
和 Bottom Up
所谓 Top Down
,就是从最上层的程序,也就是最低级的权限一步步提权,每一次提权就获得更底层一点的权限,慢慢渗透到目标权限层
一个特别适合了解 Top Down 的案例来自 Quarkslab 的 Breaking Samsung’s ARM TrustZone(PDF & GitHub)
这个案例它们假设一开始只有 Normal World 中 EL0
的权限,但是可以自己写程序调用 TrustZone 的 Driver,通过 Driver → Android Kernel → SMC → Secure Monitor → Trusted OS Kernel → Trusted Application
这条线路调用 TA 的相关功能。它们逆向了 TA 的代码,找到了一处 memcpy 越界漏洞,从而拿到了该 TA 的 Secure World EL0
权限
但是这个 TA 的权限有限,他们又通过 Trusted Application → System Call → Trusted OS → Secure Service
的线路调用同是Secure World EL0
,但是有更多 System Call 权限的一个 Secure Service
。他们同样在这个 Secure Service
中找到了一处 memcpy 越界漏洞,从而拿到了更高权限的 Secure World EL0
执行权限
然后,它们发现这个 Secure Service
的其中一个 System Call
是一个任意地址 mmap,而且没有任何限制。于是他们可以直接把Secure Monitor
的物理地址直接 mmap 到 Secure Service
的虚拟地址空间,然后直接改写Secure Monitor
的代码,直接拿到Secure Monitor
所在的Secure World EL3
权限。基本上来说,拿到 EL3 权限,就已经可以做任何攻击者自己想做的事情了
Top Down
的思路需要在各个权限层都能找到漏洞进行利用,可以说难度非常大,而且所有这些都是基于软件上的漏洞,OEM 可以通过系统更新来进行修复。不过大部分厂家没有防回滚机制,所以攻击者可以通过降级刷机刷回一个有漏洞的版本,再进行提权
一种防回滚的操作是每次重大安全更新都烧掉一个eFUSE
比特,然后每个版本的固件都会检查当前烧掉的 eFUSE 比特数是否等于当前的版本号,如果大于的话会拒绝执行,如果小于的话会烧掉相应的比特。如果设备有防回滚机制,攻击者会尽量保持使用旧版固件,然后尽力阻止固件更新
Top Down
的一种捷径是通过Diff
分析对比更新前后固件的变化,找到安全更新修复的漏洞,然后进行利用
对应的,Bottom Up
就是直接找 bootROM 的漏洞。因为 bootROM 是整个信任链的根基,拥有最高的执行权限,如果可以做到Code Execution
,那所有的Secure Boot
保护措施都将形同虚设。而且因为 bootROM 是写死在 CPU 中的,连 OEM 都无法更改,所以一旦可以被利用,厂家将永远无法修复它,只能通过发售新的修复过的硬件来避免它
一个最适合了解Bottom Up
的案例是 Glitching the Switch,这个漏洞几乎同时被好几个研究团队发现,称为 Fusée Gelée
Nintendo Switch
使用的是 NVIDIA 的 Tegra X1 芯片,这款芯片的 bootROM 是不可读的,原理是在 bootROM 即将跳转到 FSBL 的时候,会通过一个专门的寄存器,改变 bootROM 的可读区间,使得大部分的 bootROM 代码变得不可读。这个不论是开发设备还是消费产品都是如此
所以他们攻击 bootROM 的第一步就是要 dump 出来 bootROM 的代码。他们用了一种 Glitching 的手段来做到这一步。Glitching 的硬件原理在视频中有详细介绍,简单来说就是通过在非常精确的时间点,执行微秒级的电压骤变使得 bootROM 在写那个可视性寄存器的时候出现错误,导致 bootROM 没有被不可视化,进而他们可以在一块开发板上用自己写的 FSBL 读取 bootROM 代码
拿到 bootROM 之后他们根据芯片的数据手册和自己的实验,分析出各种寄存器的用途,然后对 bootROM 的 USB 层进行逆向分析。最后他们发现了在一个叫做 RCM 的 USB 模式下,可以通过栈溢出拿到 bootROM 的执行权限
拿到 bootROM 权限之后,他们就可以禁用掉 FSBL 的签名验证,相似的,Secure Boot
接下来的所有环节的签名验证都可以被禁用掉,那基本上就是想干什么都可以了
现在Secure Boot
攻击的 Holy Grail
就是 bootROM 级别的漏洞,因为它最为强大,而且无法被厂家修复。但是 Top Down
的思路在没有 bootROM 级别漏洞的情况下也是一种考虑方式,而且Top Down
的话对每一个 Secure Boot
的组成部件能有更深的了解,作为学习 Secure Boot
来说也是一个不错的选择
安全启动:
注:上面说的BootLoader、文件系统、内核的安全启动固件是否能被篡改,用通用的检测方法都可覆盖检测范围
基于硬件的可信环境解决安全问题,包括:Android 的安全增强功能、实时内核保护(RKP)、基于 TrustZone 的完整性测量架构、基于 TrustZone 的安全性服务、安全启动、可信启动和硬件信任根
注:基于硬件建立一个值得信任的环境,一旦设备开始运行,则对这个环境进行维护,保证它一直处于信任的状态,并在需要的时候,通过证明设备的完整性来检验设备是可以被继续信任的以及将这些数据信息采集回来进行分析
监控系统启动过程。结合操作系统已有的Security boot
等启动流程,对系统启动过程的关键信息和关键过程进行采集,监控操作系统image的完整性和有效性,对异常的数据进行上报
Android 是一个可定制的系统,开发人员可对其进行修改以满足开发的需求。例如,如果有一个已停止更新的旧版 Android,开发者可刷写自定义 ROM 并进行更新
build prop sys.oem_unlock_allowed
根据系统属性的值来做判断,但不是每一个Android设备都是默认的sys.oem_unlock_allowed
属性,不太推荐:
getprop |grep lock
sys.oem_unlock_allowed
该值是否为1参数决定系统是正常启动、还是关机充电状态,排除掉正常状态的值,非正常状态的值一概告警,因为不同厂商系统定义的值都不同,很难全部都概况进来(此方法会有超多误报,不建议使用)
设备状态有如下四种:
检测方法:
system
分区下的文件与数据库中对应的hash
值做对比ID或key
会改变,对唯一的ID或key进行校验检测busybox sha1sum /system/xxx
),和PC上相应文件的hash值做对比即可Android 5.x
以后的机器都支持verity,只要配置verity功能,system分区别篡改后将无法挂载及启动,这个功能是在底层块设备之上加的hash tree来实现的,即每个block
的hash
以tree
形式组织放在system分区尾部
很多Android 用户会Root安卓系统以DIY
自己的手机。在某种程度上,Root后的Android设备可以变得更安全。然而事实并非如此,越来越多恶意软件盯上了使用Android系统的个人和企业,由此引发的安全问题愈发突出。为此,谷歌为使Android 7.0
牛轧糖更加安全添加了一种称为verified boot的新特性,使得系统难以被root
在Android 7.0
牛轧糖系统中,在开机时首先会验证加密完整性是否被篡改;一旦检测到系统文件被篡改(或者是修改过的boot image
),则禁止启动或限定功能。(实际上再Android 6.0时代,系统也会进行完整性检查,只不过那个时候检测到系统被篡改的话,系统只是发出警告)。然而root过程中必须修改系统文件,提升用户权限。如此一来,也就理解了为什么Android 7.0
牛轧糖的Root难度加大了
许多同学都知道,任何想要修改系统内核(操作系统的核心组件)的操作都会被verified boot所察觉。这也带来了一个问题:哪怕这有一个字节的改动也会被verified boot检查到,导致数据丢失
分区验证:
xxx
分区为某特定值时才可以进行解锁,其他值都不能解锁
dump a
分区所有文件,进入刷机模式,flash boot
包到b 分区,设备b 分区为活跃分区,进入刷机模式模式,擦除a 的所有分区,再次拔开进入刷机模式模式,查看活跃分区是bfastboot,cmd
输入命令fastboot flash boot+
文件,可以成功刷到当前的活跃分区中,擦除刚刚刷入的文件,设置b 为活跃分区,fastboot set_active b
,输入上面的adb 命令,可以成功刷入当前的活跃分区即b,再擦除,指定刷到a 和b 两个分区fastboot flash boot_a/boot_b+
文件,都可以成功unlock
设备在fastboot 模式下,可以刷入所有的分区信 息。前提条件:设备为unlock。步骤:把所有的文件dump 出来,然后用fastboot flash
分区名分区文件路径命令刷入可信链: BootROM作为可信根,验证加载第一阶段Boot Loader
(FSBL (First Stage Bootloader)
);
Boot Loader
加载 Trusted OS
和 Trusted OS
中 应用程序,以及 第二阶段Boot Loader
(Second Stage BootLoader
)Boot Loader
加载验证和运行kernel;jetson上 第二阶段Boot Loader
中的验证程序又称为 CBOOT系统启动过程:bootROM → FSBL (First Stage Bootloader) → secure Moniter → Trusted OS →(SSB) Second Stage Bootloader → kernel start
secure boot
,然后从emmc中加载FSBL,并比对与eFUSE中key是否相同,验证FSBL的合法性secure Moniter 、 Trusted OS 、 second Stage Bootloader
是否正常,然后跳转到secure Moniter
执行secure Moniter
初始化secure world
中环境,并从emmc
加载各种TA,并为其映射虚拟内存空间,然后跳转到SSBSecond Stage BootLoader
加载和验证kernel,并且跳转到kernel运行Android设备终端开机启动模式的检测:
Recovery
模式(恢复模式)、或Fastboot
模式(快速引导模式),如果是Recovery
模式(恢复模式)、或Fastboot
模式(快速引导模式)则产生告警frp (Factory Reset Protection) lock
:
Android 5.1
设备默认启用的设备锁,实现 “find my device
” 功能;lock 状态时,如果 factory reset 后会要求输入之前设备登录的 Google 帐号密码,否则就是砖机状态enable oem unlocking
” 会是未选中状态且灰色不可切换根据设备 System 分区挂载来判断是否绕过Android安全引导机制:
# 虚拟设备挂载状态时展示的信息(此时代表 Dm-verity 是正常启用的)
$ mount | grep system
/dev/block/dm-0 /system ext4 ro, seclabel, relatime, data=ordered 0 0
# 真实的物理设备挂载状态时展示的信息(此时代表 Dm-verity 被禁用了)
$ mount | grep system
/dev/block/sde20 on /system type ext4 (ro, seclabel, noatime, discard, data=ordered)
原因:因为,在 Android 7 之后,对分区会进行相应的验证,例如 system 分区,不能之前的版本一样,使用adb root
、adb remount
对 system 分区进行挂载,需要先关闭分区检测功能,所以用 adb disable-verity
来关闭分区检测功能,前提是需要 root 权限
Android 7 版本默认会打开
system verified boot
,对分区会进行相应的验证,即在 userdebug和user版本会把 system 映射到dm-0
设备,然后再挂载。挂载前会检查 system 分区数据完整性,如果 system 分区被恶意修改了,则不允许挂载 system
注:若上传一些文件到设备 system 分区后,就不要再尝试启用 Dm-verity 功能,因为system 分区数据已经发生变化,再次启用后,设备将会无法开机。另外,
adb disable-verity/enable-verity
命令只能在 userdebug 模式下使用。user 版本不支持关闭dm-verity
# 使用 adb disable-verity 来关闭分区检测功能
# 但需要拥有 root 权限
1、adb root 获取root权限
2、adb disable-verity 关闭分区检测功能
3、adb reboot 执行adb disable-verity后需要重启设备
4、adb root 设备重启后再次获取root权限
5、adb remount 使system分区为可读可写模式
根据设备的完整性(可信启动),来检测设备是否被篡改:
引导加载程序是否被篡改的检测:
检测和阻止最常见的内核攻击:
定期内核测量 (PKM)【内核完整性子系统】:
SE for Android
。PKM 保护 Linux 内核代码和数据页面免受恶意攻击,并有助于防止试图禁用SE for Android
的攻击SE for Android
使用的物理内存地址,以确定是否:
SE for Android
已启用SE for Android
处于强制执行模式SE for Android
,或将其切换到许可模式,PKM 会检测到状态变化并报告违规情况,以帮助管理员快速诊断问题SysIntegrity API
检测系统完整性(适用华为系统),例如检测被恶意病毒、木马软件利用root权限植入病毒、篡改用户设备信息和破坏系统等操作:
特性 | 设备类型 | OS版本 | HMS Core(APK)版本 |
---|---|---|---|
系统完整性检测 | 华为手机、华为平板 | EMUI 3.0 及以上 | 4.0.0.300 及以上 |
系统完整性检测 | 非华为手机、非华为平板 | Android 4.4及以上(API Level 19及以上) | 4.0.0.300 及以上 |
应用安全检测 | 华为手机、华为平板 | EMUI 5.0 及以上 | 4.0.0.300 及以上 |
恶意URL检测 | 华为手机、华为平板 | EMUI 3.0 及以上 | 4.0.0.300 及以上 |
恶意URL检测 | 非华为手机、非华为平板 | Android 4.4及以上(API Level 19及以上) | 4.0.0.300 及以上 |
虚假用户检测 | 华为手机、华为平板 | EMUI 3.0 及以上 | 4.0.0.300 及以上 |
虚假用户检测 | 非华为手机、非华为平板 | Android 4.4及以上(API Level 19及以上) | 4.0.0.300 及以上 |
恶意Wi-Fi检测 | 华为手机、华为平板 | EMUI 4.1 及以上 | 4.0.3.300 及以上 |
注:通过构造指定文件的完整性样本库(快照),作为比对标准,当这些文件发生改动时,其对应的校验值也必然随之变化,我们便可识别这些变化从而产生对应告警信息。监控的属性变化主要包括:权限、文件类型、属主、属组、文件大小、创建时间、最后修改时间(文件修改日期)、最后访问时间、增加的大小以及链接数(符号连接),并能够使用SHA1、MD5等算法为每个文件生成校验码。简而言之,通过对系统做快照,记录下HASH值、修改时间、以及管理员对文件做的预处理。这个快照可以让我们建立一个数据库,然后存储到外部设备进行保管。当想要对系统进行一个完整性检测时,只需将之前构建的数据库放置一个到系统可访问的区域,然后将当前系统的状态和数据库进行对比,最后将检测到的当前系统的变更情况报告的数据采集回来到云端并产生对应的告警信息
根据监听设备功能按键要进入fastboot 模式的模式来做检测:
locked
的值出现变化(不同厂商定义内容不同,需自行确认,甚至可能不会在系统系统里面用某个值来判断locked是否解锁)在Android原生系统中该选项显示是:已加密,但在小米,华为等手机上该选项一定是显示:已加密,因为Google把该选项的权限放给了各手机厂家,各手机厂家可以根据自己的要求是否要默认加密手机,通常厂商出厂发售时默认都会做加密。如果手机加密了(即显示手机已加密)用户是不办法取消的,除非BL解锁,那么我们即可通过DE(Device Encrypted
,设备加密)是否被使用来判断设备是否解锁
Android 具有加密文件系统以保护用户数据的功能,Android 加密分为:
Full Disk Encryption
)File-Based Encryption
)全盘加密引入于 Android 4.4
,在 Android 10
中去除。其原理是,系统在初始化时随机生成一个 128 位的主密钥,并使用此密钥与 AES 算法将数据分区(data)加密。当用户设置密码时,主密钥被使用用户设置的密码加密后储存起来(根据设备支持情况,储存在闪存或硬件安全存储中)。当用户修改密码时,主密钥不会改变,所以数据不需要被重新加密
全盘加密有一个缺点 :由于应用程序依赖于数据分区,而在设备启动后,用户第一次输入密码前,设备的数据分区是未被解密的,所以用户无法使用包括闹钟、电话在内的任何功能
为了解决解锁前无法使用任何设备功能的问题,Android 7.0
引入了文件级加密。文件级加密可对每个文件单独进行加密,并且支持对不同文件使用不同的密钥加密。一般来说,文件级加密体系中有 CE(Credential Encrypted
,凭据加密)和 DE(Device Encrypted
,设备加密)两个密钥,前者用于加密用户的大部分数据,后者用于加密需要在解锁设备前访问的数据。CE 所用的密钥被以类似于全盘加密主密钥的形式加密存储,DE 所用的密钥被直接存储。应用程序可以选择其存储的特定数据使用 CE 还是 DE 进行加密,例如闹钟应用程序可将设定的闹钟列表存储在 DE 中,在设备启动后解锁前即可工作。而安全敏感的数据,如 Google 账户凭据则存放在 CE 中,仅在用户解锁设备后可访问
注:可通过DE(Device Encrypted
,设备加密)是否被使用来判断设备是否解锁了
SafetyNet Attestation API
是一种反滥用 API,可以让应用开发者评估运行其应用的 Android 设备。该 API 应该用作滥用检测系统的一部分,以帮助确定您的服务器是否与在真实 Android 设备上运行的真实应用互动。
SafetyNet Attestation API
提供采用加密签名的证明,用于评估设备的完整性。为了创建证明,该 API 会检查设备的软件和硬件环境,以查找是否存在完整性问题,并将相应数据与已获批 Android 设备的参考数据进行比较。生成的证明会绑定到调用方应用提供的 Nonce。该证明还包含生成时间戳以及发起请求的应用的元数据
最可靠的解决方案是使用SafetyNet Attestation
。但是,这不会检测到所有引导加载程序解锁(例如,未检测到运行 Magisk 的我的 Nexus 6)。此外,您可能会因为其他原因导致设备出现故障,例如作为模拟器、运行自定义 ROM、被 root、API 挂钩,甚至只是拥有未经 Google 认证的手机
注:比如说各种游戏和银行应用。其中有相当数量都使用了Google提供的SafetyNet API。它的“基本完整性”检查会检测设备的BootLoader是否被解锁,SafetyNet API
它是Google官方用于检测设备固件是否被修改。刷过机的玩家应该都知道,解了锁的BootLoader才能允许玩家刷入经过修改的各种Recovery、内核
如果您对保证引导加载程序被解锁的情况感兴趣,请使用 SafetyNet Attestation API
并查看建议字段。如果 API 检测到未锁定的引导加载程序,{"advice": "LOCK_BOOTLOADER"}
将出现在令牌中。请注意,在正常使用情况下,不会有建议字段
可通过SafetyNet Attestation API
来判断引导加载程序是否已解锁,官网详细介绍:https://developer.android.com/training/safetynet/attestation
注:对于国内这些OEM厂商来说,要想预装谷歌服务,必须通过谷歌的GTS验证
如下这些情况无法使用SafetyNet验证:
出于增加安全性的考虑,Google 推出了 SafetyNet 这样的检测,以确保 Android Pay
等一些 App 的安全运行
所谓SafetyNet检测,就是谷歌开发的一套Root机制检测程序,通过检测系统是否被篡改而判断环境是否安全的方式
已知港澳台和国外的所有银行客户端,以及某些在Play Store
上架的手游均使用到了SafetyNet
检测。至于中国境内的银行的Root检测,因为没办法使用谷歌服务,无法进行SafetyNet
检测,因此绕过其检测相对绕过SafetyNet
要容易的多
已知英国Barclays银行客户端使用了三组Root检测机制:
首先说说OEM锁,Android 设备应支持锁定和解锁关键部分(指将设备启动到引导加载程序所需的任何部分)。这些部分可能包括 fuse、传感器中枢的虚拟分区、第一阶段引导加载程序等。如需锁定关键部分,您必须采用一种机制,阻止设备上运行的代码(内核、恢复映像和 OTA 代码等)故意修改任何关键部分。如果设备处于锁定关键部分状态,OTA 应无法更新关键部分
从锁定状态转换为解锁状态应需要与设备进行物理交互。此类交互的效果类似于运行fastboot flashing unlock
命令,但要求用户按下设备上的实体按钮。设备不应允许在没有进行物理交互的情况下以程序化方式从lock critical
状态转换为 unlock critical
状态,并且设备不应以 unlock critical
状态推出
再来说说Trusted Boot
和TrustZone
这些必要的保护措施,但一旦 Android 运行,安全启动和可信启动过程就会停止。检查 Android 本身的完整性由称为设备映射器验证 ( dm-verity) 的内置 Android 功能处理,该功能在非常低的级别提供完整性检查。例如三星的 dm-verity
版本包括一些增强功能,使运营商更容易使用固件无线更新在设备上修补 Android
比如三星的 TIMA (三星智能手机通过一系列三星专有的安全功能超越了基本的 Android 检查,这些安全功能为 Android 添加了完整性检查,称为 TIMA) 在 TrustZone TEE 内运行,该 TEE 提供多种安全服务,包括认证、可信用户界面、KeyStore、客户端证书管理以及 TIMA 实时保护的两个组件:实时内核保护( RKP)和周期性内核测量(PKM)
PKM
PKM 是一种被动检查,它是在 TrustZone TEE
中运行的软件,无论是否有任何东西试图触及 Android 内核。PKM 定期检查内核以检测代码或数据是否已被恶意软件修改。PKM 还检查 SE for Android 使用的关键数据结构的完整性,以检测禁用这些安全检查的尝试
RKP 是一种主动安全检查,旨在阻止篡改内核。使用 RKP,可以在 TrustZone TEE 中拦截和检查关键内核事件。可以阻止或记录影响内核的事件以指示可疑的篡改。篡改警报可用于移动设备管理(MDM) 和企业移动管理(EMM) 软件,这意味着检查这些日志是具有安全意识的 IT 经理的一项关键任务
假设Android 设备在TrustZone TEE
的受保护状态下运行。RKP 会试图阻止篡改;如果有任何东西通过 RKP 或绕过 RKP,那么 PKM 可以阻止它。无论哪种情况,当检测到安全问题时,都可以在安全运营平台中看到相对应的威胁告警
Android 设备借助通过TrustZone TEE
进行的被动和主动完整性检查,以及Trusted Boot
技术,Android 设备会具有强大的硬件辅助安全设置,可为当今的企业创建易于部署和受保护的硬件
可信启动的一个核心思路就是在当前启动代码加载下一级代码之前,对所加载的代码进行完整性校验,并且使用PKI公钥基础设施进行核实。这些启动代码通常可以分为若干个阶段(stage),例如在ARM中有:
内核 -> init -> …
实际上每个启动阶段还会进行细分,但这里的重点是需要清楚信任链的作用是在每一阶段代码加载执行下一阶段代码时都会进行验证
信任链的作用是对下一阶段要执行的代码进行校验,那么就会回归到一个问题:最初的代码由谁来校验?其实上面有提到,最初的代码即BL1的代码,是保存在BootROM中,出厂烧写后不可修改的。因此BootROM代码需要尽可能简单,只需要进行必要的初始化操作。
这样一来,信任根就变成了可以烧写BootROM代码的芯片厂商。信任是可以传递的,芯片厂商作为信任根将代码执行权限交给下一级之后,比如OEM厂商,下级代码就拥有了信任链所有权,也就是说下级代码就变成了新的信任根。但是ROM的空间有限,所以通常还使用OTP(One-Time-Programmable
)来保存不同阶段的签名信息。OTP是支持一次性编程的硬件,如多晶硅熔断器(poly-silicon fuses
),烧毁之后无法恢复,从而保证写入后无法被篡改
Android 刷机的几个大步骤:
一般情况下,用户启动Android设备后,引导程序会检查设备是否已解锁以及是否有任何修改的分区。如果设备被锁定且任何分区被修改,设备将无法启动
如果设备已解锁,设备将正常启动,且启动时设备会在分区内验证设备是否已解锁:SECCFG
。此时,启动程序后,分区SECCFG
便不可被读取。由于这个原因,一些变量设置被写入分区 NVDATA,因为系统可以读取分区 NVDATA。这些变量设置包含有关锁定/解锁引导程序的详细信息以及有关开发人员设置和一些敏感数据(如 IMEI、Wifi MAC 和蓝牙 MAC)的许多其他详细信息。因此,我们只需要将未锁定的 SECCFG 与锁定的 NVDATA 混合在一起即可
Windows 步骤:
android-sdk-windows.zip
文件或SDK安装文件,下载链接:https://developer.android.com/studioAndroid Debug Bridge
,就是调试桥。它能够让用户输入指令来操作文件传输,安装APK文件等功能D://android-sdk-windows/tools/
adb devices
,查看设备有那些Android 操作系统更多是软件的开源平台,但软件的某些方面受到制造商或谷歌的限制。在这方面,OEM Unlock
是重中之重。您可能会喜欢自定义 ROM、内核和植根您的设备,如果您要在任何 Android 手机上解锁引导加载程序,那么首先您必须在 Android 手机上启用 OEM 解锁。OEM 解锁选项始于 2014 年的 Android 5 或棒棒糖(lollipop )。这是因为谷歌带来的安全原因。由于我们现在处于Android Oreo
和Android Pie
的时代,这也是必须要了解如何启用OEM 解锁的其中一个原因
fastboot oem enable-charger-screen
fastboot oem disable-charger-screen
$ fastboot oem device-info
(bootloader) Device tampered: false
(bootloader) Device unlocked: true
(bootloader) Device critical unlocked: true
(bootloader) Charger screen enabled: false
(bootloader) Display panel:
OKAY [ 0.015s]
Finished. Total time: 0.016s
fastboot协议是一种通过USB连接与bootloader通讯的机制。它被设计的非常容易实现,适用于Linux、Windows或者macOS等多种平台。fastboot是Android系统提供的一种较recovery更底层的通过USB更新文件系统的方式。
Android开发包提供了fastboot.exe
工具用于与Android系统通信,主要完成分区镜像烧录、分区擦除、设备重启、获取设备状态信息等操作。当需要通过fastboot协议与Android系统交互时,Android系统需要启动到bootloader模式,此时只有最基础的硬件初始化,包括按键、USB、存储系统、显示等模块,以支持分区镜像的写入和系统启动模式的切换
fastboot flashing unlock
fastboot erase {partition}
fastboot erase frp
fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash recovery recovery.img
fastboot flashall
fastboot format data
fastboot flashing lock
fastboot continue
fastboot reboot
fastboot reboot-bootloader
分析fastboot启动模式,要从手机启动过程开始,如下图(Linux Kernel
启动流程),其实fastboot就是在bootloader阶段中运行的:
通常进入Fastboot的两种方式:
adb reboot bootloader
注:Fastboot 是依次判断设备是否锁定,分区是否存在,是否为保护分区,校验通过之后才给手机端发送flash指令
一般情况下,刷机方法是用Recovery来完成的,此处介绍两种比较简单的方法安装Recovery
首先,把recovery放到SDK下tools目录中,并打开cmd且进入adb 所在目录下,以及让手机先进入fastboot
模式。每个设备进入fastboot的方法都由厂商自由设定,所以并不相同。或者,可尝试在cmd中输入进入fastboot模式: adb reboot bootloader
fastboot boot recovery.img
:刷入 boot 内核。直接将recovery放在缓存中,并运行,并不是真正意义上的安装fastboot flash recovery recovery.img
:刷入第三方recovery(TWRP Recovery
)。在手机中其实已经存在了recovery这个分区,将想要刷入手机的recovery覆盖到原有的,是真正意义上的安装
fastboot flash userdata userdata.img
:成功完成以上各文件的刷入后,重启手机即可进入新的系统
reboot system now
:重启手机apply sdcard:update.zip
:通过安装一个名为update.zip的文件刷机,且该文件是放在sdcard的根目录下的apply any zip from sdcard
:通过安装一个名字后缀为.zip的文件来刷机,文件是放在sdcard的根目录下的wipe data/factory reset
:擦除数据/还原至出厂设置,就是把所有的用户使用数据删除
backup/restore
:备份或还原usb toggle
:usb模式,这时手机可以相当与一个u盘,用户可以将sdcard上的数据拷贝出来,或者将需要使用的刷机包放入sdcard中参考链接:
https://orangey.blog.csdn.net/article/details/124602736
https://source.android.com/devices/tech/perf/boot-times?hl=zh-cn
https://source.android.com/devices/automotive/camera-hal
https://blog.csdn.net/manjianchao/article/details/80515191
https://blog.csdn.net/qq_23452385/article/details/113057861
https://www.ytechb.com/enable-oem-unlock-android/
https://itoolab.com/unlock-android/enable-oem-unlock-missing/
https://sspai.com/post/67932
书籍《智能硬件安全》
https://source.android.com/docs/core/bootloader/locking_unlocking
https://blog.men.ci/mobile-security-compare/
https://insights.samsung.com/2019/09/04/samsung-trusted-boot-and-trustzone-integrity-management-explained/
https://www.qualcomm.com/news/onq/2017/01/secure-boot-and-image-authentication-mobile-tech
https://bbs.pediy.com/thread-260399.htm
https://blog.csdn.net/u010206565/article/details/109888855
https://sakura-paris.org/Android
https://blog.omitol.com/2017/09/30/Bypass-QCOM-Secure-Boot
https://evilpan.com/2020/11/14/android-secure-boot/
https://www.modb.pro/db/478501
https://docs.samsungknox.com/admin/fundamentals/welcome.htm
https://www.digi.com/resources/documentation/digidocs/embedded/android/dea11/cc8x/android-trustfence_r_secure-boot-intro
https://security.tencent.com/index.php/blog/msg/38
http://support-cn.samsung.com/Upload/DeveloperChina/DeveloperChinaFile/20190612174302747A417D089B4.pdf
https://trust.mi.com/docs/miui-security-white-paper-global/2
https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/
https://www.riscure.com/blog/samsung-investigation-part1
https://mp.weixin.qq.com/s/dRgkcVayeGvh8SSm8B2a2A
https://cloud.tencent.com/developer/article/1043636
https://patents.google.com/patent/CN114499892B/zh
https://patents.google.com/patent/CN103530559A/zh
https://blog.csdn.net/feelabclihu/article/details/115774916
你以为你有很多路可以选择,其实你只有一条路可以走
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。