【逆向】【Android微信】獲取微信聊天記錄

逐夢中原

2020-02-23 晴 鄭州

出場人物

  • 沉瓶 - 產品經理
  • 飯鹹 - 程序員

工作環境

  • 硬件:MacBook Pro (Retina, 13-inch, Early 2015)
  • 硬件相應系統:macOS Catalina,10.15.3
  • 微信版本7.0.4

需求

  • 微信好友頭像照片牆

故事

沉瓶:在網上看到一些人微信頭像做成一張圖片,看着不錯,既好玩又能吸引用戶,這個能不能做。
飯鹹:獲取微信的信息方法很多,以前網頁版微信能用的時候,可以直接網頁請求獲取,網上很多開源代碼。
沉瓶:我看了,很多代碼都不更新了,是不是不能用了。
飯鹹:是的,微信關閉了服務器,這些請求自然不能做了。不過有些人直接通過對PC版本的微信進行HOOK,實現很多有意義的功能,你可以找找。
沉瓶:找到了一個,不過沒有提供可以運行的程序,還有別的方法木有了。
飯鹹:微信本身就是手機系統的,對手機進行分析就可以了,而且分析微信的文章也很多,微信程序沒有加殼,分析難度也不大,可以試試。
沉瓶:那你試試,我研究下怎麼拼接圖片去。
飯鹹:好的,盤它。

需求分析

    1. 獲取微信頭像
    • 1.1 獲得數據庫文件路徑和密匙
    • 1.2 將數據庫文件導出到本地
    • 1.3 打開加密的數據庫文件
    1. 將頭像拼接成照片牆

實現步驟

1. 獲取微信頭像

關於獲取微信聊天記錄的方案網絡上有很多資料,本博文就是根據下面的文章學習而來的:

結合上面兩篇博文,我執行了下面的方案。

1.1 獲得數據庫文件路徑和密匙

根據資料,我們找到一份基於Xposed的源碼https://github.com/adamyi/AndroidWechatSQLiteDecrypt,該源碼可以獲得EnMicroMsg.db文件的路徑和密碼,但是未能正確的獲取加密方式,可能是因爲代碼長時間不更新的原因吧(代碼是兩年前的)。

源碼邏輯不復雜,hook了數據庫打開的操作,在這個地方,騰訊執行了數據庫的打開操作,該操作將路徑、密碼、加密方式都作爲參數傳了進來。具體代碼如下所示:

public class XModule implements IXposedHookLoadPackage {
    static private String TAG = "wxSqlPwdHook";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.packageName.equals("com.tencent.mm")) {

            XposedHelpers.findAndHookMethod(
					"com.tencent.wcdb.database.SQLiteDatabase", 														// 被HOOK對象名
					loadPackageParam.classLoader, 																		// classLoader,固定的值,不用關心
					"openDatabase", 																					// 被HOOK對象的函數名
					String.class,																						// 參數0:數據庫全路徑
                    byte[].class, 																						// 參數1:用戶名密碼(一個加密後的7位值)
					loadPackageParam.classLoader.loadClass("com.tencent.wcdb.database.SQLiteCipherSpec"),				// 參數2:是一個SQLiteCipherSpec對象,該對象中包含了加密方式
                    loadPackageParam.classLoader.loadClass("com.tencent.wcdb.database.SQLiteDatabase$CursorFactory"),	// 參數3:某工廠對象
					int.class,																							// 參數4:Flags,未知標記
                    loadPackageParam.classLoader.loadClass("com.tencent.wcdb.DatabaseErrorHandler"),					// 參數5:錯誤處理的句柄
					int.class,																							// 參數6:加密方式的某個參數PoolSize
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
							// 參數0:數據庫全路徑
                            Log.i(TAG, "Path: " + param.args[0]);
							// 參數1:用戶名密碼(一個加密後的7位值)
                            Log.i(TAG, "Password: " + new String((byte[]) param.args[1], "UTF-8"));
                            Formatter formatter = new Formatter();
                            for (byte b : (byte[]) param.args[1]) {
                                formatter.format("%02x", b);
                            }
                            Log.i(TAG, "Password (hex): 0x" + formatter.toString());
							// 參數2:是一個SQLiteCipherSpec對象,該對象中包含了加密方式
                            Log.i(TAG, "CipherSpec - Cipher: " + XposedHelpers.getObjectField(param.args[2], "cipher"));
                            Log.i(TAG, "CipherSpec - KdfIteration: " + XposedHelpers.getIntField(param.args[2], "kdfIteration"));
                            Log.i(TAG, "CipherSpec - Hmac Enabled: " + XposedHelpers.getBooleanField(param.args[2], "hmacEnabled"));
                            Log.i(TAG, "CipherSpec - Page Size: " + XposedHelpers.getIntField(param.args[2], "pageSize"));
							// 參數4:Flags,未知標記
                            Log.i(TAG, "Flags: " + param.args[4]);
							// 參數6:加密方式的某個參數PoolSize
                            Log.i(TAG, "PoolSize: " + param.args[6]);
                        }
                    });
        }
    }
}

