安卓微信本地数据库解密与删除聊天记录恢复 EnMicroMsg.db FTS5IndexMicroMsg_encrypt.db
- 前言
- 正文
-
- 經驗回顧
- 新的問題
- 解決華為舊備份數據導出問題
- 解密索引數據庫
-
- 先要解密微信消息庫
- 解密索引庫
- 從索引庫恢復被刪除的消息
- 總結
前言
在電子數據取證過程中,對微信本地數據庫的解密、提取與恢復是非常重要的工作內容。本文以華為mate系列手機和最新版的微信(7.0.3)為例,通過總結互聯網上已經發表的文章經驗,主要針對華為手機備份軟件升級、微信7.0以后索引庫加密以及通過索引庫恢復被刪除聊天記錄等內容予以補充。
正文
經驗回顧
網上有很多關于安卓微信本地數據庫(7.0版本以前主要是EnMicroMsg.db)的解密教程,以及恢復已刪除聊天記錄的原理教程,由于微信的不斷升級,很多教程的內容已經不符合實際需要了,通過驗證,發現以下經驗仍然可用:
新的問題
隨著安卓操作系統的不斷升級,安全性越來越高,想通過root等方式獲取手機存儲鏡像然后再進行數據恢復的方式越來越難了,因此大多數電子數據取證的廠家是通過手機廠商官方備份文件對手機數據在本機存儲中備份后,通過導出的備份文件來進行數據提取和恢復。
問題一:華為手機的官方備份軟件在8.0版本以后不再支持本機存儲備份,需要通過OTG轉接頭在外部存儲中備份。很多廠家采取的方法是對備份軟件降級,然后仍然在本機存儲備份后導出。另外8.0以前的備份是以sqlite數據庫(.db)的形式存儲的,而8.0以后的備份是以壓縮文件(.tar)的形式存儲的。對于手工分析來講,新的備份機制更容易操作。但是如果是舊的備份方式,需要把存在數據庫里的文件導出才能進行下一步工作。
問題二:微信7.0以后,對幾個以前沒有加密的數據庫文件(尤其是對恢復數據最重要的索引庫)進行了加密,而且經測試,所使用的密碼不是EnMicroMsg.db加密所使用的密碼。
問題三:網上很多文章對于通過索引庫恢復被刪除的聊天記錄說明不夠詳細。
解決華為舊備份數據導出問題
使用低版本華為備份軟件得到的微信備份文件為一個com.tencent.mm.apk文件和一個com.tencent.mm.db文件。
用sqlite數據庫管理工具打開com.tencent.mm.db,發現只有三個表,其中apk_file_info表中儲存了所有文件名和索引號,apk_file_data中則存儲了文件數據。索引號為-1的是目錄,索引號大于0的是有用的文件。
在apk_file_data中索引號相同的是同一個文件,每個文件被切成若干個8K以內的碎片進行存儲,導出時需要拼接起來再導出。
導出文件數據的python代碼如下:
將代碼保存為out.py后與com.tencent.mm.db文件放在同一目錄下,python out.py運行即可在當前目錄下導出所有文件。生成目錄為data/data/com.tencent.mm。
比較懶,沒有加注釋和提示信息。實際使用時請自行添加提示信息和異常處理代碼。如果導出文件數據較多程序效率比較低,可自行優化,代碼僅供參考。
解密索引數據庫
先要解密微信消息庫
首先需要解密EnMicroMsg.db,以便提取微信id。因為CompatibleInfo.cfg是通過java的HashMap編碼的,因此從此文件中提取IMEI值需要解碼。沒找到python解碼java HashMap的代碼,所以就用java代碼湊合一下。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.security.MessageDigest; import java.util.HashMap; public class GetDBKey {public static void main(String[] args) {try {ObjectInputStream in = new ObjectInputStream(new FileInputStream("CompatibleInfo.cfg"));Object DL = in.readObject();HashMap hashWithOutFormat = (HashMap) DL;String s = String.valueOf(hashWithOutFormat.get(Integer.valueOf(258))); // 取手機的IMEISystem.out.println("IMEI:"+s);ObjectInputStream in1 = new ObjectInputStream(new FileInputStream("systemInfo.cfg"));Object DJ = in1.readObject();HashMap hashWithOutFormat1 = (HashMap) DJ;String t = String.valueOf(hashWithOutFormat1.get(Integer.valueOf(1))); // 取微信的uinSystem.out.println("uin:"+t);s = s + t; //合并到一個字符串s = encode(s); // MD5System.out.println("密碼是 : " + s.substring(0, 7));in.close();in1.close();} catch (Exception e) {e.printStackTrace();}}public static String encode(String content){try {MessageDigest digest = MessageDigest.getInstance("MD5");digest.update(content.getBytes());return getEncode32(digest);}catch (Exception e){e.printStackTrace();}return null;}private static String getEncode32(MessageDigest digest){StringBuilder builder = new StringBuilder();for (byte b : digest.digest()){builder.append(Integer.toHexString((b >> 4) & 0xf));builder.append(Integer.toHexString(b & 0xf));}return builder.toString();} }把代碼另存為GetDBKey.java,把CompatibleInfo.cfg和systemInfo.cfg(在com.tencent.mm/MicroMsg目錄中)跟代碼放在同一目錄,編譯運行后直接顯示密碼。如果需要看IMEI和uin,請自行添加輸出代碼。
另外一種方法是通過DENGTA_META.xml中的IMEI_DENGTA值(有的手機備份沒有)和system_conf_prefs.xml中的system_config_prefs來提取IMEI和uin。這兩個是明文,直接看就可以了。如果登錄過多個微信賬號,所有的uin都在app_brand_global_sp.xml中。這三個xml文件都在com.tencent.mm/shared_prefs目錄下。
取得密碼后,一種方法是使用sqlcipher2.1(CSDN有下載)GUI版直接打開。
第二種方法是通過sqlcipher命令行解密。第三種方法是通過程序代碼解密。
python參考代碼如下(需要先用pip install pysqlcipher3安裝python的sqlcipher支持庫才能引用):
將代碼中的imei值和uin值替換成剛才獲得的值即可。將EnMicroMsg.db與python程序放在同一目錄下運行即可解密,生成的文件名為EnMicroMsg-decrypted.db。
解密索引庫
微信索引庫FTS5IndexMsg.db之前是不加密的,但到了微信7.0以后,索引庫就變成了FTS5IndexMsg_encrypt.db,明顯加密了。使用EnMicroMsg.db的密碼進行解密失敗,通過與幾個電子取證公司的技術人員交流,了解到密碼算法確實變了,而且加密參數也有變化。大體的情況是變成IMEI、uin、微信id三者拼接后的32位MD5值取前7位作為密碼。涉及到產品細節無法透露,因此具體算法還需要自行研究。
先用sqlite管理工具將EnMicroMsg-decrypted.db打開,打開userinfo表,其中id為2對應的值為微信id。通常為wxid_xxxxxxxxxxxxxx格式。
這樣的話至少素材已經齊了,接下來就是研究具體的算法了。
算法只能通過反編譯apk文件來查找。
先從官網下載最新版的jadx 0.9.0zip版(不要下載exe版,因為需要調整運行參數)
將bin目錄中的jadx-gui.bat的DEFAULT_JVM_OPTS參數里面Xms和Xmx分別調整到1024M和7G。參數調整后如下:
如果Xmx值小于7G則在反編譯比較大的軟件時jadx會出現假死狀態。
不用開反混淆開關(其實無所謂,看個人習慣)進行反編譯,然后全部保存。
利用文本編輯器(我用的是NotePad++,開源還好用)對反編譯的java代碼進行文件內容搜索,查找加密算法位置。
首先搜索“FTS5IndexMsg_encrypt.db”,發現com\tencent\mm\plugin\fts\d.java中有:
往下看,發現有這么一句:
this.lXS = SQLiteDatabase.openOrCreateDatabase(absolutePath, com.tencent.mm.a.g.u(stringBuilder.append(a.OZ()).append(q.Kc()).append(com.tencent.mm.model.q.Wt()).toString().getBytes()).substring(0, 7).getBytes(), null, null);stringBuilder是一個字符串構造函數,連續拼接了三個字符串,經過一個運算后取了前7位,與了解到的情況相符。
通過分析發現:
com.tencent.mm.kernel.a.OZ()取uin;
com.tencent.mm.compatible.e.q.Kc()取DeviceID(即IMEI);
com.tencent.mm.model.q.Wt()取userinfo(即微信id);
com.tencent.mm.a.g.u()是MD5算法。
因此說明這個密碼是將uin、IMEI、微信id連續拼接然后計算32位MD5值再取前7位作為密碼。
這里需要注意的是,uin如果是負值不能直接進行拼接,要把它加上4294967296(最大無符號數),得到的正數作為最終的uin進行拼接。
另外,除了密碼之外據說加密算法等參數也有變化,因此還需要繼續搜索。
這次搜索sqlcipher參數“PRAGMA”,發現最終調用的是com\tencent\wcdb\database\SQLiteCipherSpec.java中的幾個參數(wcdb對應wcdb.so文件,其實是改了名的sqlcipher.so),對應值分別為:
另外經與廠商技術人員溝通,發現還有個參數需要調整:
setPageSize=4096;這幾個參數分別對應如下sqlcipher參數:
PRAGMA cipher = 'aes-256-cbc'; PRAGMA cipher_use_hmac = ON; PRAGMA cipher_page_size = 4096; PRAGMA kdf_iter = 64000;綜上所述,一切解密需要的素材都齊了,相應的python代碼如下:
from os.path import isfile # 用pip install pysqlcipher3安裝python的sqlcipher支持庫再引用 from pysqlcipher3 import dbapi2 as sqlite import hashlib import sys import time import logging import relogging.basicConfig(filename='FTS5IndexMicroMsg_decrypt.log', format="%(asctime)s %(levelname)s: %(message)s", datefmt="%d-%b-%Y %I:%M:%S %p", level=logging.DEBUG)def decrypt( key ):logging.info( "連接數據庫..." )conn = sqlite.connect( "FTS5IndexMicroMsg_encrypt.db" )c = conn.cursor() c.execute( "PRAGMA key = '" + key + "';" )c.execute( "PRAGMA cipher = 'aes-256-cbc';" )c.execute( "PRAGMA cipher_use_hmac = ON;" )c.execute( "PRAGMA cipher_page_size = 4096;" )c.execute( "PRAGMA kdf_iter = 64000;" )try:logging.info( "正在解密..." )c.execute( "ATTACH DATABASE 'FTS5IndexMicroMsg_decrypt.db' AS fts5indexdecrypt KEY '';" )c.execute( "SELECT sqlcipher_export( 'fts5indexdecrypt' );" )c.execute( "DETACH DATABASE fts5indexdecrypt;" )logging.info( "正在分離數據庫..." )c.close()status = 1except:c.close()status = 0return statusdef generate_key():imei = "866666666666666"logging.info( "IMEI: " + str( imei ))uin = "2377777777"logging.info( "UIN: " + str( uin ))account = "wxid_1l8w9yqrxxxxxx"logging.info( "account: " + str( account ))logging.info( "正在生成密鑰..." ) key = hashlib.md5( str( uin ).encode("utf8") + str( imei ).encode("utf8") + str( account ).encode("utf8")).hexdigest()[ 0:7 ]logging.info( "密鑰: " + key )return keydef db_hash():f = open( 'FTS5IndexMicroMsg_decrypt.db', 'rb' ).read()logging.info( "正在生成哈希值..." ) if len( f ) > 0:db_md5 = hashlib.md5( f ).hexdigest()logging.info( "FTS5IndexMicroMsg_decrypt.db MD5: " + db_md5 )db_sha1 = hashlib.sha1( f ).hexdigest()logging.info( "FTS5IndexMicroMsg_decrypt.db SHA1: " + db_sha1 )returndef main(): if not ( isfile( "FTS5IndexMicroMsg_encrypt.db" )):print ("##########")print ("'FTS5IndexMicroMsg_encrypt.db'不存在!")print ("正在退出腳本...")print ("##########")sys.exit()logging.info( "腳本啟動..." )key = generate_key()status = decrypt( key )if status == 1:db_hash()print ("##########")print ("解密成功!")print ("解密文件: FTS5IndexMicroMsg_decrypt.db")print ("日志文件: FTS5IndexMicroMsg_decrypt.log")print ("##########")logging.info( "解密成功!" )logging.info( "解密文件: FTS5IndexMicroMsg_decrypt.db" )else:print ("##########")print ("解密失敗!")print ("日志文件: FTS5IndexMicroMsg_decrypt.log")print ("##########")logging.info( "解密失敗!" )logging.info( "正在退出腳本..." )main()這次放了比較規范的代碼,之前也是為了體現python的簡潔,很多復雜功能沒幾行代碼就搞定了。
只要把IMEI、uin、微信id換成之前取出來的即可。把加密數據庫和python代碼放在同一個目錄中運行就可以得到解密數據庫。
另外在搜索代碼的過程中發現MicroMsgPriority.db也加密了,密碼是uin、微信id、IMEI順次拼接的32位MD5值取前7位。sqlcipher參數與索引庫相同。可以簡單修改以上代碼就可以實現解密。
從索引庫恢復被刪除的消息
用winhex打開解密后的索引庫:
在右側顯示區上方點擊“ANSI ASCII”,選擇“Unicode UTF-8”,向下滾動就可看到連續的中文,這些就是索引后的消息。其中包括已刪除和未刪除的內容。
經查閱資料并與廠商技術人員溝通,發現這些信息的存儲格式開頭如下:
aa bb 03 00 cc 或 aa bb 04 00 cc dd
如果一個區域里面aa的值一致,說明是正常未刪除信息,如果aa值不一致,則說明是刪除信息。bb是從7F到00順序排列(偶爾有中斷)相當于序號。如果是03則cc是后面正文長度,如果是04則cc dd是正文長度。
cc或者cc dd是varint格式,需要進行一定的變換之后才能得出長度值。
計算方法為:
cc->16進制轉10進制->減13->除以2,如果結果是3的倍數,說明是中文,再除以3,得到的數值就是正文長度。如果除以2以后不是3的倍數,說明是英文(半角),這個得數就是英文正文長度。
例如:
55->85->72->36->12個漢字
19->25->12->6->2個漢字
17->23->10->5個英文
如果是cc dd要麻煩一些。先將cc dd都轉成二進制,然后把cc的首位1和之后的所有0都去掉,把dd首位0去掉,然后拼到一起,再轉成10進制->減13->除以2,如果結果是3的倍數,說明是中文,再除以3,得到的數值就是正文長度。如果除以2以后不是3的倍數,說明是英文(半角),這個得數就是英文正文長度。
例如:
81 23
81-> 10000001 23->00100011 合并為10100011,十進制是163;163->150->75->25個漢字
81 11
81->10000001 11->00010001 合并為10010001,十進制是145;145->132->66->22個漢字
這樣的話,就可以通過程序把符合規則的內容全部導出來,就是被刪除的消息。如果想確定交互雙方,還需要配合其他數據分析。
如果有問題可以聯系,15387172081,微信同號,1037512447 qq/微信
總結
以上是生活随笔為你收集整理的安卓微信本地数据库解密与删除聊天记录恢复 EnMicroMsg.db FTS5IndexMicroMsg_encrypt.db的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7开机登录界面的壁纸怎样更换修改
- 下一篇: SaaS小读-客户成功