微信数据库解密逆向
·
微信数据库解密逆向
1. 前置准备
- 准备一台root手机
- 安装xpose框架
- 微信版本8.0.57
2 .获取数据库密码
xposed获取数据库密码如下
XposedHelpers.findAndHookMethod("com.tencent.wcdb.database.SQLiteDatabase",classloader, "openDatabase", "java.lang.String", "byte[]", "com.tencent.wcdb.database.SQLiteCipherSpec", "com.tencent.wcdb.database.SQLiteDatabase$CursorFactory", int.class, "com.tencent.wcdb.DatabaseErrorHandler", int.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String database = (String) param.args[0];
byte[] bytes2 = (byte[]) param.args[1];
if (bytes2 != null) {
XposedBridge.log("Xposed: pwd2=" + new String(bytes2) + ",database=" + database);
}
}
});
3 .使用sqlcipher解密微信数据库
微信的本地数据库存放在 /data/data/com.tencent.mm/MicroMsg里面的一长串字符串的目录里面

工具下载地址:https://download.csdn.net/download/qq_25353539/90793430
命令行参数:
# 假设密码为 "1a2b3c4",路径已用英文命名
sqlcipher-shell32 "C:\wechat\EnMicroMsg.db"
# 输入以下SQL命令
PRAGMA key = '1a2b3c4';
PRAGMA cipher_compatibility = 3;
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter =4000;
PRAGMA cipher_use_hmac = OFF;
.schema -- 成功则显示表结构
python代码如下:
import hashlib
import os
import sqlite3
from Crypto.Cipher import AES
SQLITE_FILE_HEADER = b"SQLite format 3\x00"
KEY_SIZE = 32
DEFAULT_PAGESIZE = 1024
DEFAULT_ITER = 4000
# 通过密钥解密数据库
def decrypt(key: str, db_path, out_path):
"""
通过密钥解密数据库
:param key: 密钥 7位16进制字符串
:param db_path: 待解密的数据库路径(必须是文件)
:param out_path: 解密后的数据库输出路径(必须是文件)
:return:
"""
if not os.path.exists(db_path) or not os.path.isfile(db_path):
raise Exception("db_path must be a file")
with open(db_path, "rb") as file:
blist = file.read()
# 每一个数据库文件的开头16字节都保存了一段唯一且随机的盐值,作为HMAC的验证和数据的解密
salt = blist[:16]
byteKey = hashlib.pbkdf2_hmac('sha1', key.encode(), salt, DEFAULT_ITER, dklen=KEY_SIZE)
first = blist[16:DEFAULT_PAGESIZE]
if len(salt) != 16:
raise Exception("salt must be 16 bytes")
block_sz = 16
reserve_sz = 0
# iv size
iv_sz = 16
# hmac size
hmac_sz = 20
reserve_sz = iv_sz
reserve_sz += hmac_sz
if reserve_sz % block_sz != 0:
reserve_sz = ((reserve_sz // block_sz) + 1) * block_sz
print("reserve_sz:", reserve_sz)
reserve_sz = iv_sz
if reserve_sz % block_sz != 0:
reserve_sz = ((reserve_sz // block_sz) + 1) * block_sz
print("reserve_sz:", reserve_sz)
newblist = [blist[i:i + DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)]
with open(out_path, "wb") as deFile:
deFile.write(SQLITE_FILE_HEADER)
# 第一页前16字节为盐值,紧接着是992字节的加密数据段和16字节的保留段
iv = first[-16:]
t = AES.new(byteKey, AES.MODE_CBC, iv)
decrypted = t.decrypt(first[:-16])
deFile.write(decrypted)
deFile.write(first[-16:])
# 后续页均是1008字节长度的加密数据段和16字节的保留段
for i in newblist:
iv = i[-16:]
t = AES.new(byteKey, AES.MODE_CBC, iv)
decrypted = t.decrypt(i[:-16])
deFile.write(decrypted)
deFile.write(i[-16:])
try:
conn = sqlite3.connect(out_path)
c = conn.cursor()
c.execute("SELECT name FROM sqlite_master WHERE type='table';")
c.close()
conn.close()
except Exception as e:
print("Error: ", e)
return False
return True, [db_path, out_path]
def get_msgdb_key(uin, imei):
key = imei + uin
md5 = hashlib.md5()
md5.update(key.encode('utf-8'))
key = md5.hexdigest()[:7].lower()
print("key:", key)
return key
def parse_contract(db_path):
if not os.path.exists(db_path):
print("DB not found: ", db_path)
return False
conn = sqlite3.connect(db_path)
c = conn.cursor()
users = c.execute("SELECT username, alias, nickname from rcontact WHERE type=1 OR type=8388611")
for user in users:
username = user[0]
alias = user[1]
nickname = user[2]
# 忽略微信团队和文件助手
if username == "weixin" or username == "filehelper":
continue
print(user)
return True
imei = "121213123"
uin = "123123131"
password= get_msgdb_key(uin, imei)
ret = decrypt(password, "c://logs/EnMicroMsg.db", "EnMicroMsg.decrypted.db")
parse_contract("EnMicroMsg.decrypted.db")
备注:此脚本参考 https://www.52pojie.cn/thread-1881980-1-1.html
wechat_msgdb_decrypt
4.后续介绍数据库密码加密算法…
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)