記錄學習「PC版微信資料庫解密」全過程,參考原文「PC版微信資料庫解密詳細教程」連結:https://bbs.pediy.com/thread-251303-4.htm
1、環境&工具Windows10:https://www.microsoft.com/
PC版微信:https://pc.weixin.qq.com/
visual studio community 2019:https://visualstudio.microsoft.com/zh-hans/
Ollydbg (吾愛破解專用版):https://down.52pojie.cn/Tools/Debuggers/%E5%90%BE%E7%88%B1%E7%A0%B4%E8%A7%A3%E4%B8%93%E7%94%A8%E7%89%88Ollydbg.rar
openssl 1.0.2:https://www.openssl.org/source/openssl-1.0.2r.tar.gz
SQLite DB Browser:https://sqlitebrowser.org/dl/
2、提取資料庫文件密碼打開 微信(退出狀態) 和 OD :
使用OD 附加 微信進程, 點擊 「文件」 --> "附加" 會彈出新窗口, 找到名稱是 wechat 的選中 點擊附加:
加載後OD標題處會顯示 wechat.exe:
點擊菜單欄 「查看」 --> "可執行模塊" (快捷鍵:Alt+E):
打開後找到 名稱為「WeChatWi」 且路徑以WeChatWin.dll 結尾這一行,雙擊進入:
Executable modules:
名稱=WeChatWi
文件版本=3.3.0.115
路徑=D:\Program Files (x86)\Tencent\WeChat\WeChatWin.dll進入後OD標題末尾處會顯示 WeChatWi , 接下來點擊 「插件」-->「中文搜尋引擎」--> "搜索ASCII" :
點擊後需要等等待一會,搜索結束後會跳轉到搜索結果界面:
搜索結果展示,在此界面右鍵 選擇 「Find」 (快捷鍵:Ctrl+F):
在搜索框中輸入「DBFactory::encryptDB」:
搜索到後雙擊進入,會定位到「push WeChatWi .XXXXXX" 這個位置,然後向下6行找到 」test edx , edx" :
在「test edx,edx" 這一行下斷點, 直接雙擊本行(滑鼠不要放在地址那一欄)或者 選中本行 按下快捷鍵 」F2" , 斷點設置成功後,本行地址欄會變成紅色:
斷點設置好後,點擊「」按鈕(或者在調試菜單中選擇「運行」,快捷鍵 「F9」),這時寄存器窗口中的EDX的值應該是00000000。
切換到微信登錄頁面,點擊登錄,然後到手機端確認登錄。這是OllyDbg界面中的數據不斷滾動,直到EDX不再為全0並且各個窗口內容停止滾動為止。
此時斷點生效了,寄存器的值也發生變化了,接下來單擊選中EDX的值然後單擊滑鼠右鍵,在彈出的菜單裡面選擇「數據窗口中跟隨」,則數據窗口中顯示的就是EDX的值也就是內存地址對應的內容:
從地址」05340DB8「 開始選中 32 個字節,就是微信資料庫的加密密碼,本圖中密碼如下:
05340DB8 71 1A 1F FA 27 E6 41 D9 AB 8E 8D C0 F1 8A F9 66
05340DC8 76 11 6F EF 95 30 48 91 B3 9B 40 9B 57 B1 35 00 」711A1FFA27E641D9AB8E8DC0F18AF96676116FEF95304891B39B409B57B13500」 得到這個即密碼提取結束,退出OD。
將提取到的密碼轉換為 0x 格式備用,如下:
{0x71,0x1A,0x1F,0xFA,0x27,0xE6,0x41,0xD9,0xAB,0x8E,0x8D,0xC0,0xF1,0x8A,0xF9,0x66,0x76,0x11,0x6F,0xEF,0x95,0x30,0x48,0x91,0xB3,0x9B,0x40,0x9B,0x57,0xB1,0x35,0x00}3、編譯解密程序本文使用編譯工具:visual studio community 2019
3.1-配置openssl在編譯前需要配置openssl ,經過測試強制使用openssl 1.0.2r的版本,下載地址:https://www.openssl.org/source/openssl-1.0.2r.tar.gz
下載並解壓, openssl 需要自己編譯,網上教程有很多,我直接把編譯後生成的文件打包:
將這個兩個文件夾直接複製到openssl 1.0.2r 解壓的目錄中:
3.2-配置visual studio
接下來配置 visual studio, 打開visual studio,選擇 「創建新項目」:
選擇「C++ 控制臺應用」:
配置項目:(名稱和位置 自定義)設置好後點擊創建
生成默認的 hello world 代碼:
接下是添加openssl附加依賴庫,單擊 菜單欄的 「項目」 --> "dewechatdb屬性":(這個跟設置的項目名稱一致)
1.配置與平臺需要保持一致:
2.選擇 C/C++ 下面的 「常規」 --> 配置項 「附加包含目錄」 :
點擊右側空白處。在下拉框裡選擇「編輯…」,在對話框中點擊四個圖標按鈕最左側的「新行」按鈕,會生成一個空白行,點擊右側的「…」:
在彈出的對話框裡選擇前面解壓的openssl目錄(根據自己放目錄選擇,本文是D:\tools\openssl-1.0.2r)中的include目錄。
配置好後如圖:
3.選擇左側「連結器」下面的「常規」 --> 「附加庫目錄」:
點擊右側空白處,選擇openssl目錄下的lib目錄,設置完成後如下:
最後點擊「連結器-->「輸入」:
右側最上面有「附加依賴項」,默認已經有一些系統庫,點擊右側內容,選擇「編輯…」
添加 libeay32.lib 、ssleay32.lib 依賴項。
到此配置完成。
3.3-編譯程序複製大佬的原始碼:
using namespace std;
#include <Windows.h>
#include <iostream>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/hmac.h>
#undef _UNICODE
#define SQLITE_FILE_HEADER "SQLite format 3"
#define IV_SIZE 16
#define HMAC_SHA1_SIZE 20
#define KEY_SIZE 32
#define SL3SIGNLEN 20
#ifndef ANDROID_WECHAT
#define DEFAULT_PAGESIZE 4096 //4048數據 + 16IV + 20 HMAC + 12
#define DEFAULT_ITER 64000
#else
#define NO_USE_HMAC_SHA1
#define DEFAULT_PAGESIZE 1024
#define DEFAULT_ITER 4000
#endif
//pc端密碼是經過OllyDbg得到的32位pass。
unsigned char pass[] = { 0x53,0xE9,0xBF,0xB2,0x3B,0x72,0x41,0x95,0xA2,0xBC,0x6E,0xB5,0xBF,0xEB,0x06,0x10,0xDC,0x21,0x64,0x75,0x6B,0x9B,0x42,0x79,0xBA,0x32,0x15,0x76,0x39,0xA4,0x0B,0xB1 };
char dbfilename[50];
int Decryptdb();
int main(int argc, char* argv[])
{
if (argc >= 2) //第二個參數argv[1]是文件名
strcpy_s(dbfilename, argv[1]); //複製
//沒有提供文件名,則提示用戶輸入
else {
cout << "請輸入文件名:" << endl;
cin >> dbfilename;
}
Decryptdb();
return 0;
}
int Decryptdb()
{
FILE* fpdb;
fopen_s(&fpdb, dbfilename, "rb+");
if (!fpdb)
{
printf("打開文件錯!");
getchar();
return 0;
}
fseek(fpdb, 0, SEEK_END);
long nFileSize = ftell(fpdb);
fseek(fpdb, 0, SEEK_SET);
unsigned char* pDbBuffer = new unsigned char[nFileSize];
fread(pDbBuffer, 1, nFileSize, fpdb);
fclose(fpdb);
unsigned char salt[16] = { 0 };
memcpy(salt, pDbBuffer, 16);
#ifndef NO_USE_HMAC_SHA1
unsigned char mac_salt[16] = { 0 };
memcpy(mac_salt, salt, 16);
for (int i = 0; i < sizeof(salt); i++)
{
mac_salt[i] ^= 0x3a;
}
#endif
int reserve = IV_SIZE; //校驗碼長度,PC端每4096位元組有48位元組
#ifndef NO_USE_HMAC_SHA1
reserve += HMAC_SHA1_SIZE;
#endif
reserve = ((reserve % AES_BLOCK_SIZE) == 0) ? reserve : ((reserve / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
unsigned char key[KEY_SIZE] = { 0 };
unsigned char mac_key[KEY_SIZE] = { 0 };
OpenSSL_add_all_algorithms();
PKCS5_PBKDF2_HMAC_SHA1((const char*)pass, sizeof(pass), salt, sizeof(salt), DEFAULT_ITER, sizeof(key), key);
#ifndef NO_USE_HMAC_SHA1
PKCS5_PBKDF2_HMAC_SHA1((const char*)key, sizeof(key), mac_salt, sizeof(mac_salt), 2, sizeof(mac_key), mac_key);
#endif
unsigned char* pTemp = pDbBuffer;
unsigned char pDecryptPerPageBuffer[DEFAULT_PAGESIZE];
int nPage = 1;
int offset = 16;
while (pTemp < pDbBuffer + nFileSize)
{
printf("解密數據頁:%d/%d \n", nPage, nFileSize / DEFAULT_PAGESIZE);
#ifndef NO_USE_HMAC_SHA1
unsigned char hash_mac[HMAC_SHA1_SIZE] = { 0 };
unsigned int hash_len = 0;
HMAC_CTX hctx;
HMAC_CTX_init(&hctx);
HMAC_Init_ex(&hctx, mac_key, sizeof(mac_key), EVP_sha1(), NULL);
HMAC_Update(&hctx, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset + IV_SIZE);
HMAC_Update(&hctx, (const unsigned char*)& nPage, sizeof(nPage));
HMAC_Final(&hctx, hash_mac, &hash_len);
HMAC_CTX_cleanup(&hctx);
if (0 != memcmp(hash_mac, pTemp + DEFAULT_PAGESIZE - reserve + IV_SIZE, sizeof(hash_mac)))
{
printf("\n 哈希值錯誤! \n");
getchar();
return 0;
}
#endif
//
if (nPage == 1)
{
memcpy(pDecryptPerPageBuffer, SQLITE_FILE_HEADER, offset);
}
EVP_CIPHER_CTX* ectx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ectx, EVP_get_cipherbyname("aes-256-cbc"), NULL, NULL, NULL, 0);
EVP_CIPHER_CTX_set_padding(ectx, 0);
EVP_CipherInit_ex(ectx, NULL, NULL, key, pTemp + (DEFAULT_PAGESIZE - reserve), 0);
int nDecryptLen = 0;
int nTotal = 0;
EVP_CipherUpdate(ectx, pDecryptPerPageBuffer + offset, &nDecryptLen, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset);
nTotal = nDecryptLen;
EVP_CipherFinal_ex(ectx, pDecryptPerPageBuffer + offset + nDecryptLen, &nDecryptLen);
nTotal += nDecryptLen;
EVP_CIPHER_CTX_free(ectx);
memcpy(pDecryptPerPageBuffer + DEFAULT_PAGESIZE - reserve, pTemp + DEFAULT_PAGESIZE - reserve, reserve);
char decFile[1024] = { 0 };
sprintf_s(decFile, "dec_%s", dbfilename);
FILE * fp;
fopen_s(&fp, decFile, "ab+");
{
fwrite(pDecryptPerPageBuffer, 1, DEFAULT_PAGESIZE, fp);
fclose(fp);
}
nPage++;
offset = 0;
pTemp += DEFAULT_PAGESIZE;
}
printf("\n 解密成功! \n");
return 0;
}替換pass[] 的值為第一步獲取的 密碼:(轉換成0x格式的密碼值)
//pc端密碼是經過OllyDbg得到的32位pass。
unsigned char pass[] = {}
//本文獲取的密碼為:
{0x71,0x1A,0x1F,0xFA,0x27,0xE6,0x41,0xD9,0xAB,0x8E,0x8D,0xC0,0xF1,0x8A,0xF9,0x66,0x76,0x11,0x6F,0xEF,0x95,0x30,0x48,0x91,0xB3,0x9B,0x40,0x9B,0x57,0xB1,0x35,0x00}替換好後將代碼複製到剛才在visual studio創建的 dewechatdb.cpp 中(刪除默認生成的hello world代碼):
點擊「本地windows調試器」(或者按F5鍵),如果前面的步驟操作都正確,應該可以完成編譯並自動運行,彈出一個命令行窗口,提示需要輸入文件名則為成功:
編譯成功,生成了 D:\wwwcode\c\dewechatdb\Debug\dewechatdb.exe 文件,將dewechatdb.exe 複製到微信的資料庫文件夾中,
默認安裝微信的文件夾路徑為:C:\Users\Administrator\Documents\WeChat Files\********\Msg ,
如果找不到路徑可以在微信設置--> 文件管理 中找到,可以使用打開文件夾 按鈕直接打開:
//使用:
dewechatdb.exe 資料庫名解密 ChatMsg.db 這個庫:
dewechatdb.exe ChatMsg.db解密成功後會生成 dec_ChatMsg.db 文件,即為解密後的資料庫文件,使用 DB Browser for SQLite 工具打開即可查看內容:
解密後的數據(微信聊天記錄):
到此解密完成。
4、常見問題匯總(踩坑記錄)Q1:為什麼我下載的openssl裡面沒有lib目錄,而且include內為空?
A1: openssl 下載後需要編譯(win安裝的openssl 會出現位置錯誤),才會有lib目錄 和include裡面的內容,本文已打包include和lib文件夾。
Q2: 設置斷點之後微信就顯示無法獲取二維碼或者無法登陸?
A2:OD 版本問題可以換一個OD試一試(建議使用與本文一致的OD),或者是 設置好斷點後 沒有點擊運行 。
Q3: 為什麼編譯完成後使用生成的exe解密時顯示「打開文件錯」?
A3:經過測試是因為在解密時微信是在登錄狀態,所以在解密資料庫文件時要退出微信(一定還有其他情況會提示「打開文件錯」,我沒遇到)。
Q4: 編譯好的exe 運行時提示缺少libeay32.dll文件?
A4:下載一個根據系統版本放在指定的目錄內就可以了:https://cn.dll-files.com/libeay32.dll.html
下載後會有教程: