吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 752|回复: 0
收起左侧

[Android 求助] 如何对解密的微信数据库再加密-python

[复制链接]
7Days 发表于 2025-5-30 22:44
25吾爱币
采用GitHub上Pywxdump的代码decryption代码对数据库MSG**.db文件进行了解密,对加密原理不是很了解,想知道如何用python写一个加密算法,使得解密后的文件能够重新加密回去。
目前自己写了一个加密算法,但是对解密后的文件再进行加密后表内的数据丢失,应该是数据的分割、填充和拼接不完全一致,导致数据损坏。请求解决办法。望指点~~~~!
解密的代码网上很多,不过我也放了一份吧。
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name:         getwxinfo.py
# Description:
# Author:       xaoyaoo
# Date:         2023/08/21
# 注:该部分注释为最初学习使用,仅作参考
# 微信数据库采用的加密算法是256位的AES-CBC。数据库的默认的页大小是4096字节即4KB,其中每一个页都是被单独加解密的。
# 加密文件的每一个页都有一个随机的初始化向量,它被保存在每一页的末尾。
# 加密文件的每一页都存有着消息认证码,算法使用的是HMAC-SHA1(安卓数据库使用的是SHA512)。它也被保存在每一页的末尾。
# 每一个数据库文件的开头16字节都保存了一段唯一且随机的盐值,作为HMAC的验证和数据的解密。
# 为了保证数据部分长度是16字节即AES块大小的整倍数,每一页的末尾将填充一段空字节,使得保留字段的长度为48字节。
# 综上,加密文件结构为第一页4KB数据前16字节为盐值,紧接着4032字节数据,再加上16字节IV和20字节HMAC以及12字节空字节;而后的页均是4048字节长度的加密数据段和48字节的保留段。
# -------------------------------------------------------------------------------
import hmac
import hashlib
import os
from typing import Union, List
from Cryptodome.Cipher import AES
# from Crypto.Cipher import AES # 如果上面的导入失败,可以尝试使用这个
 
from utils import wx_core_error, wx_core_loger
 
SQLITE_FILE_HEADER = "SQLite format 3\x00"  # SQLite文件头
 
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
 
 
# 通过密钥解密数据库
@wx_core_error
def decrypt(key: str, db_path: str, out_path: str):
    """
    通过密钥解密数据库
    :param key: 密钥 64位16进制字符串
    :param db_path:  待解密的数据库路径(必须是文件)
    :param out_path:  解密后的数据库输出路径(必须是文件)
    :return:
    """
    if not os.path.exists(db_path) or not os.path.isfile(db_path):
        return False, f"[-] db_path:'{db_path}' File not found!"
    if not os.path.exists(os.path.dirname(out_path)):
        return False, f"[-] out_path:'{out_path}' File not found!"
 
    if len(key) != 64:
        return False, f"[-] key:'{key}' Len Error!"
 
    password = bytes.fromhex(key.strip())
 
    try:
        with open(db_path, "rb") as file:
            blist = file.read()
    except Exception as e:
        return False, f"[-] db_path:'{db_path}' {e}!"
 
    salt = blist[:16]
    first = blist[16:4096]
    if len(salt) != 16:
        return False, f"[-] db_path:'{db_path}' File Error!"
    mac_salt = bytes([(salt[i] ^ 58) for i in range(16)])
    byteHmac = hashlib.pbkdf2_hmac("sha1", password, salt, 64000, KEY_SIZE)
    mac_key = hashlib.pbkdf2_hmac("sha1", byteHmac, mac_salt, 2, KEY_SIZE)
    hash_mac = hmac.new(mac_key, blist[16:4064], hashlib.sha1)
    hash_mac.update(b'\x01\x00\x00\x00')
 
    if hash_mac.digest() != first[-32:-12]:
        return False, f"[-] Key Error! (key:'{key}'; db_path:'{db_path}'; out_path:'{out_path}' )"
 
    with open(out_path, "wb") as deFile:
        deFile.write(SQLITE_FILE_HEADER.encode())
        for i in range(0, len(blist), 4096):
            tblist = blist[i:i + 4096] if i > 0 else blist[16:i + 4096]
            deFile.write(AES.new(byteHmac, AES.MODE_CBC, tblist[-48:-32]).decrypt(tblist[:-48]))
            deFile.write(tblist[-48:])
 
    return True, [db_path, out_path, key]

我的部分有问题的解密的程序如下:
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# -*- coding: utf-8 -*-import hmac
import hashlib
import os
from typing import Union, List
from Cryptodome.Cipher import AES
# from Crypto.Cipher import AES # Alternative import if above fails
 
