虽然电脑上还是旧版的QQ,但手机上早已更新到了新版(NT)。这次来研究一下如何解密NTQQ的数据库。虽然电脑版的NTQQ数据库格式跟安卓的相同,但获取key这一部分只适用于安卓版本。
首先,手机需要有root权限,这样才能访问/data/data目录。进入/data/data/com.tencent.mobileqq,将databases和files/uid这两个文件夹拷到电脑上,接下来的操作会在电脑上(Windows)进行。
获取数据库文件
在uid目录下,可以看到文件名格式为“QQ号###uid”的文件,例如123456789###u_xxxxxxxx。得到这个uid之后,对它进行md5,得到一串hash,此处记为uid hash。
将uid hash末尾加上“nt_kernel”后,再次进行md5,得到另一串hash,将这串hash前面加上“nt_qq_”,在databases/nt_db目录下可以找到对应的路径,这就是QQ号对应的数据库路径了。
hash代码如下:
def get_qq_uid_hash(nt_uid):
return md5(nt_uid.encode('utf-8')).hexdigest()
def get_qq_path_hash(qq_uid_hash):
return md5((qq_uid_hash+'nt_kernel').encode('utf-8')).hexdigest()
获取key
数据库目录下有多个数据库文件,我尝试了其中几个文件,解密方式应该都是一样的。
用winhex打开数据库文件,可以看到如下内容:

其中,第一个红框内的字符串记为rand。将前面得到的uid hash后面加上这个rand,再进行md5,就得到key了:
def get_key(qq_uid_hash, rand):
return md5((qq_uid_hash+rand).encode('utf-8')).hexdigest()
解密
先去除掉文件的前1024个字节,这样才能被正确读取:
import shutil
with open('nt_msg.db', 'rb') as f_in:
f_in.seek(1024)
with open('nt_msg_2.db', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
解密需要使用sqlcipher,windows下可以从这里下载已编译好的版本:https://github.com/QQBackup/sqlcipher-github-actions/releases
运行sqlcipher命令行:
.\sqlcipher-x64.exe .\nt_msg_2.db
进入sqlcipher环境后,依次输入如下命令:
PRAGMA key = 'key'; PRAGMA cipher_page_size = 4096; PRAGMA kdf_iter = 4000; PRAGMA cipher_hmac_algorithm = HMAC_SHA1; PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA512; PRAGMA cipher = 'aes-256-cbc';
首先,第一行的key,就是前面获取到的key。
第四行的算法,根据图1中的第2个红框进行填写,此处就是HMAC_SHA1。
此时,应该可以正常读取数据库的内容了。
导出
尽管现在可以正常读取数据库了,但为了之后更方便地读取,我需要将它导出为未加密状态的正常数据库文件。在这一步,我遇到了不少麻烦。
一开始,我直接在sqlcipher中导出为新的数据库:
ATTACH DATABASE 'nt_msg_dec.db' AS plaintext KEY '';
SELECT sqlcipher_export('plaintext');
DETACH DATABASE plaintext;
出现报错:
Runtime error: database disk image is malformed
于是,根据这个issue,我先在sqlcipher中导出sql文件:
.output nt_msg.sql .dump
安装MSYS2,进入UCRT64终端,安装sqlite3:
pacman -S mingw-w64-ucrt-x86_64-sqlite3
对之前的sql进行一些处理,再导入sqlite3:
cat nt_msg.sql | sed -e 's|^ROLLBACK;\( -- due to errors\)*$|COMMIT;|g' > nt_msg_2.sql sqlite3 nt_msg_dec.db < nt_msg_2.sql
又出现报错:
Parse error near line xxx: unrecognized token: xxx
我猜测,应该是因为里面某些字段包含特殊字符(例如一些非主流的昵称)。目前没发现有什么办法能够在保留这些字符的情况下进行导入,因此只好去除掉这些字符:
sed -i 's/[[:cntrl:]]//g' nt_msg_2.sql
再次导入sqlite3,这次正常了,能够创建出新的数据库文件了。就是不知道会不会有什么缺失。
下一步,我将基于数据库中的聊天记录,删除掉部分群聊的图片。
参考
1. https://docs.aaqwq.top/decrypt/NTQQ%20(Android).html
2. https://github.com/Mythologyli/qq-nt-db