终于找到微信聊天记录SQLite数据库文件解密方法了,一起来看看吧!

本文主要是介绍终于找到微信聊天记录SQLite数据库文件解密方法了,一起来看看吧!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://github.com/xuchengsheng/

图片

  • 获取当前登录微信的微信昵称、账号、手机号、邮箱、秘钥、微信Id、文件夹路径

  • 将微信PC的多个聊天记录数据库合并为单一数据库文件

  • 支持微信聊天对话窗口(文本消息,引用消息,图片消息,表情消息,卡片链接消息,系统消息,等)

  • 综合管理微信会话、联系人、群聊与朋友圈

  • 支持导出微信各类记录(聊天记录,联系人,群聊,等)

  • 查看历史朋友圈记录,超越三日限制,随时回看朋友圈历史

  • 展示好友数、群聊数及今日收发消息总量的微信统计功能

  • 过去15天内每日微信消息数量统计

  • 最近一个月内微信互动最频繁的前10位联系人

  • 展示微信消息类别占比图表

  • 展示微信最近使用的关键字词云图

图片

图片

图片

图片

图片

图片

图片

图片

图片

🚀快速启动

安装包方式部署

  • 点击下载 wx-dump-4j-bin.tar.gz

  • 解压缩 wx-dump-4j-bin.tar.gz,进入 bin 目录

  • 双击start.bat启动文件

  • 启动成功后访问:http://localhost:8080

源码方式部署

  • 下载源码git clone https://github.com/xuchengsheng/wx-dump-4j.git

  • 安装后端依赖cd wx-dump-4j & mvn clean install

  • 使用开发工具启动 com.xcs.wx.WxDumpApplication

  • 安装前端依赖cd wx-dump-ui & npm install

  • 启动前端服务npm run start

  • 访问:http://localhost:8000

📚实现原理

  • 微信SQLite数据库文件解密实现,基于HmacSHA1的安全解密算法

⛔️使用限制

本软件仅适用于Windows操作系统。我们目前不支持macOS、Linux或其他操作系统。如果你在尝试在非Windows系统上运行本软件时可能遇到兼容性问题,这些问题可能导致软件无法正常运行或产生其他意外后果。

操作系统支持情况
Windows支持
macOS不支持
Linux不支持

微信SQLite数据库文件解密实现

  • 微信SQLite数据库文件解密实现

    • SQLite页结构描述

    • SQLite页结构图

    • 解密实现过程

    • 源码地址

SQLite页结构描述

微信SQLite数据库文件以每个页面4096字节的大小进行划分,这些页面组成了文件的基本结构。每个页面内部包含了关键的元素,包括盐值、加密后的内容、初始化向量(IV)、哈希值(hashMac),以及用于保留的空字节。这个结构在整个数据库文件中起到了关键的组织和安全保障的作用。

首个页面是独特的,它包含了生成加密密钥所需的盐值、加密后的内容、初始化向量(IV)、哈希值(hashMac),以及用于保留的空字节。盐值在加密密钥生成过程中发挥着关键的作用,而哈希值则用于验证密钥的正确性,提供了额外的安全层。空字节的存在为未来可能的拓展或变化预留了空间。

随后的页面结构与首个页面相似,仍然包括了加密后的内容、初始化向量(IV)以及用于保留的空字节。这种一致性的结构确保了整个数据库文件的统一性和安全性,使得每个页面都能够独立存储经过加密的数据块,并在需要时通过初始化向量进行解密。这种巧妙的设计使得SQLite数据库文件在存储和保护数据方面表现出色。

SQLite页结构图

图片

解密实现过程

DecryptServiceImpl类是一个解密服务的实现,专门用于解密SQLite数据库文件。首先,它定义了SQLite数据库文件的文件头、加密算法(HmacSHA1)、页面大小(4096字节)、迭代次数(64000次)以及密钥长度(32字节)。主要功能由wechatDecrypt方法实现,该方法接收密码和解密业务对象作为参数。

wechatDecrypt方法内部,首先通过FileInputStream读取数据库文件内容,提取文件头、盐值、第一页信息,包括内容、IV、hashMac和保留字段。随后,利用PBKDF2算法和用户提供的密码生成密钥,并根据提取的盐值和hashMac验证密钥的正确性。

如果密钥验证成功,便创建输出文件,写入SQLite文件头,并对第一页进行解密,写入解密后的内容和保留字段。接着,循环处理后续数据块,逐一解密并写入到输出文件。整个过程保证了对SQLite数据库文件的完整性和保密性的维护。

在解密过程中,doDecrypt方法使用AES/CBC/NoPadding模式对数据进行解密。为了处理大文件,splitDataPages方法将文件内容分割成多个页面进行逐一处理。

最后,通过checkKey方法检查密钥的有效性,确保解密过程中密钥的正确性。该类结合了多重密码学技术,保障了对SQLite数据库文件的高效且安全的解密操作。

public class DecryptServiceImpl implements DecryptService {
    /**     * SQLite数据库的文件头     */    private static final String SQLITE_FILE_HEADER = "SQLite format 3\u0000";
    /**     * 算法     */    private static final String ALGORITHM = "HmacSHA1";
    /**     * 一页的大小     */    private static final int DEFAULT_PAGESIZE = 4096;
    /**     * 迭代次数     */    private static final int ITERATIONS = 64000;
    /**     * Key长度     */    private static final int HASH_KEY_LENGTH = 32;
    @Override    public void wechatDecrypt(String password, DecryptBO decryptBO) {        // 创建File文件        File file = new File(decryptBO.getInput());
        try (FileInputStream fis = new FileInputStream(file)) {            // 文件大小            byte[] fileContent = new byte[(int) file.length()];            // 读取内容            fis.read(fileContent);
            // 提取盐值            byte[] salt = Arrays.copyOfRange(fileContent, 0, 16);            // 提取第一页            byte[] firstPage = Arrays.copyOfRange(fileContent, 16, DEFAULT_PAGESIZE);            // 提取第一页的内容与IV            byte[] firstPageBodyAndIv = Arrays.copyOfRange(firstPage, 0, firstPage.length - 32);            // 提取第一页的内容            byte[] firstPageBody = Arrays.copyOfRange(firstPage, 0, firstPage.length - 48);            // 提取第一页IV            byte[] firstPageIv = Arrays.copyOfRange(firstPage, firstPage.length - 48, firstPage.length - 32);            // 提取第一页的hashMac            byte[] firstPageHashMac = Arrays.copyOfRange(firstPage, firstPage.length - 32, firstPage.length - 12);            // 提取第一页的保留字段            byte[] firstPageReservedSegment = Arrays.copyOfRange(firstPage, firstPage.length - 48, firstPage.length);
            // 生成key            byte[] key = Pbkdf2HmacUtil.pbkdf2Hmac(ALGORITHM, HexUtil.decodeHex(password), salt, ITERATIONS, HASH_KEY_LENGTH);
            byte[] macSalt = new byte[salt.length];            for (int i = 0; i < salt.length; i++) {                macSalt[i] = (byte) (salt[i] ^ 58);            }            // 秘钥匹配成功            if (checkKey(key, macSalt, firstPageHashMac, firstPageBodyAndIv)) {                File outputFile = new File(decryptBO.getOutput());                File parentDir = outputFile.getParentFile();
                // 检查父目录是否存在,如果不存在,则创建                if (!parentDir.exists()) {                    parentDir.mkdirs();                }
                // 解密并写入新文件                try (FileOutputStream deFile = new FileOutputStream(outputFile)) {                    deFile.write(SQLITE_FILE_HEADER.getBytes());                    deFile.write(doDecrypt(key, firstPageIv, firstPageBody));                    deFile.write(firstPageReservedSegment);                    // 解密后续数据块                    for (byte[] page : splitDataPages(fileContent)) {                        byte[] iv = Arrays.copyOfRange(page, page.length - 48, page.length - 32);                        byte[] body = Arrays.copyOfRange(page, 0, page.length - 48);                        byte[] reservedSegment = Arrays.copyOfRange(page, page.length - 48, page.length);                        deFile.write(doDecrypt(key, iv, body));                        deFile.write(reservedSegment);                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }    }
    /**     * 使用AES/CBC/NoPadding模式进行解密     *     * @param key   密钥     * @param iv    初始化向量     * @param input 待解密的数据     * @return 解密后的数据     * @throws GeneralSecurityException 抛出异常     */    private byte[] doDecrypt(byte[] key, byte[] iv, byte[] input) throws GeneralSecurityException {        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");        SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);        return cipher.doFinal(input);    }
    /**     * 将数据分割成多个页面     *     * @param fileContent 文件内容的字节数组     * @return 分割后的页面列表     */    private List<byte[]> splitDataPages(byte[] fileContent) {        List<byte[]> pages = new ArrayList<>();        for (int i = DEFAULT_PAGESIZE; i < fileContent.length; i += DEFAULT_PAGESIZE) {            // 计算每个分割页面的结束位置            int end = Math.min(i + DEFAULT_PAGESIZE, fileContent.length);            byte[] slice = new byte[end - i];            // 将数据复制到新的页面中            System.arraycopy(fileContent, i, slice, 0, slice.length);            pages.add(slice);        }        return pages;    }
    /**     * 检查密钥是否有效     *     * @param byteKey 密钥的字节数组     * @param macSalt MAC盐值     * @param hashMac 预期的MAC哈希值     * @param message 消息内容     * @return 如果密钥有效返回true,否则返回false     * @throws Exception 抛出异常     */    private boolean checkKey(byte[] byteKey, byte[] macSalt, byte[] hashMac, byte[] message) throws Exception {        // 使用PBKDF2算法生成MAC密钥        byte[] macKey = Pbkdf2HmacUtil.pbkdf2Hmac(ALGORITHM, byteKey, macSalt, 2, 32);        Mac mac = Mac.getInstance(ALGORITHM);        SecretKeySpec keySpec = new SecretKeySpec(macKey, ALGORITHM);        mac.init(keySpec);        // 更新MAC计算的消息内容        mac.update(message);        // 添加额外的数据到消息中        mac.update(new byte[]{1, 0, 0, 0});        // 比较计算出的MAC值和预期的MAC值是否相同        return Arrays.equals(hashMac, mac.doFinal());    }}

  • https://github.com/xuchengsheng/wx-dump-4j

  • com.xcs.wx.service.impl.DecryptServiceImpl

这篇关于终于找到微信聊天记录SQLite数据库文件解密方法了,一起来看看吧!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/970027

相关文章

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

idea maven编译报错Java heap space的解决方法

《ideamaven编译报错Javaheapspace的解决方法》这篇文章主要为大家详细介绍了ideamaven编译报错Javaheapspace的相关解决方法,文中的示例代码讲解详细,感兴趣的... 目录1.增加 Maven 编译的堆内存2. 增加 IntelliJ IDEA 的堆内存3. 优化 Mave

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与

一文详解JavaScript中的fetch方法

《一文详解JavaScript中的fetch方法》fetch函数是一个用于在JavaScript中执行HTTP请求的现代API,它提供了一种更简洁、更强大的方式来处理网络请求,:本文主要介绍Jav... 目录前言什么是 fetch 方法基本语法简单的 GET 请求示例代码解释发送 POST 请求示例代码解释

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

CSS去除a标签的下划线的几种方法

《CSS去除a标签的下划线的几种方法》本文给大家分享在CSS中,去除a标签(超链接)的下划线的几种方法,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧... 在 css 中,去除a标签(超链接)的下划线主要有以下几种方法:使用text-decoration属性通用选择器设置:使用a标签选择器,将tex

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.