from utils import wx_core_error, wx_core_loger
 
SQLITE_FILE_HEADER = "SQLite format 3\x00"  # SQLite文件头
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
PAGE_DATA_SIZE = 4064  # 4096 - 32 (16 IV + 16 HMAC/padding)
 
@wx_core_error
def encrypt(key: str, db_path: str, out_path: str):
    """
    通过密钥加密数据库
    :param key: 密钥 64位16进制字符串
    :param db_path:  待加密的数据库路径(必须是文件)
    :param out_path:  加密后的数据库输出路径(必须是文件)
    :return:
    """
    if not os.path.exists(db_path) or not os.path.isfile(db_path):
        return False, f"[-] db_path:'{db_path}' File not found!"
    if not os.path.exists(os.path.dirname(out_path)):
        return False, f"[-] out_path:'{out_path}' File not found!"
 
    if len(key) != 64:
        return False, f"[-] key:'{key}' Len Error!"
 
    password = bytes.fromhex(key.strip())
    original_size = os.path.getsize(db_path)
 
    try:
        with open(db_path, "rb") as file:
            blist = file.read()
    except Exception as e:
        return False, f"[-] db_path:'{db_path}' {e}!"
 
    # 验证SQLite文件头
    if not blist.startswith(SQLITE_FILE_HEADER.encode()):
        return False, f"[-] db_path:'{db_path}' is not a valid SQLite database!"
 
    # 生成盐值
    salt = os.urandom(16)
    mac_salt = bytes([(salt[i] ^ 58) for i in range(16)])
     
    # 生成加密密钥
    byteHmac = hashlib.pbkdf2_hmac("sha1", password, salt, 64000, KEY_SIZE)
    mac_key = hashlib.pbkdf2_hmac("sha1", byteHmac, mac_salt, 2, KEY_SIZE)
 
    with open(out_path, "wb") as encFile:
        # 1. 写入盐值
        encFile.write(salt)
         
        # 2. 处理第一页(特殊处理)
        # 第一页数据范围:从SQLite文件头之后开始,取4032字节
        first_page_data = blist[len(SQLITE_FILE_HEADER):len(SQLITE_FILE_HEADER) + 4032]
         
        # 确保数据长度是16的倍数(AES要求)
        if len(first_page_data) % 16 != 0:
            padding = 16 - (len(first_page_data) % 16)
            first_page_data += bytes(padding)
        else:
            padding = 0
         
        # 生成初始化向量
        iv = os.urandom(16)
         
        # 加密数据
        cipher = AES.new(byteHmac, AES.MODE_CBC, iv)
        encrypted_data = cipher.encrypt(first_page_data)
         
        # 计算HMAC(关键修复:匹配解密时的范围)
        # 解密时验证的是 [16:4064] 范围(加密数据 + IV)
        hmac_data = encrypted_data + iv
        hash_mac = hmac.new(mac_key, hmac_data, hashlib.sha1)
        hash_mac.update(b'\x01\x00\x00\x00'# 与解密过程一致
        page_hmac = hash_mac.digest()[:20# 取前20字节
         
        # 写入第一页(加密数据 + IV + HMAC + 填充)
        encFile.write(encrypted_data)
        encFile.write(iv)
        encFile.write(page_hmac)
        encFile.write(b'\x00' * (12 + padding))  # 填充 + 长度对齐
         
        # 3. 处理剩余页面
        pos = len(SQLITE_FILE_HEADER) + 4032
        while pos < len(blist):
            # 读取4048字节数据(后续页的数据块)
            page_data = blist[pos:pos + 4048]
             
            # 确保数据长度是16的倍数
            if len(page_data) % 16 != 0:
                padding = 16 - (len(page_data) % 16)
                page_data += bytes(padding)
            else:
                padding = 0
             
            # 生成IV
            iv = os.urandom(16)
             
            # 加密数据
            cipher = AES.new(byteHmac, AES.MODE_CBC, iv)
            encrypted_data = cipher.encrypt(page_data)
             
            # 计算HMAC
            hmac_data = encrypted_data + iv
            hash_mac = hmac.new(mac_key, hmac_data, hashlib.sha1)
            hash_mac.update(b'\x01\x00\x00\x00'# 与解密过程一致
            page_hmac = hash_mac.digest()[:20# 取前20字节
             
            # 写入页面
            encFile.write(encrypted_data)
            encFile.write(iv)
            encFile.write(page_hmac)
            encFile.write(b'\x00' * (12 + padding))  # 填充 + 长度对齐
             
            pos += 4048
 
    return True, [db_path, out_path, key]

1748615613751.jpg

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-11-6 19:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表