diff --git a/lifelog-recorder/HANDOFF.md b/lifelog-recorder/HANDOFF.md index 145d02d..4551708 100644 --- a/lifelog-recorder/HANDOFF.md +++ b/lifelog-recorder/HANDOFF.md @@ -260,6 +260,24 @@ Tier-0 PhotoFaceWorker (15min, battery-not-low) Tier-1 PhotoVlWorker (1 **落库 / 展示**:朋友圈图**不进相册**(「照片」tab 只放头像 + 真正人脸认出的合照);图按条存 `filesDir/moments//_.jpg`,文字写 `moments` 表(`createTime` 存 ms)。朋友圈 tab 的 `MomentRow` 按 `createTimeMs` glob 回该条的图,渲染成微信式「正文 + 九宫格 + 时间」。幂等:头像 `getByPath` 去重、`moments.clearUser` + 目录清空重灌、开头 `idsByPathLike("%/moment__%")` 清旧版误导进相册的图。 +### 微信聊天:端上 SQLCipher 解密(v0.8,2026-06-10,P2 #6,纯本地不经 Mac) + +朋友圈库明文好读,**聊天库 `EnMicroMsg.db` 是 SQLCipher 加密**——过去只能靠 Mac 解密推 `wx_enroll/messages.json`。现在端上直接解密读,**key 纯端上可推导,不用 Frida**。代码 `vision/WeChatChatImporter.kt` + `PhotologViewModel.importChatFor()`。 + +**key 推导(真机验证 = 旧 Frida 抓到的 `e03ce81`)**: +``` +key = MD5(imei + uin).hex()[:7].lower() + imei = "1234567890ABCDEF" # 微信默认值:现代 Android(10+)读不到真 IMEI 时的回退,稳定 + uin = 215004919 # 从 com.tencent.mm/shared_prefs/*.xml 的 last_login_uin 读 +``` +> ⚠️ imei 用**默认值**而非真 IMEI 是关键。真 IMEI 算出来不对。`WeChatChatImporter` 候选 `["1234567890ABCDEF",""]` 逐个试开兜底。 + +**SQLCipher 参数(微信用旧版)**:`PRAGMA cipher_compatibility = 1` + `PRAGMA cipher_page_size = 1024`(在 `SQLiteDatabaseHook.postKey` 里设)。依赖 `net.zetetic:android-database-sqlcipher:4.5.4`。 + +**流程**:`su --mount-master`(两坑见 §七)拷 `MicroMsg//EnMicroMsg.db`(+wal/shm) + echo uin → 算 key 候选 → `SQLiteDatabase.openDatabase(path, key, …, OPEN_READONLY, hook)`,能查 `sqlite_master` 即 key 对 → 读 `message` 表 `WHERE type=1 AND talker IN (?…)`(type=1 文本、talker=对方 wxid、isSend 0/1、createTime ms、content)→ 写 `wechat_messages`(`clearTalker` 先清再灌,幂等)。 + +**接线**:单人「⬇下载图片」顺带解密该人聊天;通讯录「🔄更新」**一次性解密整库**读所有 wxid(避免逐人重复解密整库,慢)。`message` 表结构等见 memory `wechat-android-decrypt`。 + --- ## §五 §六 待办(按优先级)