現在新出品的手機,基本都加密了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.so
與libdrmfs.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中寫入日誌。使用dmesg
或cat /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組件運行時的一系列狀況,是分析故障的利器。
-
系統中,根目錄有一個
/vendor
,鏈接到/system/vendor
。 ↩