杂谈 · 2023年5月6日 0

Wechat聊天记录db取证解密

已加密数据库路径:…\WeChat Files\wxid_44cdgh0tng3o41\Msg\Multi

1. 思路

MSGx.db文件一般用AES的64位密钥加密,微信在运行时会将该aeskey放在内存里,因此我们只要知道aeskey到基地址的偏移距离+基地址得到密钥地址,从而读取并解码,用于破解该数据库,最终用数据库软件打开就好。

GetKey.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import pymem
import struct
import binascii

AESKEY_OFFSET = 0x2FFD590
WECHAT_VERSION = "3.9.2.23"

def getAesKey(p):
    # 获取 WeChatWin.dll 的基地址
    base_address = pymem.process.module_from_name(p.process_handle, "wechatwin.dll").lpBaseOfDll

    # 读取 AES Key 的地址
    result = p.read_bytes(base_address + AESKEY_OFFSET, 4)
    addr = struct.unpack("<I", result)[0]

    # 读取 AES Key
    aesKey = p.read_bytes(addr, 0x20)

    # 解码
    result = binascii.b2a_hex(aesKey)
    return base_address, result.decode()

if __name__ == "__main__":
    print(f"微信版本为:{WECHAT_VERSION}\n密钥偏移地址为:{hex(AESKEY_OFFSET)}")
    p = pymem.Pymem()
    p.open_process_from_name("WeChat.exe")
    base_offset, aesKey = getAesKey(p)
    print(f"数据库密钥为:{aesKey}"

DecDB.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import hmac
import ctypes
import hashlib
from Crypto.Cipher import AES

def decrypt_msg(path, password):
    KEY_SIZE = 32
    DEFAULT_ITER = 64000
    DEFAULT_PAGESIZE = 4096  # 4048数据 + 16IV + 20 HMAC + 12
    SQLITE_FILE_HEADER = bytes("SQLite format 3", encoding="ASCII") + bytes(1)  # SQLite 文件头

    with open(path, "rb") as f:
        # TODO: 优化,考虑超大文件
        blist = f.read()

    salt = blist[:16]  # 前16字节为盐
    key = hashlib.pbkdf2_hmac("sha1", password, salt, DEFAULT_ITER, KEY_SIZE)  # 获得Key

    page1 = blist[16:DEFAULT_PAGESIZE]  # 丢掉salt

    mac_salt = bytes([x ^ 0x3a for x in salt])
    mac_key = hashlib.pbkdf2_hmac("sha1", key, mac_salt, 2, KEY_SIZE)

    hash_mac = hmac.new(mac_key, digestmod="sha1")
    hash_mac.update(page1[:-32])
    hash_mac.update(bytes(ctypes.c_int(1)))

    if hash_mac.digest() != page1[-32:-12]:
        raise RuntimeError("Wrong Password")

    pages = [blist[i:i+DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)]
    pages.insert(0, page1)  # 把第一页补上

    with open(f"{path}.dec.db", "wb") as f:
        f.write(SQLITE_FILE_HEADER)  # 写入文件头

        for i in pages:
            t = AES.new(key, AES.MODE_CBC, i[-48:-32])
            f.write(t.decrypt(i[:-48]))
            f.write(i[-48:])

if __name__ == "__main__":
    path = "E:/wechat/documents/WeChat Files/wxid_44cdgh0tng3o41/Msg/Multi/MSG0.db"
    key = bytes.fromhex("cannot tell u ") # 

    decrypt_msg(path, key)

2. 尝试获取新版本3.9.2.23的偏移地址

试了好几个方法和工具但是不知道该搜索什么关键词…

2. 最终实现效果

这里其实是https://github.com/AdminTest0/SharpWxDump这个项目里的源码,里面有写到3.9版本的偏移地址,不过他使用int的十进制,我们用计算器算一下改为0x……就可以了。

这里有两个可能的密钥,每个都试一下:

3. 其他

真无语,统一版本不同设备下的密钥是不同的,这就意味着如果在电脑上有个珍贵的聊天记录数据,有一天这个电脑里的微信崩溃不能运行了,这个记录也恢复不出来…因为目前来说除非获得AES的加密方式(密钥和明文m),否则就只能在微信运行的时候在内存里读取key,当然了能逆向出来这个加密算法是最好的,但是也不太现实。

Reference:

  1. 红队攻防之PC端微信个人信息与聊天记录取证 (qq.com)
  2. 偷偷查看微信聊天记录 (qq.com)
  3. 微信数据库解密wechatgetkey溺阳的博客-CSDN博客
  4. [原创]PC版微信数据库解密详细教程-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)
  5. https://github.com/AdminTest0/SharpWxDump