尧图精选

qq聊天记录导出

🕒 发布时间:2026/10/1 21:51:27 📁 来源:尧图网络
### 1. 提取手机文件以只读方式拉取 UID 映射与数据库文件夹# 1. 查看账号与 nt_uid 映射adb shellsu -c ls -la /data/data/com.tencent.mobileqq/files/uid/# 2. 打包拉取 nt_db 目录到本地工作区mkdir-p./nt_db adb exec-outsu -c tar -C /data/data/com.tencent.mobileqq/databases/nt_db -cf - .|tar-xf--C./nt_db/涉及文件UID 映射/data/data/com.tencent.mobileqq/files/uid/QQ号###nt_uid数据库文件/data/data/com.tencent.mobileqq/databases/nt_db/nt_qq_QQ_path_hash/nt_msg.db2. 密钥计算逻辑QQ_UID_hashmd5(nt_uid)QQ_path_hashmd5(QQ_UID_hash nt_kernel)对应文件夹名称nt_qq_{QQ_path_hash}rand 读取nt_msg.db前 1024 字节定位QQ_NT DB后的 Protobuf 字段Tag\x12\x08提取 8 字节字符串。Keymd5(QQ_UID_hash rand)3. 解密操作步骤去除文件头截掉nt_msg.db前 1024 字节另存为nt_msg.clean.db。SQLCipher 配置参数注意cipher_page_size须在key之前执行PRAGMA cipher_page_size4096;PRAGMAkeyKey;PRAGMA kdf_iter4000;PRAGMA cipher_hmac_algorithmHMAC_SHA1;PRAGMA cipher_kdf_algorithmPBKDF2_HMAC_SHA512;PRAGMA cipheraes-256-cbc;导出明文库使用rowid游标遍历加跳跃步进机制将数据转储为无需密码的标准明文 SQLitent_msg_plain.db自动跳过损坏页。4. 完整解密脚本依赖pip install sqlcipher3-binary protobuf#!/usr/bin/env python3importosimportsysimporthashlibimportsqlite3importreimportsqlcipher3.dbapi2assc HEADER_SIZE1024BATCH_SIZE5000defget_key_and_clean(db_path:str,nt_uid:str)-tuple[str,str]:clean_pathdb_path.replace(.db,.clean.db)withopen(db_path,rb)asfin:headerfin.read(HEADER_SIZE)ifnotos.path.exists(clean_path)oros.path.getsize(clean_path)!os.path.getsize(db_path)-HEADER_SIZE:withopen(clean_path,wb)asfout:whilechunk:fin.read(6420):fout.write(chunk)tag_posheader.find(b\x12\x08)randheader[tag_pos2:tag_pos10].decode(latin1)qq_uid_hashhashlib.md5(nt_uid.encode(utf-8)).hexdigest()keyhashlib.md5((qq_uid_hashrand).encode(utf-8)).hexdigest()returnkey,clean_pathdefopen_enc(path:str,key:str):connsc.connect(path,isolation_levelNone)conn.execute(PRAGMA cipher_page_size 4096;)conn.execute(fPRAGMA key {key.replace(\\, \\)};)conn.execute(PRAGMA kdf_iter 4000;)conn.execute(PRAGMA cipher_hmac_algorithm HMAC_SHA1;)conn.execute(PRAGMA cipher_kdf_algorithm PBKDF2_HMAC_SHA512;)conn.execute(PRAGMA cipher aes-256-cbc;)conn.execute(SELECT count(*) FROM sqlite_master;).fetchone()returnconndefdecrypt_to_plain(clean_path:str,key:str,out_path:str):encopen_enc(clean_path,key)tables[r[0]forrinenc.execute(SELECT name FROM sqlite_master WHERE typetable).fetchall()]enc.close()ifos.path.exists(out_path):os.remove(out_path)plainsqlite3.connect(out_path)plain.execute(PRAGMA journal_mode WAL;)plain.execute(PRAGMA synchronous NORMAL;)fortableintables:iftable.startswith(sqlite_):continueencopen_enc(clean_path,key)ddlenc.execute(SELECT sql FROM sqlite_master WHERE typetable AND name?,(table,)).fetchone()[0]plain.execute(re.sub(r^CREATE\sTABLE\s,CREATE TABLE IF NOT EXISTS ,ddl,flagsre.IGNORECASE))ncolslen(enc.execute(fPRAGMA table_info({table})).fetchall())ph,.join(?*ncols)last_rowid0batchBATCH_SIZE jump1whileTrue:try:rowsenc.execute(fSELECT rowid, * FROM {table} WHERE rowid ? ORDER BY rowid LIMIT ?,(last_rowid,batch)).fetchall()ifnotrows:breaklast_rowidrows[-1][0]plain.executemany(fINSERT OR IGNORE INTO {table} VALUES ({ph}),[r[1:]forrinrows])plain.commit()jump1ifbatchBATCH_SIZE:batchmin(BATCH_SIZE,batch*2)exceptException:enc.close()encopen_enc(clean_path,key)ifbatch1:last_rowidjump jumpmin(jump*2,148)batch1000else:batchmax(1,batch//4)ifjump(148):breakenc.close()plain.close()print(f[✓] 解密完成:{out_path})if__name____main__:iflen(sys.argv)3:print(用法: python decrypt.py nt_msg.db 路径 nt_uid [nt_msg_plain.db 输出路径])sys.exit(1)db_file,uid_strsys.argv[1],sys.argv[2]out_filesys.argv[3]iflen(sys.argv)3elsedb_file.replace(.db,_plain.db)k,cleanget_key_and_clean(db_file,uid_str)print(f[*] 派生密钥:{k})decrypt_to_plain(clean,k,out_file)5. 输出产物说明nt_msg.clean.db剥离前 1024 字节后的 SQLCipher 加密文件。nt_msg_plain.db无需密码的标准明文 SQLite 数据库可用任意 SQLite 查看工具直接打开。nt_msg_export.db经 Protobuf 反序列化后的消息数据库包含格式化的私聊/群聊文本及 FTS 全文搜索索引。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →