首页 > 数据库 >劫持微信聊天记录并分析还原 —— 解密数据库(二)

劫持微信聊天记录并分析还原 —— 解密数据库(二)

时间:2024-11-05 18:10:43浏览次数:1  
标签:微信 db 解密 聊天记录 key error path os out

  • 本工具设计的初衷是用来获取微信账号的相关信息并解析PC版微信的数据库。

  • 程序以 Python 语言开发,可读取、解密、还原微信数据库并帮助用户查看聊天记录,还可以将其聊天记录导出为csv、html等格式用于AI训练,自动回复或备份等等作用。下面我们将深入探讨这个工具的各个方面及其工作原理。


【完整演示工具下载】

https://www.chwm.vip/index.html?aid=23


  1. 我们先根据上一篇文章《劫持微信聊天记录并分析还原 —— 帐号信息截取(一)》截取的帐号信息来尝试解密微信数据库。

  1. 详细命令:
    decrypt -k "04395c**********5e47d8" -i "C:\Users\admin\Documents\WeChat Files\wxid_b11\Msg" -o "C:\Users\admin\AppData\Local\Temp\wx_tmp"

3.参数详解:
-k 为指定key密匙 04395c******************************5e47d8
-i 为微信数据库路径 wx_dir + Msg
-o 为解密存放的路径  C:\Users\admin\AppData\Local\Temp\wx_tmp(系统临时目录)

  1. 然后我们可以看到提示解密 114 个文件,成功 36 个,失败 78 个。其中显示失败的文件我们可以忽略(因为有些并不是数据库文件),只要有一个成功的那么就是解密成功。


部分实现代码

# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name:         decryption.py
# Description:
# Author:       Rainbow
# Date:         2024/11/05
# 微信数据库采用的加密算法是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]

@wx_core_error
def batch_decrypt(key: str, db_path: Union[str, List[str]], out_path: str, is_print: bool = False):
    """
    批量解密数据库
    :param key: 密钥 64位16进制字符串
    :param db_path: 待解密的数据库路径(文件或文件夹)
    :param out_path: 解密后的数据库输出路径(文件夹)
    :param is_logging: 是否打印日志
    :return: (bool, [[input_db_path, output_db_path, key],...])
    """
    if not isinstance(key, str) or not isinstance(out_path, str) or not os.path.exists(out_path) or len(key) != 64:
        error = f"[-] (key:'{key}' or out_path:'{out_path}') Error!"
        wx_core_loger.error(error, exc_info=True)
        return False, error

    process_list = []

    if isinstance(db_path, str):
        if not os.path.exists(db_path):
            error = f"[-] db_path:'{db_path}' not found!"
            wx_core_loger.error(error, exc_info=True)
            return False, error

        if os.path.isfile(db_path):
            inpath = db_path
            outpath = os.path.join(out_path, 'de_' + os.path.basename(db_path))
            process_list.append([key, inpath, outpath])

        elif os.path.isdir(db_path):
            for root, dirs, files in os.walk(db_path):
                for file in files:
                    inpath = os.path.join(root, file)
                    rel = os.path.relpath(root, db_path)
                    outpath = os.path.join(out_path, rel, 'de_' + file)

                    if not os.path.exists(os.path.dirname(outpath)):
                        os.makedirs(os.path.dirname(outpath))
                    process_list.append([key, inpath, outpath])
        else:
            error = f"[-] db_path:'{db_path}' Error "
            wx_core_loger.error(error, exc_info=True)
            return False, error

    elif isinstance(db_path, list):
        rt_path = os.path.commonprefix(db_path)
        if not os.path.exists(rt_path):
            rt_path = os.path.dirname(rt_path)

        for inpath in db_path:
            if not os.path.exists(inpath):
                error = f"[-] db_path:'{db_path}' not found!"
                wx_core_loger.error(error, exc_info=True)
                return False, error

            inpath = os.path.normpath(inpath)
            rel = os.path.relpath(os.path.dirname(inpath), rt_path)
            outpath = os.path.join(out_path, rel, 'de_' + os.path.basename(inpath))
            if not os.path.exists(os.path.dirname(outpath)):
                os.makedirs(os.path.dirname(outpath))
            process_list.append([key, inpath, outpath])
    else:
        error = f"[-] db_path:'{db_path}' Error "
        wx_core_loger.error(error, exc_info=True)
        return False, error

    result = []
    for i in process_list:
        result.append(decrypt(*i))  # 解密

    # 删除空文件夹
    for root, dirs, files in os.walk(out_path, topdown=False):
        for dir in dirs:
            if not os.listdir(os.path.join(root, dir)):
                os.rmdir(os.path.join(root, dir))

    if is_print:
        print("=" * 32)
        success_count = 0
        fail_count = 0
        for code, ret in result:
            if code == False:
                print(ret)
                fail_count += 1
            else:
                print(f'[+] "{ret[0]}" -> "{ret[1]}"')
                success_count += 1
        print("-" * 32)
        print(f"[+] 共 {len(result)} 个文件, 成功 {success_count} 个, 失败 {fail_count} 个")
        print("=" * 32)
    return True, result

标签:微信,db,解密,聊天记录,key,error,path,os,out
From: https://www.cnblogs.com/RainbowTechnology/p/18528483

相关文章

  • springboot+vue城市闪送微信小程序【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着城市化进程的加速,人们对生活便捷性的需求日益增强,特别是在快递配送领域。传统的快递服务虽然覆盖面广,但在即时配送方面往往存在响应慢、成本高的问题。近年来,以“闪送”为代表的即时配送服务迅速崛起,以其高效、灵活的特点满足了城......
  • 代码之眼,陈欣的xml解密之路
         第一章在未来的世界里,科技已经发展到了令人难以想象的地步。人工智能、量子计算和生物技术交织在一起,创造了一个全新的社会形态。在这个世界中,有一个名为“代码守护者”的组织,专门负责维护全球信息系统的安全和稳定。 陈欣是一名年轻的女程序员,她在代码守......
  • 前端开发之jsencrypt加密解密的使用方法和使用示
    1、安装组件npminstalljsencrypt--dev2、创建加密解密的方法文件3、文件内容importJSEncryptfrom'jsencrypt'//去密钥生成网址去生成公钥和密钥http://tools.jb51.net/password/rsa_encodeconstpublicKey='生成的公钥'//前端不建议存放私钥不建议解密数据因......
  • 微信小程序XR黑色背景视频透明效果(二)
    微信官方demo中的removeBlack效果不是很好,匹配度太低,我们直接渲染透明视频第一步类似新建 effect-bgTransparent.tsconstxrFrameSystem=wx.getXrFrameSystem();functioncreateVideoTsbsEffect(scene){returnscene.createEffect({"name":"bgTransparen......
  • KillWxapkg:一款可反编译微信小程序的工具
    原创Eagle1949技术源泉免责声明本程序仅供于学习交流,请使用者遵守《中华人民共和国网络安全法》,勿将此工具用于非授权的测试,开发者不负任何连带法律责任。KillWxapkg是一款自动化反编译微信小程序,小程序安全评估工具,可用来发现小程序安全问题。它支持小程序自动解密,自动......
  • 微信小程序XR黑色背景视频透明效果(一)
    去除黑色背景主要依赖于effect="removeBlack",其中removeBlack为官方demo写的规则,代码如下constxrFrameSystem=wx.getXrFrameSystem();xrFrameSystem.registerEffect('removeBlack',scene=>scene.createEffect({name:"removeBlack",images:[{......
  • H5登录界面输入账号密码,在ios苹果微信手机上输入框上下闪烁问题
    场景描述:H5登录界面输入账号密码,在ios苹果微信手机上输入框上下闪烁问题苹果手机的浏览器就有了自动填充密码的功能,具体来说就是一个手机号密码登录的页面,ios识别到当前页面有密码输入框,所以触发了自动填充密码的功能。解决办法:在2个输入框中间加个隐藏输入框核心代码:<inpu......
  • 微信小程序 thinkphp/laravel小型酒店宾馆管理系统_71z0e
    文章目录项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取项目介绍本文工作研究的主要内容是如何实现酒店信息管理,和酒店各种信息的系统化、规范化和自动化。在设计系统时,分别设......
  • 一学就会!微信自动回复设置方便快捷!
    在忙碌时,如何高效地处理信息成为许多人面临的挑战。今天,就给大家分享一个微信管理系统,通过它的机器人功能,可以让你轻松应对信息的洪流,即使在最忙的时候也不必担心错过重要的消息。1、自动通过好友当有新的好友请求时,系统会根据你的设置自动通过这些请求,这样你就不必每次都手......
  • Vue3 iOS微信JSSDK授权签名错误及图片选择兼容
    iOS微信JSSDK授权签名错误及图片选择兼容一、项目概述二、iOS签名错误invalidsignature三、iOS选择图片转载请注明出处:https://blog.csdn.net/hx7013/article/details/143502680一、项目概述Vue3+Vite+Vue-Router4+JS-SDK1.6由于之前开发调试都是在......