Python查看Android QQ本地消息記錄數據庫


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個字段,其中extStrfrienduinselfuinsenderuin均為 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)
    

注意事項

  • 若僅查詢消息記錄篩選senderuintimemsgData三個字段即可。

  • 若單獨通過mr_troop_***查詢群聊記錄,無法查出群成員昵稱,需結合表 TroopMemberCardInfo/TroopMemberInfo 進行顯示。

  • 若僅查詢QQ聊天記錄中的圖片、視頻、語音等文件,直接檢索內部存儲 /sdcard/tencent/MobileQQ 文件夾即可。

  • 若發現一些較早的聊天記錄缺失,則需結合 slowtable_QQ號.db 進行查詢,QQ默認將超出一定數量限制的聊天記錄轉存至該文件中。

  • 在撰寫完本文后偶然發現一位大佬編寫的源碼與GUI,還比較全面,一並分享於此,供大家研究參考:怎樣導出手機中的QQ聊天記錄?

  • 本文所述方法理論上可用於查看曾在本機登錄過的他人消息記錄,若如此,請務必征得其本人同意。

  • 本文僅用於技術研究和學習之用,切勿用於非法用途。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM