TEESimulator进阶功能揭秘:ReAttest如何让应用被覆盖前创建的旧密钥回溯重签

发布时间:2026/10/4 18:04:46
TEESimulator进阶功能揭秘:ReAttest如何让应用被覆盖前创建的旧密钥回溯重签 TEESimulator进阶功能揭秘ReAttest如何让应用被覆盖前创建的旧密钥回溯重签【免费下载链接】TEESimulatorSoftware simulation for Android hardware-backed key pairs with key attestation项目地址: https://gitcode.com/gh_mirrors/te/TEESimulatorTEESimulator是一个面向 Android 的开源密钥认证模拟模块它让指定应用的密钥认证Key Attestation由软件 KeyMint 在真实 keystore 守护进程内完成其余密钥仍走真硬件。本文深入它的进阶功能ReAttest即使某把密钥在应用被覆盖之前就已生成、证书里还带着真实硬件的解锁状态unlocked root of trustReAttest 也能在配置生效时把这些旧密钥回溯重签re-attest换成 keybox 签发的证书链——密钥本身纹丝不动只换应用读到的证书。先搞懂问题为什么旧密钥是个麻烦Android 的密钥认证会生成一条证书链链顶是 Google 的根证书叶子证书里包含root of trustverified-boot 状态、deviceLocked 等、补丁级别、OS 版本等字段。银行类 App、Play Integrity 等都会校验这条链。想象这个场景你装好 TEESimulator但某个 App比如com.example.bank还没写进配置的apps列表该 App 此时创建了一把硬件密钥证书由真 TEE签发——root of trust 是设备真实的开发机上往往是 unlocked之后你才把该 App 加入 profile。从这一刻起新密钥都会被拦截、模拟但那把旧密钥的证书依然是真硬件、真实解锁状态的自供状。ReAttest 要解决的正是这个时间差问题。触发时机配置推送提交后自动运行ReAttest 不是手动按钮而是配置即触发的自愈机制守护进程监视config.json任何修改都会重新解析并推送给注入 keystore2 的原生库原生库应用完新 profile 集后回一个ack此时Control通道触发回调交给ReAttest.run执行回溯重签回调定义见 App.kt 中的onCommitted整个过程在后台专用线程完成不阻塞配置推送主流程。核心逻辑集中在 ReAttest.kt设计目标是幂等且无状态每次运行都重新扫描当前 keystore扫到什么签什么。因此换 keybox、新装了 App、甚至重复运行都会在下一次推送时自动收敛不需要任何手动迁移记录。原理拆解5 步完成回溯重签1️⃣ 从 keystore2 数据库扫描旧密钥keystore2 把每把密钥的证书存在 SQLite 数据库里blobentry表叶子证书CERT与其余链CERT_CHAIN分开存放。ReAttest通过 KeystoreDb.kt 的attestedKeys按目标 uid 扫描跳过模拟器自己签发的密钥有标记前缀不需要重签跳过叶子已经挂在当前 keybox 根下的密钥已经重签过跳过没有认证扩展字段的普通密钥没有 challenge 生成的密钥没有东西可换。2️⃣ 通过控制通道发送 resign 请求守护进程把每个待处理密钥的真实叶子证书Base64经 Unix socket 发给注入在 keystore2 进程内的库接口是teesim_cfg_resign实现见 keymint_router.cpp。客户端封装在 Control.kt 的resign方法中10 秒超时失败则跳过该密钥。3️⃣ 在 TA 内打补丁式重签库收到请求后调用 Rust 侧的patch_attestationresign.rs——这和拦截路径给新密钥打的 patch 完全相同保留真实叶子中的公钥、challenge、KeyMint 版本等所有硬件内容改写root of trust 为 profile 的 locked/Verified 值并替换 OS/vendor/boot 补丁级别与设备 ID 字段避免真实补丁级别泄露否则 Play Integrity 拿不到 STRONG 评级;重挂根到 keybox 证书链之下用 keybox 中匹配算法RSA/ECDSA的私钥重新签名。最终返回[打补丁的叶子, keybox 中间证书…, 根证书]的新链。详细说明可参考 keymint/README.md 的 Patch and generation modes 与 resign 章节。4️⃣ 新链写回先以所有者身份走 API失败再直接写库keystore2 只允许密钥的所有者更新它的子组件。所以写回采用API 优先、数据库兜底两段式守护进程 fork 一个子进程seteuid到密钥属主 uid再以该身份调用 keystore2 的updateSubcomponent更新叶子与链见 App.kt 的runResignHelper若 API 拒绝回退为直接写 keystore2 的 SQLite 数据库KeystoreDb.kt 的updateSubcomponents复刻 AOSP 的set_blob语义先删旧blobentry再插新行。关键点密钥 blob 全程不碰——真硬件密钥继续照常加解密、签名只是应用下次读认证链时看到的是 keybox 根下的一致链条。5️⃣ 结果日志一目了然跑完后 logcat或 WebUI 的 Logs 面板里会看到类似re-attest: 3 pre-existing target key(s) to re-root across 2 uid(s) re-attest: key id101231 uid10123 profiledefault re-rooted (5-cert chain) re-attest: re-rooted 3 of 3 pre-existing target key(s) to the keybox开机时的额外动作清除外来认证密钥回溯重签还有一个前置关卡认证密钥ATTEST_KEY本身。认证密钥负责给其它密钥的叶子签名而 keystore2 会把认证密钥自己的证书链快照附加进最终结果——如果这把认证密钥是覆盖前由真硬件签发的外来密钥我们永远无法控制它签出的叶子。因此守护进程首次启动提交配置时会执行一次purgeTargetAttestKeysReAttest.kt删除目标应用名下非我所有的认证密钥迫使应用下次重新生成由于拦截器保证ATTEST_KEY用途的密钥一律在 TA 内生成替代品必然是我们自己的其签出的叶子才能被完整打补丁若删除走了数据库直删没走所有者 APIkeystore2 内存缓存不会失效此时会用setprop ctl.restart keystore2重启守护进程由注入器对新 pid 重新注入。这个清除是一次性的AtomicBoolean一次性开关不会在运行中打扰任何密钥。新手上手三步让旧密钥转正 前提模块已刷入、/data/adb/teesim/keybox.xml已放好没有 keybox 时拦截器是 no-opReAttest 也自然无事可做。把应用加入 profile编辑config.json模块自带默认配置 module/config.default.json默认覆盖 GMS 与 Play Store或在 KernelSU/APatch 的 WebUI 里勾选应用{ profiles: { default: { keybox: keybox.xml, apps: [com.google.android.gms, com.android.vending] } } }保存即生效守护进程监视配置变化自动重新解析、推送并等待ack——无需重启看日志确认在 WebUI Logs 面板或logcat -s TEESimulator中搜索re-attest确认目标旧密钥数量与re-rooted N of N。之后每次换 keybox、改 profile 或新装 App都会在下次推送时自动重新收敛无需任何手动操作。常见问题QReAttest 会破坏旧密钥吗不会。它只重写数据库里存储的证书CERT/CERT_CHAIN子组件密钥 blob 原样保留原有加解密数据不受影响。Q为什么我的旧密钥没被重签依次检查密钥是否属于目标 profile 的 uid叶子是否已挂在当前 keybox 根下已处理过则跳过resign 是否超时控制通道断开时请求会被跳过待下次推送重试。Q换了一个新 keybox 后旧密钥会跟上吗会。正因为无状态、每轮重扫新 keybox 生效后的下一次配置推送就会把旧链替换为新 keybox 根下的链。Q能查看某把密钥当前挂了什么链WebUI 的密钥管理页可列出目标应用创建的密钥并查看其认证记录底层数据结构与扫描逻辑见 app/README.md 中 ReAttest 一节。小结ReAttest 是 TEESimulator 从拦截新密钥走向补齐历史账的关键设计一次配置提交扫库、重签、写回一气呵成API 优先、数据库兜底保证写入成功幂等无状态让换 keybox 与新应用都能自愈再配合开机一次性清除外来认证密钥旧密钥与新密钥最终收敛到同一套 keybox 根下的自洽世界。对使用者而言它的全部成本就是——保存一下配置文件剩下的交给守护进程。【免费下载链接】TEESimulatorSoftware simulation for Android hardware-backed key pairs with key attestation项目地址: https://gitcode.com/gh_mirrors/te/TEESimulator创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考