Android Verified Boot介绍与有关使用

背景

在搞安卓驱动调试的时候,由于不熟悉,导致系统没有按照我预期启动完毕;因此需要注意这一块的东西。

简介

Verified Boot 是 Android 4.4 开始引入的一个新特性,作用是在系统启动时校验 system 分区是否被篡改。好处在于可以检测到 system “发生过” 改动,比如用户使用 root 软件强行植入 su 文件,但最后删除了 su, 这种情况也能检测出来。一旦检验不过,系统就不能正常启动,并且有相关的图文提示,请参看:https://source.android.com/security/verifiedboot/index.html

Android 6.0 的 CDD 文档,章节 9.10. Verified Boot 对该特性有详细的描述。可知,在出厂搭载 Android 6.0 系统的设备上,如果硬件达到要求,是必须激活这一特性的。请参看:https://static.googleusercontent.com/media/source.android.com/en//compatibility/android-cdd.pdf

启用

在编译系统中开启

在编译系统中开启签名 boot.img 和 recovery.img功能:

build/target/product/verity.mk文件中添加:

PRODUCT_SUPPORTS_VERITY := true

修改device/qcom/msm8996/msm8996.mk文件:

PRODUCT_SPPORTS_VERITY := true

在开启 LK 验证开启

在编译系统中开启 Boot 和 Recovery 功能:

Bootable/bootloader/lk/AndroidBoot.mk文件中:

ifeq($PRODUCT.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY), true)
VERIFIED_BOOT := VERIFIED_BOOT = 1
else
VERIFIED_BOOT := VERIFIED_BOOT = 0
endif

device/OEM/project_name/project_name.mk中添加:

PRODUCT_SUPPORTS_VERITY := truePRODUCT_SYSTEM_VERITY_PARTITION := /dev/block/bootdevice/by-name/system$(call inherit-product, build/target/product/verity.mk)PRODUCT_COPY_FILES += \frameworks/native/data/etc/android.software.verified_boot.xm:system/etc/permissions/android.software.verifie

device/OEM/project_name/fstab.qcom中添加verify标志:

/dev/block/bootdevice/by-name/system /system ext4 ro,barrier=1,discard wait,verify

签名key

默认开发 key

包括公钥和私钥,它们位于:build/target/product/security/. 它们用来给 boot 和 recovery 签名,以及验证 system partition 的 metadata table.

它们的位置定义位于:build/target/product/verity.mk 文件中:

PRODUCT_VERITY_SIGNING_KEY := build/target/product/security/verity

Key 文件

作用说明:

build/target/product/security/verity.pk8
– privatekey used to sign boot.img and system.imgverity.x509.pem
– certificate include publickeyverity_key
– publickey used indm verity forsystem.img

有些老的版本只有两个key文件:

verity_private_dev_key
– privatekey used to sign boot.img and system.imgverity_key
– publickey used indm verity forsystem image

我们可以看到在 build/core/Makefile 文件中:

$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOT_SIGNER)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
$(BOOT_SIGNER) /boot $@ $(PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCT_VERITY_SIGNING_KEY).x509.pem $@
$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))

生成 OEM 自己的公钥密钥对

在 Linux 系统中,确保所安装的 openssl 版本足够新,可以参看: /build/target/product/security_releasekey/README 文件。

openssl versionOpenSSL 1.0.2d 9 Jul 2015
development/tools/make_key mykey ‘/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com’

不用输入密码,然后 mykey.pk8 和 mykey.x509.pem 将会在当前目录生成。

为DM-Verity 功能生成 verity key

生成 generate_verity_key

使用下面的命令来生成 verity key 的工具 generate_verity_key:

source build/envsetup.sh
choosecombo
make generate_verity_key (mmm system/extras/verity/)

将 *.x509.pem 转换成 verity key

generate_verity_key 的代码位于:system/extra/verity/generate_verity_key.c

