├── LICENSE ├── README.md └── wechat.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 JustYoomoon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WechatDecrypt 2 | 微信消息解密工具 3 | 4 | 5 | ## 使用教程 6 | 編譯,將這個文件拷貝到微信數據庫目錄,一般在這: 7 | 8 | ``` 9 | C:\Users\Administrator\Documents\WeChat Files\********\Msg 10 | ``` 11 | 12 | 星號標記處就是需要解密的微信ID 13 | 14 | 15 | 16 | 如果要解密ChatMsg.db,在CMD執行`dewechat ChatMsg.db`即可。 17 | 18 | 19 | 解密成功後,會輸出`de_ChatMsg.db`,用sqlite打開即可。 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /wechat.cpp: -------------------------------------------------------------------------------- 1 | using namespace std; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #undef _UNICODE 10 | #define SQLITE_FILE_HEADER "SQLite format 3" 11 | #define IV_SIZE 16 12 | #define HMAC_SHA1_SIZE 20 13 | #define KEY_SIZE 32 14 | 15 | #define SL3SIGNLEN 20 16 | 17 | #ifndef ANDROID_WECHAT 18 | #define DEFAULT_PAGESIZE 4096 //4048数据 + 16IV + 20 HMAC + 12 19 | #define DEFAULT_ITER 64000 20 | #else 21 | #define NO_USE_HMAC_SHA1 22 | #define DEFAULT_PAGESIZE 1024 23 | #define DEFAULT_ITER 4000 24 | #endif 25 | //pc端密码是经过OllyDbg得到的32位pass。 26 | 27 | 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 }; 28 | char dbfilename[50]; 29 | int Decryptdb(); 30 | int CheckKey(); 31 | int CheckAESKey(); 32 | int main(int argc, char* argv[]) 33 | { 34 | if (argc >= 2) //第二个参数argv[1]是文件名 35 | strcpy_s(dbfilename, argv[1]); //复制 36 | //没有提供文件名,则提示用户输入 37 | else { 38 | cout << "请输入文件名:" << endl; 39 | cin >> dbfilename; 40 | } 41 | Decryptdb(); 42 | return 0; 43 | } 44 | 45 | int Decryptdb() 46 | { 47 | FILE* fpdb; 48 | fopen_s(&fpdb, dbfilename, "rb+"); 49 | if (!fpdb) 50 | { 51 | printf("打开文件错!"); 52 | getchar(); 53 | return 0; 54 | } 55 | fseek(fpdb, 0, SEEK_END); 56 | long nFileSize = ftell(fpdb); 57 | fseek(fpdb, 0, SEEK_SET); 58 | unsigned char* pDbBuffer = new unsigned char[nFileSize]; 59 | fread(pDbBuffer, 1, nFileSize, fpdb); 60 | fclose(fpdb); 61 | 62 | unsigned char salt[16] = { 0 }; 63 | memcpy(salt, pDbBuffer, 16); 64 | 65 | #ifndef NO_USE_HMAC_SHA1 66 | unsigned char mac_salt[16] = { 0 }; 67 | memcpy(mac_salt, salt, 16); 68 | for (int i = 0; i < sizeof(salt); i++) 69 | { 70 | mac_salt[i] ^= 0x3a; 71 | } 72 | #endif 73 | 74 | int reserve = IV_SIZE; //校验码长度,PC端每4096字节有48字节 75 | #ifndef NO_USE_HMAC_SHA1 76 | reserve += HMAC_SHA1_SIZE; 77 | #endif 78 | reserve = ((reserve % AES_BLOCK_SIZE) == 0) ? reserve : ((reserve / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; 79 | 80 | unsigned char key[KEY_SIZE] = { 0 }; 81 | unsigned char mac_key[KEY_SIZE] = { 0 }; 82 | 83 | OpenSSL_add_all_algorithms(); 84 | PKCS5_PBKDF2_HMAC_SHA1((const char*)pass, sizeof(pass), salt, sizeof(salt), DEFAULT_ITER, sizeof(key), key); 85 | #ifndef NO_USE_HMAC_SHA1 86 | PKCS5_PBKDF2_HMAC_SHA1((const char*)key, sizeof(key), mac_salt, sizeof(mac_salt), 2, sizeof(mac_key), mac_key); 87 | #endif 88 | 89 | unsigned char* pTemp = pDbBuffer; 90 | unsigned char pDecryptPerPageBuffer[DEFAULT_PAGESIZE]; 91 | int nPage = 1; 92 | int offset = 16; 93 | while (pTemp < pDbBuffer + nFileSize) 94 | { 95 | printf("解密数据页:%d/%d \n", nPage, nFileSize / DEFAULT_PAGESIZE); 96 | 97 | #ifndef NO_USE_HMAC_SHA1 98 | unsigned char hash_mac[HMAC_SHA1_SIZE] = { 0 }; 99 | unsigned int hash_len = 0; 100 | HMAC_CTX hctx; 101 | HMAC_CTX_init(&hctx); 102 | HMAC_Init_ex(&hctx, mac_key, sizeof(mac_key), EVP_sha1(), NULL); 103 | HMAC_Update(&hctx, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset + IV_SIZE); 104 | HMAC_Update(&hctx, (const unsigned char*)& nPage, sizeof(nPage)); 105 | HMAC_Final(&hctx, hash_mac, &hash_len); 106 | HMAC_CTX_cleanup(&hctx); 107 | if (0 != memcmp(hash_mac, pTemp + DEFAULT_PAGESIZE - reserve + IV_SIZE, sizeof(hash_mac))) 108 | { 109 | printf("\n 哈希值错误! \n"); 110 | getchar(); 111 | return 0; 112 | } 113 | #endif 114 | // 115 | if (nPage == 1) 116 | { 117 | memcpy(pDecryptPerPageBuffer, SQLITE_FILE_HEADER, offset); 118 | } 119 | 120 | EVP_CIPHER_CTX* ectx = EVP_CIPHER_CTX_new(); 121 | EVP_CipherInit_ex(ectx, EVP_get_cipherbyname("aes-256-cbc"), NULL, NULL, NULL, 0); 122 | EVP_CIPHER_CTX_set_padding(ectx, 0); 123 | EVP_CipherInit_ex(ectx, NULL, NULL, key, pTemp + (DEFAULT_PAGESIZE - reserve), 0); 124 | 125 | int nDecryptLen = 0; 126 | int nTotal = 0; 127 | EVP_CipherUpdate(ectx, pDecryptPerPageBuffer + offset, &nDecryptLen, pTemp + offset, DEFAULT_PAGESIZE - reserve - offset); 128 | nTotal = nDecryptLen; 129 | EVP_CipherFinal_ex(ectx, pDecryptPerPageBuffer + offset + nDecryptLen, &nDecryptLen); 130 | nTotal += nDecryptLen; 131 | EVP_CIPHER_CTX_free(ectx); 132 | 133 | memcpy(pDecryptPerPageBuffer + DEFAULT_PAGESIZE - reserve, pTemp + DEFAULT_PAGESIZE - reserve, reserve); 134 | char decFile[1024] = { 0 }; 135 | sprintf_s(decFile, "dec_%s", dbfilename); 136 | FILE * fp; 137 | fopen_s(&fp, decFile, "ab+"); 138 | { 139 | fwrite(pDecryptPerPageBuffer, 1, DEFAULT_PAGESIZE, fp); 140 | fclose(fp); 141 | } 142 | 143 | nPage++; 144 | offset = 0; 145 | pTemp += DEFAULT_PAGESIZE; 146 | } 147 | printf("\n 解密成功! \n"); 148 | return 0; 149 | } 150 | 151 | --------------------------------------------------------------------------------