zoukankan      html  css  js  c++  java
  • 【转载】微信数据库解密算法

    #include "stdafx.h"
    #include <Windows.h>
    #include <openssl/rand.h>
    #include <openssl/evp.h>
    #include <openssl/aes.h>
    #include <openssl/hmac.h>
     
    //#define ANDROID_WECHAT
     
    #define SQLITE_FILE_HEADER "SQLite format 3" //length == 16
    #define IV_SIZE 16
    #define HMAC_SHA1_SIZE 20
    #define KEY_SIZE 32
     
    #ifndef ANDROID_WECHAT
    #define DEFAULT_PAGESIZE 4096
    #define DEFAULT_ITER 64000
    #else
    #define NO_USE_HMAC_SHA1
    #define DEFAULT_PAGESIZE 1024
    #define DEFAULT_ITER 4000
    #endif
    <br>
    //安卓端这里密码是7位,pc端是经过算法得到的32位pass。
    //下面附pc端拿密码的OD图
    unsigned char pass[] = { 0x5C, 0xF8, 0x6A, 0x13, 0x61, 0xA1, 0x46, 0x14, 0x98, 0x6C, 0x2D, 0x6F, 0x5E, 0x6C, 0x16, 0x81, 0xB8, 0xCF, 0x5D, 0x3F, 0xD2, 0xEB, 0x49, 0xCE, 0xAF, 0xFB, 0x88, 0xE3, 0xD8, 0x28, 0xC7, 0xBD };
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        FILE *fpdb = fopen("MicroMsg.db", "rb+");
        if (!fpdb)
        {
            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;
    #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("decrypt page:%d/%d 
    ", nPage, nFileSize / DEFAULT_PAGESIZE);
     
    #ifndef NO_USE_HMAC_SHA1
            //check hmac
            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)))
            {
                //hash check err
                return 0;
            }
    #endif
            //
            if (nPage == 1)
            {
                memcpy(pDecryptPerPageBuffer, SQLITE_FILE_HEADER, offset);
            }
     
            //aes decrypt
            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);
     
            //assert(nTotal == DEFAULT_PAGESIZE - reserve - offset);
     
            //no necessary ,just like sqlcipher
            memcpy(pDecryptPerPageBuffer + DEFAULT_PAGESIZE - reserve, pTemp + DEFAULT_PAGESIZE - reserve, reserve);
     
            FILE *fp = fopen("MicroMsg_Decrypt.db", "ab+");
            {
                fwrite(pDecryptPerPageBuffer, 1, DEFAULT_PAGESIZE, fp);
                fclose(fp);
            }
     
            nPage++;
            offset = 0;
            pTemp += DEFAULT_PAGESIZE;
        }<br>
        return 0;
    }
    

      

  • 相关阅读:
    JAVA后端方面,如何快速达到能实习的程度
    如何高效地把Spring boot学到能干活的程度
    零高并发项目经验的人如何通过面试得到实践机会?
    Java学到什么程度可以面试工作?
    Java培训班学员如何找工作?如何过试用期?
    作为Java技术面试官,我如何深挖候选人的技能
    今年我拿到了期望中的收入,同时更希望能在睡后收入上有进一步的发展——2021年我的总结与思考
    程序员月薪一万到底难不难?
    自学java,如何快速地找到工作
    搞IT的应届生如何写好简历?
  • 原文地址:https://www.cnblogs.com/blck/p/9560305.html
Copyright © 2011-2022 走看看