Python查看Android QQ本地消息記錄數據庫
需求
- 隨着電子產品的更新換代,每隔一段時間我們就會更換手中的電子設備,早期版本的QQ不支持備份聊天記錄,Android 版本的不同也給QQ數據遷移帶來了一定的麻煩。能不能通過提取QQ的數據文件來獲取到以往設備中的消息記錄?
調研
-
Android QQ的聊天記錄存儲於
/data/data/com.tencent.mobileqq/databases
目錄下,其中QQ號.db
文件即為該QQ號的聊天記錄數據庫,獲得該文件即有機會調取出相應的聊天記錄。 -
本文僅適用於 Android 設備。
-
本文僅用於技術研究和學習之用,切勿用於非法用途。
前期准備
-
數據庫獲取
首先需要獲得上面提到的 QQ號.db 文件。由於該文件位於
/data
分區下,Android 默認不可讀寫。如果手機已root可直接復制到電腦上。如果手機沒有root並且不想root,現在的系統大多提供了數據備份與恢復這一功能,我們可以使用這一工具備份整個QQ的數據,然后將壓縮包導出至電腦上,提取出其中的QQ號.db
文件。直接打開這個 .db 文件是不是就可以看到消息記錄了呢?如果有那么簡單自然就不會有這篇文章了。
我們使用 SQLite Expert 打開這個數據庫,可以看到,這個 database 包含很多張 table ,其中有許多名為
mr_friend_***
、mr_troop_***
的數據表。查看這些 table ,我們可以發現里面存有諸如 msgId、msgUid、msgData、msgtype、senderuin、selfuin、time 等字段。通過這些字段以及其中的內容,我們基本可以確定,這就是 QQ 存放消息記錄的數據表。表名mr_friend_***
應當代表與某好友的聊天記錄,mr_troop_***
應當代表某QQ群的聊天記錄。 -
數據表分析
以
mr_friend_***_New
為例,此類數據表一共26個字段,其中extStr
、frienduin
、selfuin
、senderuin
均為 TEXT 文本類型,msgData
為 BLOB 二進制類型,且以上5個字段內容均為亂碼,猜測應當是被加密了。其余21個字段均為 INTEGER 類型,無亂碼未加密。現在要做的就是解密這5個加密字段的內容,重點是msgData
字段。 -
數據表解密
互聯網是很發達的,在本文之前很多年早已有人破解出了密鑰,在此就不用多費時間去親自推敲了:表名
mr_friend_***_New
中的***為QQ號/群號的32位大寫MD5值,表中用於加密5字段的密鑰為本設備的IMEI號,將加密數據與該IMEI號進行逐位異或即可解密。如果手機背面的進網許可標簽沒有撕掉,直接把手機翻過來就能看到IMEI號(有些設備貼在電池內側);也可以直接在手機里查詢,打開撥號盤,輸入
*#06#
,會顯示14位長度的MEID和15位長度的IMEI,如果手機有兩個卡槽則還有第2個15位的IMEI。
代碼實現
-
僅查詢
import sqlite3 import time import hashlib IMEID = '****************' # 可以是15位IMEI也可以是14位MEID conn = sqlite3.connect('*********.db') # QQ號 c = conn.cursor() cu = conn.cursor() # 獲取表名,保存在tab_name列表 cu.execute("select name from sqlite_master where type='table'") tab_name = cu.fetchall() tab_name = [line[0] for line in tab_name] num = input("請輸入QQ號:") hl = hashlib.md5() hl.update(num.encode(encoding='utf-8')) for line in tab_name: if "mr_friend_"+hl.hexdigest().upper() in line: # 查找對應QQ號的聊天記錄,如果是群聊記錄則需將mr_friend改成mr_troop cursor = c.execute('SELECT senderuin,time,msgData FROM '+line+' WHERE msgtype=-1000;') # msgtype=-1000代表文本類型 def decrypt_msg(encrypted_msg): # 解密單條數據 if type(encrypted_msg) is bytes: "" # bytes類型無需轉碼 elif type(encrypted_msg) is int: if 1000000000<encrypted_msg<10000000000: timeArray = time.localtime(encrypted_msg) encrypted_msg = time.strftime("%Y-%m-%d %H:%M:%S", timeArray) # 時間戳需要轉換為標准時間 return encrypted_msg else: encrypted_msg = bytes(encrypted_msg, encoding = "utf8") msg = [] for i in range(len(encrypted_msg)): msg.append(encrypted_msg[i] ^ IMEID[i%15].encode()[0]) # 如果前面用的14位MEID此處也對應換成i%14 return bytes(msg).decode() for row in cursor: decrypted_msgs = [] for item in row: decrypted_msgs.append(decrypt_msg(item)) print(decrypted_msgs)
注意事項
-
若僅查詢消息記錄篩選
senderuin
、time
、msgData
三個字段即可。 -
若單獨通過
mr_troop_***
查詢群聊記錄,無法查出群成員昵稱,需結合表 TroopMemberCardInfo/TroopMemberInfo 進行顯示。
-
若僅查詢QQ聊天記錄中的圖片、視頻、語音等文件,直接檢索內部存儲
/sdcard/tencent/MobileQQ
文件夾即可。 -
若發現一些較早的聊天記錄缺失,則需結合
slowtable_QQ號.db
進行查詢,QQ默認將超出一定數量限制的聊天記錄轉存至該文件中。 -
在撰寫完本文后偶然發現一位大佬編寫的源碼與GUI,還比較全面,一並分享於此,供大家研究參考:怎樣導出手機中的QQ聊天記錄?
-
本文所述方法理論上可用於查看曾在本機登錄過的他人消息記錄,若如此,請務必征得其本人同意。
-
本文僅用於技術研究和學習之用,切勿用於非法用途。