已加密数据库路径:…\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,当然了能逆向出来这个加密算法是最好的,但是也不太现实。