参考了 https://github.com/QQBackup/QQ-History-Backup/issues/9 以及 https://github.com/QQBackup/qq-win-db-key 中的各平台教程。
在 iOS 设备上操作
-
Cydia / Sileo / Zebra 添加 Frida 官方软件源
https://build.frida.re
-
安装
Frida
包 -
启动 Frida 服务器
在终端(NewTerm 之类的终端App,或SSH)运行:
frida-server -v
如果端口被占用,更换其他端口,如:
frida-server --listen='0.0.0.0:27043' -v
启动 Frida 服务端。
命令前部加上
sudo
赋予 root 用户权限也许会更好
-
需要有 TrollStore 巨魔 环境
-
App 脱壳,可参考下一章节(需要得到完整的 IPA 安装包)
-
下载 Frida Gadget 动态链接库
frida-gadget-x.x.x-ios-universal.dylib.gz
并解压得到frida-gadget-ios-universal.dylib
-
注入 Frida Gadget 动态链接库,有两种方法,Sideloadly 更方便且支持 Windows,命令行方式 optool 需要在 macOS 环境下进行
直接照图进行配置:
- 不允许自动更改 Bundle ID
- 开启文件共享(即开放 App 沙盒 Documents 目录到系统自带的文件 App)
- 注入动态链接库
- 仅导出 IPA
然后点击 Start 开始导出
-
解压脱壳得到的 IPA 安装包
-
安装 optool,这里需要使用
xcodebuild
命令
git clone https://github.com/alexzielenski/optool.git
cd optool
git submodule update --init --recursive
xcodebuild
ln -s $PWD/build/Release/optool /usr/local/bin/optool
- 将前面下载的
frida-gadget-ios-universal.dylib
放入 IPA 解压目录下的Payload/QQ.app/Frameworks
目录
cp frida-gadget-ios-universal.dylib Payload/QQ.app/Frameworks
- 用 optool 把动态链接库加载命令插入到 QQ 主程序中(此处路径无法自动补全,注意不要打错了)
optool install -c load -p "@executable_path/Frameworks/frida-gadget-ios-universal.dylib" -t Payload/QQ.app/QQ
运行成功的输出:
Found thin header...
Load command already exists
Successfully inserted a LC_LOAD_DYLIB command for arm64
Writing executable to Payload/QQ.app/QQ...
-
为了方便后续导出聊天记录数据库等文件,需要修改 App 配置,允许用户通过系统自带的文件 App 访问 App 沙盒 Documents 目录,具体操作可以网上查询(
-
重新打包 IPA,可以直接压缩
Payload
目录为 zip 归档,然后重命名文件后缀为ipa
,把重新打包好的 IPA 安装包发送到 iOS 设备
发送重新打包好的 QQ IPA 安装包到 iOS 设备,使用 TrollStore 巨魔 进行安装,如果提示安装失败,应用已存在,选择强制安装
需要使用巨魔的原因:附带了 Frida Gadget 的 QQ 安装包需要以覆盖,或者更新的方式安装到设备,这样它才能读取到聊天记录,不然系统会分配新的沙盒空间。为了实现这一点,App Bundle ID 需要保持不变,即
com.tencent.mqq
,但如果使用腾讯的com.tencent.*
作为 Bundle ID,在签名过程中就会失败,因此需要绕过签名,即使用 TrollStore 安装。
将 iOS 设备有线连接至 PC,可以自行用 frida-ps
等工具测试一下 Frida 服务器是否正常工作(无线连接等可以参考 Frida 文档 - Gadget)
如果你的 QQ 版本和脚本 ios_get_key.js 内注释的版本一致,可直接跳过进入下一步
如果 QQ 版本不一致,但下一步的脚本 ios_get_key.js 可以正常使用,也可以忽略本节
可选工具
- dumpdecrypted (https://github.com/stefanesser/dumpdecrypted)
- frida-ios-dump (https://github.com/AloneMonkey/frida-ios-dump)
- AppsDump2(有图形界面的App,用起来很方便,不过似乎找不到它的仓库链接)
- ...
只需要得到脱壳后的 Mach-O 二进制主程序即可,不需要完整的 IPA 安装包。
本篇示例
- iOS QQ v9.0.1.620
- SQLCipher v4.5.1
主要目的是获取 sqlite3_key_v2
函数位置,页大小、纯文本文件大小、PBKDF2 迭代次数等通常是固定的。
-
用例如 IDA 的反编译工具反编译脱壳得到的 Mach-O 二进制主程序
-
搜索二进制片段
sqlite3_key_v2
,可以找到日志文本,从而定位到SQLCipher C API 的sqlite3_key_v2
函数在程序中的位置。第三个参数即为数据库密钥,根据传入的其他实参,还能得到更多信息。
int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey);
得到目标函数的位置为 000000010DA1BFB4
。由于IDA基址设为了 0000000100000000
,两者相减,
得到偏移量为 0xDA1BFB4
,将其设置为脚本文件 ios_get_key.js 中的 SQLLiteKeyV2Offset
的值。
// ios_get_key.js
const SQLLiteKeyV2Offset = 0xDA1BFB4;
- 根据调用关系
sqlite3CodecAttach
->sqlcipher_codec_ctx_init
->sqlcipher_codec_ctx_set_pagesize
可以确定页大小为4096
- 根据调用关系
sqlite3CodecAttach
->sqlcipher_codec_ctx_init
->sqlcipher_codec_ctx_set_plaintext_header_size
,
用 Frida hooksqlcipher_codec_ctx_set_plaintext_header_size
函数,可以确定纯文本文件大小为0
- 在 PC 上安装 frida(确保 Python 已安装)
# pipx 可以把包安装到隔离的环境,避免依赖冲突
pip install pipx
pipx install frida
frida --version
iOS 上没有编译好的 frida 工具(只有 frida-server),因此需要电脑
有试过自己编译,但总是会因为 macOS/iOS 的平台判定什么的导致运行失败(
-
下载 ios_get_key.js(如果上一步已经下载过了可以跳过)
-
iOS 设备打开 QQ App
-
PC Frida 连接至 iOS 设备,终端运行命令以附加脚本到 QQ 进程
连接方式有两种:
- USB 连接:
frida -U QQ -l ios_get_key.js
- 网络连接
frida -H <设备IP地址>:<frida-server端口号> QQ -l ios_get_key.js
IP地址为iOS设备的IP地址,端口号在第一步配置过。例如:
frida -H 192.168.1.163:27043 QQ -l ios_get_key.js
iOS frida-server 只能附加到已有进程,不能以 spawn 方式生成进程,原因暂不知
-
iOS 设备 QQ 进行登录操作
-
查看 PC 终端 输出内容,可以看到一条条信息被输出,其中
pKey
为数据库密钥zFilename
为对应的数据库文件所在路径
输出的数据库信息已经过筛选。
例如:
+------------
¦- db: 0x152ec8710
¦- *zDb: main
¦- *pkey: d3c1d0f05b2cxxxxxxxxxxc1ac161c29
¦- *pkey-hex: ...
¦- nKey: 32
¦+
¦- zFilename: /var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be/nt_msg.db
+------------
¦- db: 0x152ec8710
¦- *zDb: main
¦- *pkey: d3c1d0f05b2cxxxxxxxxxxc1ac161c29
¦- *pkey-hex: ...
¦- nKey: 32
¦+
¦- zFilename: /var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be/guild_msg.db
+------------
复制其中的 pKey
和 zFilename
- 从 iOS 设备下载数据库文件
- 越狱用户可使用 SFTP 或 Filza App
- 免越狱方式直接用 iOS 自带的文件 App 查看
路径为上一步的 zFilename
所在目录的路径
/var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be
该目录下有数个数据库,除了一般的聊天记录以外还有(QQ频道记录?)更多数据。
-
下载安装 SQLite 查看器(需支持读取SQLCipher加密的数据库),如 DB Browser for SQLite
-
删除数据库文件 前
1024
字节 部分 -
解密数据库
- 密码:上一步获取的
pKey
- 页大小:
4096
- KDF 迭代:
4000
- HMAC 算法:
HMAC_SHA1
- KDF 算法:
PBKDF2_HMAC_SHA512
- 纯文本文件头大小:
0