让TWRP支持解密高通data分区

现在新出品的手机,基本都加密了data分区,旨在保障用户数据的安全。其中高通方案的手机使用的加密方案是QSEE(高通安全执行环境,Qualcomm Security Executing Environment),每次启动设备时会有一个专门的过程来解密data分区。然而,TWRP Recovery默认并没有附带高通的加密组件,因此在启动时会无法解密和访问data分区,使得体验大打折扣。因此必须把高通的加密组件从Android系统中移植过来。

QSEE加密组件的组成

高通QSEE组件由本体qseecomd程序、Keystore及其依赖库组成。

首先是qseecomd加解密过程全由qseecomd完成,因此移植过程相对比较简单。

Keystore是加解密过程所必需的“钥匙”,为一个so格式的库文件,每个高通方案设备有属于自己的Keystore,路径为/system/vendor/lib64/hw/keystore.<高通方案型号>.so(32位处理器型号请将lib64改为lib)。

qseecomd运行还需依赖其它库文件,查看依赖可使用readelf -d qseecomd

Dynamic section at offset 0x2cb8 contains 35 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libcutils.so]
 0x0000000000000001 (NEEDED)             Shared library: [libutils.so]
 0x0000000000000001 (NEEDED)             Shared library: [liblog.so]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libQSEEComAPI.so]
 0x0000000000000001 (NEEDED)             Shared library: [libdrmfs.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 ......

值得注意的是,上述命令给出的依赖库,除了libQSEEComAPI.solibdrmfs.so由高通提供外,其他的均为安卓公用的运行库,TWRP会提供它们。

另外,qseecomd的运行还离不开解释器linker,使用readelf -l qseecomd,在输出中可以看到qseecomd所使用linker的绝对路径。

Elf file type is DYN (Shared object file)
Entry point 0x125c
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000001f8 0x00000000000001f8  R E    0x8
  INTERP         0x0000000000000238 0x0000000000000238 0x0000000000000238
                 0x0000000000000015 0x0000000000000015  R      0x1
      [Requesting program interpreter: /sbin/linker64]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000001dd8 0x0000000000001dd8  R E    0x10000
  LOAD           0x0000000000002c88 0x0000000000012c88 0x0000000000012c88
                 0x0000000000000540 0x0000000000000540  RW     0x10000
  DYNAMIC        0x0000000000002cb8 0x0000000000012cb8 0x0000000000012cb8
                 0x0000000000000270 0x0000000000000270  RW     0x8
  NOTE           0x0000000000000250 0x0000000000000250 0x0000000000000250
                 0x0000000000000038 0x0000000000000038  R      0x4
  GNU_EH_FRAME   0x0000000000001cc0 0x0000000000001cc0 0x0000000000001cc0
                 0x0000000000000024 0x0000000000000024  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002c88 0x0000000000012c88 0x0000000000012c88
                 0x0000000000000378 0x0000000000000378  R      0x1

找到加密所需的文件

在上一步中,我们已经知道了加密需要用到哪些文件,那么它们位于安卓系统的哪一个路径?根据下面的表格,整理出它们所在的路径,以及放置到TWRP根文件系统中的路径。

文件 在Android系统中的路径 TWRP中的路径
qseecomd /system/bin/qseecomd /sbin/qseecomd
libQSEEComAPI.so /system/vendor/lib64/libQSEEComAPI.so[1] /vendor/lib64/libQSEEComAPI.so
libdrmfs.so /system/vendor/lib64/libdrmfs.so /vendor/lib64/libdrmfs.so

将文件复制到TWRP源码中

Android设备配置文件(/device/<厂商名>/<设备名>)中,如果存在目录recovery/root,那么该目录中的内容就会在编译TWRP时,自动复制到TWRP的根文件系统中。因此,请将上一步中的文件,根据上表的路径复制到其中。

使用patchelf修改qseecomd的linker路径

系统环境与TWRP的环境还是有所差别的。为了保证qseecomd能够正确地找到解释器linker,我们还需要使用patchelf工具,对qseecomd进行一番修改,否则运行时会提示“qseecomd: not found”,尽管qseecomd确实在指定的目录中。

qseecomd默认的linker是/system/bin/linker64,而TWRP的linker则是/sbin/linker64。因此,我们需要这样修改linker路径:

patchelf --set-interpreter /sbin/linker64 qseecomd

修改完成后,再使用readelf -l qseecomd进行检查,就可以发现修改成功了。

qseecomd注册为服务

qseecomd以服务的形式运行,它会在运行之时自动对data分区进行解密。想让qseecomd作为服务运行,需要修改init.recovery.qcom.rc,这是Android的init配置文件之一。

创建该文件,在其中写入如下内容:

on property:ro.crypto.state=encrypted
    stop qseecomd
    start qseecomd

#
# qseecomd 的服务项
# 设置为随TWRP启动而自动启动
#
service qseecomd /sbin/qseecomd
    user root
    group root
    seclabel u:r:recovery:s0

# 
# 修复TWRP的一个Bug:删除无效的bootdevice链接并重新创建
# 默认地,TWRP会在/dev/block目录下创建一个bootdevice链接,指向启动设备,
# 但因为未知的原因使得该链接无效。因此需要重新创建之,否则qseecomd会无法识别启动设备,导致出错
#
on boot
    exec u:r:recovery:s0 -- /sbin/busybox rm -r /dev/block/bootdevice
    symlink /dev/block/platform/7824900.sdhci /dev/block/bootdevice


on fs
    #
    # 保险起见,在这个地方也尝试重新创建设备链接
    #
    symlink /dev/block/platform/7824900.sdhci /dev/block/bootdevice

    # 
    # 设置qseecomd所需设备的权限
    #
    chmod 0660 /dev/qseecom
    chown system drmrpc /dev/qseecom
    chmod 0664 /dev/ion
    chown system system /dev/ion

设置TWRP参数

TWRP本身有解密模块,并提供与qseecomd对接的接口,但默认没有启用。因此我们需要在BoardConfig.mk设置相应的选项:

TARGET_PROVIDES_KEYMASTER := true
TARGET_KEYMASTER_WAIT_FOR_QSEE := true

TARGET_PROVIDES_KEYMASTER指定设备是否具有用于解密的keymaster,keymaster正是解密必不可少的“钥匙”,高通方案的设备会提供。而TARGET_KEYMASTER_WAIT_FOR_QSEE则指定是否等待qseecomd解密完成。其中,TARGET_KEYMASTER_WAIT_FOR_QSEE至关重要,它是qseecomd解密支持的重要开关,若不设置它,就和不带加密组件无异。

调试

检查工作状态

判断TWRP是否正常解密的依据,就是观察启动后会出现什么画面。如果启动非常快,且显示的是输入密码的窗口,而事实上手机并没有使用密码加密,而是保持默认加密状态,那么说明解密不成功,还需努力调试。如果启动时间延长(定格在splash画面),进入主界面后点击底部的“日志”按钮显示“Data successfully decrypted”,那么则说明解密成功。

获取日志

并不是所有的设备都能遵照上述步骤成功为TWRP启用加密支持,各种各样的问题都有可能出现。显然,我们可以根据日志,来检查qseecomd的工作状态——qseecomd会同时往内核日志和logcat中写入日志。使用dmesgcat /proc/kmsg来获取内核日志;而在BoardConfig.mk中启用logcat支持后,我们亦可以通过运行logcat来获取qseecomd输出的另一部分日志。

启用logcat支持的开关为:

# Logcat
TWRP_INCLUDE_LOGCAT := true
TARGET_USES_LOGD := true

除此之外,我们还可以从TWRP这一边展开分析。TWRP的解密过程也被记录在TWRP本身的日志中,阅读/cache/recovery/last_log*即可了解。

总结体会

为TWRP加入解密组件,看似比较难,实则并不难,关键在于不断尝试。笔者能获得上面的成果,有赖于在反复失败后仍然能够反复尝试,最终取得成功。在整个过程当中,日志调试的作用举足轻重,它反馈了TWRP与qseecomd组件运行时的一系列状况,是分析故障的利器。


  1. 系统中,根目录有一个/vendor,链接到/system/vendor

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章