代碼使用的是XPosed框架,使用XposedHelpers.findAndHookMethod函數做的HOOK操作,HOOK點爲com.tencent.wcdb.database.SQLiteDatabase::openDatabase,該函數的參數分別爲:

  • 參數0:數據庫全路徑
  • 參數1:用戶名密碼(一個加密後的7位值)
  • 參數2:是一個SQLiteCipherSpec對象,該對象中包含了加密方式
  • 參數3:某工廠對象
  • 參數4:Flags,未知標記
  • 參數5:錯誤處理的句柄
  • 參數6:加密方式的某個參數PoolSize

我使用的微信版本爲7.0.4,上述代碼未能正確的解析SQLiteCipherSpec對象值,爲了獲得該值,我對微信進行調試,發現SQLiteCipherSpec對象的成員名稱變了,如下所示:

p2 = {SQLiteCipherSpec@9102} 
 hmacAlgorithm = 0
 hmacEnabled = false
 kdfAlgorithm = 0
 kdfIteration = 4000
 pageSize = 1024
 shadow$_klass_ = {Class@8246} "class com.tencent.wcdb.database.SQLiteCipherSpec"
 shadow$_monitor_ = -2105857932

我們將這些值修改即可正常的打印出來,打印調試日誌如下所示(我這邊使用的是VirtualApp進行試驗的):
逐夢中原

最終代碼已經上傳到github倉庫,請自取。

1.2 將數據庫文件導出到本地

將數據庫文件導出到本地,思路也很多,我的方案是,將android手機作爲ftp服務器(Servers Ultimate Pro),在本機(PC)使用FileZilla軟件連接手機的ftp服務器,直接將文件下載到本地。

ps:

  • Servers Ultimate Pro是一款集成了ssh、ftp、http等數十種協議的服務器app,可以輕鬆的將android手機變爲服務器使用,收費軟件,價格不美麗。
  • 本博文使用的是VirtualApp進行XPosed測試,需要將Servers Ultimate Pro服務器程序也安裝在VirtualApp中,這樣以來,微信和服務器程序就處於同一用戶權限了,所以PC上的FileZilla客戶端就可以訪問微信的數據文件了。

1.3 打開加密的數據庫文件

實用開源項目SQLiteStudio,在github上下載最新的軟件即可,該軟件跨平臺(Mac、Windows已經測試通過)、支持多種加密方式(這裏選擇SQLCipher選項),使用方法如下圖所示:
SQLiteStudio設置頁面
SQLiteStudio主頁面
SQLiteStudio關於

選擇數據庫軟件的過程經歷了很多次嘗試,嘗試過程請參考另一篇文章:【程序員日記】2020-02-19__踩坑微信加密後的Android數據庫

2. 將頭像拼接成照片牆

這裏不詳細介紹了,參考下面資料即可

聲明

本文章僅供用於技術研究用途,請勿利用文章內容操作用於違反法律的事情。

關於作者

歡迎各位關注公衆號和QQ羣進行技術交流,關注有福利喔。

微信公衆號:

微信公衆號

qq羣:IT技術控/953949723

逐夢中原技術交流QQ羣

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章