generate_verity_key 的用法:generate_verity_key | -convert

out/host/linux-x86/bin/generate_verity_key -convert mykey.x509.pem verity_key

拷贝并重命名

拷贝mykey.pk8,mykey.x509.pem,verity_key.pub 至 build/target/product/security/ 目录,将其重命名: verity.pk8, verity.x509.pem,verity_key ,并替换默认的开发 key。

生成 keystore

在 LK 里面,有两个 keystore:

  • oem_keystore: 编译到 LK 里面,它定义在 /bootloader/lk/platform/msm_shared/include/oem_keystore.h 中。
  • user_keystore: 存储在”keystore”分区里面。

    LK 将使用 OEM keystore 来验证 keystore 分区, 如果验证通过, 将从里面读取 user_keystore,然后用其验证 boot.img 和 recovery.img。

Google 已经在后来的 release 里移除 user_keystore,不需要 keystore 分区。

使用system/extras/verity/keystore_signer, 它实际上是调用openssl 的一个脚本,所以也可以直接调用 openssl来实现。

keystore_signer <privatekey.pk8>  <crefificate.x509.pem> <outfile> <publickey0.der>

# 相当于:
openssl rsa -in mykey.pk8 -inform DER -pubout -outform DER -out mypub.der
java -Xmx512M -jar out/host/linux-x86/framework/KeystoreSigner.jar mykey.pk8 mykey.x509.pem keystore.img mypub.der

如果在没有 pk8 格式的老版本上,则可以使用下面的命令:

keystore_signer <PRIVATE_KEY> <KEYSTORE_IMG> <RSA_PUBLIC_KEY_DER>
java -Xmx512M -jar out/host/linux-x86/framework/KeystoreSigner.jar verity_private_dev_key keystore.img mypub.der

通过上述命令获取 keystore.img之后,可以通过fast boot来刷。

当然,如果没有keystore分区,这步可以忽略

Fastboot flash keystore keystore.img

Oem_keystore可以通过下面的方法使用相同的key:

通过下面的脚本将keystore.img生成oem_keystore.h文件

function generate_oem_keystore_h()
{
echo \#ifndef __OEM_KEYSTORE_H
echo \#define __OEM_KEYSTORE_H
xxd -i $1 | sed -e 's/unsigned char .* = {/const unsigned char OEM_KEYSTORE[] = {/g' -e 's/unsigned int .* =.*;//g'
echo \#endif
}

将该oem_keystore.h文件拷贝到:bootable/bootloader/lk/platform/msm_shared/include

在 LK 中的代码调用流程

  • boot_linux_from_mmc
  • boot_verifier_init
  • verify_signed_bootimg -> boot_verify_image -> verify_image_with_sig

手机安全状态

开启 Verified Boot 功能的设备有三种安全状态:locked, verified 和 unlocked。任何状态的转换都需要使用 fastboot 命令,同时也会擦除 /data 分区(分区置0),当手机启动的时候,新的状态才会改变,同时会将一个新的文件系统挂载到 /data。除此之外,安全状态的改变用户通过物理按键(开机键,音量上下键等)的方式来确认,另外,如果是转换到 unlocked 状态,需要在开发者选项者将 OEM unlock 打开(这步需要屏幕锁验证),同时通过 fastboot oem unlock 打开。

locked state

  • 用户不能使用 fastboot 命令下载或者擦除任何分区。
  • boot 和 recovery 分区将会被 keystore 验证 (从 LK 里面的 OEM keystore开始)。
  • 唯一能使用的 fastboot 命令只有 fastboot oem unlock,但如果要使用该命令,还必须在开发者选项中将 OEM unlock打开(默认关闭)。

verified state

  • 用户可以使用 fastboot 命令来下载或者擦除特定的分区(bootable/bootloader/lk/app/aboot/aboot.c中的 critical_flash_allowed_ptn 结构体)。
  • 不允许登记 keystore或者篡改 persisten data block。
  • 对于使用用户或者第三方软件来来,这是个比较合适的状态,特别是开发者需要频繁地烧写软件。
  • 如果使用了没有被OEM签名的 keystore,那需要处理开机时的警告信息。

unlock state

  • 所有的 fastboot 命令都可以使用。
  • 用户 keystore 可以被登记或者擦除。
  • 在这种状态下,boot和recovery不会被验证。同时开机时会有警告,需要按音量上键才能继续启动。

影响

  • 软件集成和 OTA 升级,必须使用 block 方式做包和升级,相关工程师需要注意在适配。
  • 售后,用户自行刷三方固件以及 root 检测等。
  • 开机速度和 performance, Idol 4S 上实测,从校验开始到 system 分区挂载完成耗时 50 ms 以内,对开机 速度的影响可以忽略,当前没有任何证据表明会影响 performance。
  • 工程师日常开发调试。

注意事项

  • 该功能在 eng 软件上是关闭的,刷 eng 的 boot.img 不会受影响。
  • 混刷 boot.img 和 system.img 会启动不了,使能后的 userdebug 或 user 版本的 boot.img 搭配的 eng 版本的 system.img 或者未使能前的 system.img 会开不起来,因为生成时用的 key 不同。
  • 可以通过开机后查看 system 分区的挂载信息来查看是否开启了 Verified Boot 功能:
adb shell mount | grep /system

开启显示

/dev/block/dm-0 /system ext4 ro,seclabel,relatime,discard,data=ordered 0 0

关闭显示

/dev/block/bootdevice/by-name/system /system ext4 ro,seclabel,relatime,discard,data=ordered 0 0

通常会使用 userdebug 软件(或者刷 userdebug 版本的 boot.img) 来调试,但使能后,system 是无法挂载成 rw 状态的,不能 push

$ adb root
Restarting adbd as root
$ adb remount
Reremount succeeded
$ adb shell mount | grep /systtem
/dev/block/dm-0 /system ext4 ro,seclabel,relatime,discard,data=ordered 0 0
$ adb push out/target/product/project_name/system/xbin/su /system/xbin/su
failed to copy 'out/target/product/project_name/system/xbin/su' to '/system/xbin/su': Read-only file system

在 userdebug 软件(或者刷 userdebug 版本的 boot.img)有两种方法可以关闭:

1、用 adb 命令,重启后生效:

$ adb disable-verity
$ adb enable-verity

注意,如果重新刷 了 system.img 就要重新操作,因为关闭标志是写在 system.img 尾部的。当启用boot verity功能,一旦你修改了手机里的 system 分区,比如 push 进去一个 apk,再打开的话,手机会起不来。

2、替换 eng.img ,也可以修改 fstab.qcom 文件,重新编译 userdebug 的 boot.img:

具体操作是修改 device/OEM/project_name/fstab.qcom文件,去掉 verify 标志,例如:

/dev/block/bootdevice/by-name/system    /system     ext4    ro,barrier=1,discard       wait,verify
/dev/block/bootdevice/by-name/system /system ext4 ro,barrier=1,discard wait
  • user 软件没有办法,如果需要修改 system, 请刷 userdebug 或者 eng 的 boot.img。

  • 旧版的 adb 可能不支持 disable-verity 和 enable-verity 命令,请更新到最新的 Android SDK,或者使用工程编译出来的 adb (out/host/linux-x86/bin/adb)。

Android Verified Boot介绍与有关使用的更多相关文章

  1. Android sdk目录介绍

    android sdk目录介绍 build-tools 各版本SDK编译工具 docs 离线开发者文档Android SDK API参考文档 extras 扩展开发包,如兼容架包. platforms ...

  2. 我的Android第三章:Android的组件介绍

    小编摘录了Android文档介绍Android四大组件的基本内容,感觉文档的内容写的很详细所以小编将它写入了博客 Android 使用Java语言开发.Android SDK 工具编译代码-以及任意数 ...

  3. GitHub上排名前100的Android开源库介绍(来自github)

    本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...

  4. android MVP模式介绍与实战

    android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...

  5. Android 不同文件名介绍

    Android 不同文件名介绍

  6. Android发展简单介绍

    Android一词的本义指“机器人”,同一时候也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统.中间件.用户界面和应用软件组成,号称是首个为移动 ...

  7. Android IntentService使用介绍以及源码解析

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...

  8. Android Jetpack 组建介绍(一)——Lifecycler

    转自带你领略Android Jetpack组件的魅力 Android Jetpack 对于任何一个产品来说,我们开发中都会面对哪些问题?如:产品交互.用户体验.代码结构.数据获取.数据存储.网络优化. ...

  9. [原创]AndroBugs_Framework Android漏洞扫描器介绍

    [原创]AndroBugs_Framework Android漏洞扫描器介绍 1 AndroBugs_Framework Android 漏洞扫描器简介 一款高效的Android漏洞扫描器,可以帮助开 ...

  10. android开发学习---linux下开发环境的搭建&& android基础知识介绍

    一.配置所需开发环境 1.基本环境配置 JDK 5或以上版本(仅有JRE不够) (http://www.oracle.com/technetwork/java/javase/downloads/ind ...

随机推荐

  1. C#的基于.net framework的Dll模块编程(四) - 编程手把手系列文章

    这次继续这个系列的介绍: 一.命名空间的起名: 对于C#来说,一般命名空间的建议是:公司名(或个人名称).产品名.分类名,比如我这边是用的这个:Lzhdim.LPF.Helper,意思是个人名Lzhd ...

  2. leetcode(力扣) 2866. 美丽塔 II

    原题链接 暴力做法 (时间复杂度 O(n^2)) 每次选取下标 i 为峰值, 进行 n 次,对每次取max就可以找到答案 对于 i 左边的序列: 需要满足序列是非递减的, 同时每个值尽可能大 所以满足 ...

  3. 跟羽夏学 Ghidra ——简述

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

  4. ansible系列(27)--ansible的include任务复用

    目录 1. include任务复用 1.1 多个项目调用相同task 1.2 Inlcude结合tags应用 1. include任务复用 有时,我们发现大量的 Playbook 内容需要重复编写,各 ...

  5. 🔥🔥httpsok-谷歌免费SSL证书如何申请

    httpsok-谷歌免费SSL证书如何申请 使用场景: 部署CDN证书.OSS云存储证书 证书类型: 单域名 多域名 通配符域名 混合域名 证书厂商: ZeroSSL Let's Encrypt Go ...

  6. addEventListener添加事件监听

    removeEventListener移除事件监听 window.addEventListener('mousedown', e => this.closeMenu(e)) window.add ...

  7. 关于URP14绘制全屏Blit后处理的改动

    最近用回URP,发现RendererFeature这部分改动很大,启用了之前HDRP的RTHandle,RTHandle的设计类似于优化版本的RenderTexture, 可以统一控制缩放或者并非一对 ...

  8. java学习之旅(day.12)

    异常机制(Exception) 异常指程序运行中出现的不期而至的各种状况 异常分类: 检查性异常:用户输入错误引起的异常 运行时异常:写的时候未报错,但一运行就会报错, 错误(error):错误不是异 ...

  9. winform 使用Clipboard 和windows Word Com组件 把Html 导出到word

    首先是把Html复制到剪贴板 见:https://www.cnblogs.com/HelloQLQ/p/16289343.html 然后使用: private void saveAsWordCopy( ...

  10. 【winform】解决datagridview里放combox,combox不能按下键快速选择的问题

    效果图: 一开始,是拖个下拉框到窗体上,用dgv.controls.Add(combox)添加到表格里,在通过表格事件,触发时,改变下拉框的位置和大小,这样做,下拉框是会出现在表格里,但是有问题,不能 ...