From ff482fc5e129dee7ebe33134429fc6bc71711b9f Mon Sep 17 00:00:00 2001 From: shuaikangzhou <863909694@qq.com> Date: Sun, 12 Nov 2023 21:51:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EPC=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 140 +++++++----- app/DataBase/__init__.py | 4 +- app/DataBase/database.py | 1 - app/DataBase/micro_msg.py | 23 ++ app/Ui/__init__.py | 3 +- app/Ui/pc_decrypt/__init__.py | 0 app/Ui/pc_decrypt/decryptUi.py | 119 ++++++++++ app/Ui/pc_decrypt/decryptUi.ui | 218 ++++++++++++++++++ app/Ui/pc_decrypt/pc_decrypt.py | 152 +++++++++++++ app/config.py | 2 +- app/decrypt/decrypt.py | 125 +++++++++++ app/decrypt/get_wx_info.py | 141 ++++++++++++ app/decrypt/version_list.json | 386 ++++++++++++++++++++++++++++++++ decrypt_window.py | 38 ++++ doc/images/dirs.png | Bin 0 -> 40806 bytes doc/images/pc_decrypt_info.png | Bin 0 -> 14033 bytes doc/images/setting.png | Bin 0 -> 17781 bytes main.py | 17 +- readme.md | 47 +++- requirements.txt | Bin 656 -> 774 bytes 20 files changed, 1347 insertions(+), 69 deletions(-) delete mode 100644 app/DataBase/database.py create mode 100644 app/DataBase/micro_msg.py create mode 100644 app/Ui/pc_decrypt/__init__.py create mode 100644 app/Ui/pc_decrypt/decryptUi.py create mode 100644 app/Ui/pc_decrypt/decryptUi.ui create mode 100644 app/Ui/pc_decrypt/pc_decrypt.py create mode 100644 app/decrypt/decrypt.py create mode 100644 app/decrypt/get_wx_info.py create mode 100644 app/decrypt/version_list.json create mode 100644 decrypt_window.py create mode 100644 doc/images/dirs.png create mode 100644 doc/images/pc_decrypt_info.png create mode 100644 doc/images/setting.png diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 55ddfbf..aad5cd3 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,14 +4,25 @@ - @@ -609,7 +640,8 @@ - @@ -618,7 +650,7 @@ file://$PROJECT_DIR$/app/DataBase/output.py - 413 + 412 @@ -627,9 +659,9 @@ - file://$PROJECT_DIR$/app/Ui/mainview.py - 10 - diff --git a/app/DataBase/__init__.py b/app/DataBase/__init__.py index 171ff5a..94ae7f2 100644 --- a/app/DataBase/__init__.py +++ b/app/DataBase/__init__.py @@ -7,7 +7,7 @@ @Version : Python3.10 @comment : ··· """ -from . import data -from . import output +# from . import data +# from . import output __all__ = ["data", 'output'] diff --git a/app/DataBase/database.py b/app/DataBase/database.py deleted file mode 100644 index 8b13789..0000000 --- a/app/DataBase/database.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/DataBase/micro_msg.py b/app/DataBase/micro_msg.py new file mode 100644 index 0000000..972a258 --- /dev/null +++ b/app/DataBase/micro_msg.py @@ -0,0 +1,23 @@ +import sqlite3 +from pprint import pprint + +DB = sqlite3.connect("./de_MicroMsg.db", check_same_thread=False) +# '''创建游标''' +cursor = DB.cursor() + + +def get_contact(): + sql = '''select UserName,Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl.bigHeadImgUrl + from Contact inner join ContactHeadImgUrl on Contact.UserName = ContactHeadImgUrl.usrName + where Type=3 and Alias is not null + order by PYInitial + ''' + cursor.execute(sql) + result = cursor.fetchall() + pprint(result) + print(len(result)) + return result + + +if __name__ == '__main__': + get_contact() diff --git a/app/Ui/__init__.py b/app/Ui/__init__.py index 730bbfa..380c558 100644 --- a/app/Ui/__init__.py +++ b/app/Ui/__init__.py @@ -13,5 +13,6 @@ from app.Ui import mainview # 文件__init__.py # from login import login from app.Ui.decrypt import decrypt +from app.Ui.pc_decrypt import pc_decrypt -__all__ = ["decrypt", 'mainview', 'chat'] +__all__ = ["decrypt", 'mainview', 'chat', 'pc_decrypt'] diff --git a/app/Ui/pc_decrypt/__init__.py b/app/Ui/pc_decrypt/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/Ui/pc_decrypt/decryptUi.py b/app/Ui/pc_decrypt/decryptUi.py new file mode 100644 index 0000000..545cf46 --- /dev/null +++ b/app/Ui/pc_decrypt/decryptUi.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'decryptUi.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 300) + font = QtGui.QFont() + font.setFamily("微软雅黑") + Dialog.setFont(font) + self.label_3 = QtWidgets.QLabel(Dialog) + self.label_3.setGeometry(QtCore.QRect(140, 0, 221, 51)) + font = QtGui.QFont() + font.setFamily("一纸情书") + font.setPointSize(20) + self.label_3.setFont(font) + self.label_3.setObjectName("label_3") + self.progressBar = QtWidgets.QProgressBar(Dialog) + self.progressBar.setGeometry(QtCore.QRect(90, 260, 271, 23)) + self.progressBar.setProperty("value", 50) + self.progressBar.setObjectName("progressBar") + self.btn_getinfo = QtWidgets.QPushButton(Dialog) + self.btn_getinfo.setGeometry(QtCore.QRect(290, 60, 91, 41)) + self.btn_getinfo.setObjectName("btn_getinfo") + self.btn_db_dir = QtWidgets.QPushButton(Dialog) + self.btn_db_dir.setGeometry(QtCore.QRect(20, 210, 91, 41)) + self.btn_db_dir.setObjectName("btn_db_dir") + self.label_db_dir = QtWidgets.QLabel(Dialog) + self.label_db_dir.setGeometry(QtCore.QRect(120, 220, 251, 21)) + self.label_db_dir.setText("") + self.label_db_dir.setObjectName("label_db_dir") + self.label_ready = QtWidgets.QLabel(Dialog) + self.label_ready.setGeometry(QtCore.QRect(40, 260, 41, 21)) + self.label_ready.setObjectName("label_ready") + self.widget = QtWidgets.QWidget(Dialog) + self.widget.setGeometry(QtCore.QRect(20, 50, 221, 151)) + self.widget.setObjectName("widget") + self.gridLayout = QtWidgets.QGridLayout(self.widget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + self.label_wxid = QtWidgets.QLabel(self.widget) + self.label_wxid.setText("") + self.label_wxid.setObjectName("label_wxid") + self.gridLayout.addWidget(self.label_wxid, 4, 1, 1, 1) + self.label = QtWidgets.QLabel(self.widget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtWidgets.QLabel(self.widget) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) + self.label_5 = QtWidgets.QLabel(self.widget) + self.label_5.setObjectName("label_5") + self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) + self.label_4 = QtWidgets.QLabel(self.widget) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1) + self.label_key = QtWidgets.QLabel(self.widget) + self.label_key.setText("") + self.label_key.setObjectName("label_key") + self.gridLayout.addWidget(self.label_key, 5, 1, 1, 1) + self.label_phone = QtWidgets.QLabel(self.widget) + self.label_phone.setText("") + self.label_phone.setObjectName("label_phone") + self.gridLayout.addWidget(self.label_phone, 2, 1, 1, 1) + self.label_6 = QtWidgets.QLabel(self.widget) + self.label_6.setObjectName("label_6") + self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1) + self.label_pid = QtWidgets.QLabel(self.widget) + self.label_pid.setText("") + self.label_pid.setObjectName("label_pid") + self.gridLayout.addWidget(self.label_pid, 0, 1, 1, 1) + self.label_name = QtWidgets.QLabel(self.widget) + self.label_name.setText("") + self.label_name.setObjectName("label_name") + self.gridLayout.addWidget(self.label_name, 3, 1, 1, 1) + self.label_7 = QtWidgets.QLabel(self.widget) + self.label_7.setObjectName("label_7") + self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1) + self.label_version = QtWidgets.QLabel(self.widget) + self.label_version.setText("") + self.label_version.setObjectName("label_version") + self.gridLayout.addWidget(self.label_version, 1, 1, 1, 1) + self.gridLayout.setColumnMinimumWidth(0, 1) + self.gridLayout.setColumnMinimumWidth(1, 2) + self.gridLayout.setRowMinimumHeight(5, 10) + self.gridLayout.setColumnStretch(0, 1) + self.gridLayout.setColumnStretch(1, 3) + self.gridLayout.setRowStretch(5, 10) + self.pushButton_3 = QtWidgets.QPushButton(Dialog) + self.pushButton_3.setGeometry(QtCore.QRect(290, 130, 91, 41)) + self.pushButton_3.setObjectName("pushButton_3") + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.label_3.setText(_translate("Dialog", "解密数据库")) + self.btn_getinfo.setText(_translate("Dialog", "获取信息")) + self.btn_db_dir.setText(_translate("Dialog", "设置微信路径")) + self.label_ready.setText(_translate("Dialog", "未就绪")) + self.label.setText(_translate("Dialog", "PID")) + self.label_2.setText(_translate("Dialog", "手机号")) + self.label_5.setText(_translate("Dialog", "微信昵称")) + self.label_4.setText(_translate("Dialog", "wxid")) + self.label_6.setText(_translate("Dialog", "密钥")) + self.label_7.setText(_translate("Dialog", "版本")) + self.pushButton_3.setText(_translate("Dialog", "开始解密")) diff --git a/app/Ui/pc_decrypt/decryptUi.ui b/app/Ui/pc_decrypt/decryptUi.ui new file mode 100644 index 0000000..a1096c4 --- /dev/null +++ b/app/Ui/pc_decrypt/decryptUi.ui @@ -0,0 +1,218 @@ + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + + 微软雅黑 + + + + Dialog + + + + + 140 + 0 + 221 + 51 + + + + + 一纸情书 + 20 + + + + 解密数据库 + + + + + + 90 + 260 + 271 + 23 + + + + 50 + + + + + + 290 + 60 + 91 + 41 + + + + 获取信息 + + + + + + 20 + 210 + 91 + 41 + + + + 设置微信路径 + + + + + + 120 + 220 + 251 + 21 + + + + + + + + + + 40 + 260 + 41 + 21 + + + + 未就绪 + + + + + + 20 + 50 + 221 + 151 + + + + + + + + + + + + + + PID + + + + + + + 手机号 + + + + + + + 微信昵称 + + + + + + + wxid + + + + + + + + + + + + + + + + + + + + + 密钥 + + + + + + + + + + + + + + + + + + + + + 版本 + + + + + + + + + + + + + + + + 290 + 130 + 91 + 41 + + + + 开始解密 + + + + + + diff --git a/app/Ui/pc_decrypt/pc_decrypt.py b/app/Ui/pc_decrypt/pc_decrypt.py new file mode 100644 index 0000000..6cda791 --- /dev/null +++ b/app/Ui/pc_decrypt/pc_decrypt.py @@ -0,0 +1,152 @@ +import os.path +import time + +from PyQt5 import QtWidgets +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * + +from app.decrypt import get_wx_info, decrypt +from . import decryptUi + + +class DecryptControl(QWidget, decryptUi.Ui_Dialog): + DecryptSignal = pyqtSignal(str) + registerSignal = pyqtSignal(str) + + def __init__(self, parent=None): + super(DecryptControl, self).__init__(parent) + self.setupUi(self) + self.setWindowTitle('解密') + self.setWindowIcon(QIcon('./app/data/icons/logo.svg')) + self.pushButton_3.clicked.connect(self.decrypt) + self.btn_getinfo.clicked.connect(self.get_info) + self.btn_db_dir.clicked.connect(self.select_db_dir) + self.info = {} + self.ready = False + self.wx_dir = None + + def get_info(self): + try: + result = get_wx_info.get_info() + # print(result) + if result: + self.ready = True + self.info = result[0] + self.label_key.setText(self.info['key']) + self.label_wxid.setText(self.info['wxid']) + self.label_name.setText(self.info['name']) + self.label_phone.setText(self.info['mobile']) + self.label_pid.setText(str(self.info['pid'])) + self.label_version.setText(self.info['version']) + if self.wx_dir and os.path.exists(os.path.join(self.wx_dir, self.info['wxid'])): + self.label_ready.setText('已就绪') + except Exception as e: + print(e) + QMessageBox.critical(self, "错误", "请登录微信") + + def select_db_dir(self): + directory = QtWidgets.QFileDialog.getExistingDirectory( + self, "选取微信安装目录——能看到All Users文件夹", + "C:/") # 起始路径 + if directory: + self.label_db_dir.setText(directory) + self.wx_dir = directory + if self.ready: + self.label_ready.setText('已就绪') + + def decrypt(self): + if not self.ready: + QMessageBox.critical(self, "错误", "请先获取密钥") + return + + if self.ready: + if not os.path.exists(os.path.join(self.wx_dir, self.info['wxid'])): + QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以WeChat Files结尾") + return + # self.thread1 = MyThread() + # self.thread1.signal.connect(self.progressBar_view) + # self.thread1.start() + db_dir = os.path.join(self.wx_dir, self.info['wxid'], 'Msg') + self.thread2 = DecryptThread(db_dir, self.info['key']) + self.thread2.maxNumSignal.connect(self.setProgressBarMaxNum) + self.thread2.signal.connect(self.progressBar_view) + self.thread2.okSignal.connect(self.btnExitClicked) + self.thread2.start() + + def btnEnterClicked(self): + # print("enter clicked") + # 中间可以添加处理逻辑 + # QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下") + self.DecryptSignal.emit('ok') + self.close() + + def setProgressBarMaxNum(self, max_val): + self.progressBar.setRange(0, max_val) + + def progressBar_view(self, value): + """ + 进度条显示 + :param value: 进度0-100 + :return: None + """ + self.progressBar.setProperty('value', value) + # self.btnExitClicked() + # data.init_database() + + def btnExitClicked(self): + # print("Exit clicked") + self.DecryptSignal.emit('ok') + self.close() + + +class DecryptThread(QThread): + signal = pyqtSignal(str) + maxNumSignal = pyqtSignal(int) + okSignal = pyqtSignal(str) + + def __init__(self, db_path, key): + super(DecryptThread, self).__init__() + self.db_path = db_path + self.key = key + self.textBrowser = None + + def __del__(self): + pass + + def run(self): + # data.decrypt(self.db_path, self.key) + output_dir = 'app/DataBase/Msg' + if not os.path.exists(output_dir): + os.mkdir(output_dir) + tasks = [] + if os.path.exists(self.db_path): + for root, dirs, files in os.walk(self.db_path): + for file in files: + if '.db' == file[-3:]: + inpath = os.path.join(root, file) + # print(inpath) + output_path = os.path.join(output_dir, file) + tasks.append([self.key, inpath, output_path]) + self.maxNumSignal.emit(len(tasks)) + for i, task in enumerate(tasks): + decrypt.decrypt(*task) + self.signal.emit(str(i + 1)) + # print(self.db_path) + self.okSignal.emit('ok') + # self.signal.emit('100') + + +class MyThread(QThread): + signal = pyqtSignal(str) + + def __init__(self): + super(MyThread, self).__init__() + + def __del__(self): + pass + + def run(self): + for i in range(100): + self.signal.emit(str(i)) + time.sleep(0.1) diff --git a/app/config.py b/app/config.py index 4505531..87ce4e1 100644 --- a/app/config.py +++ b/app/config.py @@ -1,2 +1,2 @@ -version = '0.1.1' +version = '0.2.0' contact = '474379264' diff --git a/app/decrypt/decrypt.py b/app/decrypt/decrypt.py new file mode 100644 index 0000000..dad9e6e --- /dev/null +++ b/app/decrypt/decrypt.py @@ -0,0 +1,125 @@ +import hashlib +import hmac +import os +from typing import Union, List + +from Cryptodome.Cipher import AES + +# from Crypto.Cipher import AES # 如果上面的导入失败,可以尝试使用这个 + +SQLITE_FILE_HEADER = "SQLite format 3\x00" # SQLite文件头 + +KEY_SIZE = 32 +DEFAULT_PAGESIZE = 4096 +DEFAULT_ITER = 64000 + + +# 通过密钥解密数据库 +def decrypt(key: str, db_path, out_path): + if not os.path.exists(db_path): + return f"[-] db_path:'{db_path}' File not found!" + if not os.path.exists(os.path.dirname(out_path)): + return f"[-] out_path:'{out_path}' File not found!" + if len(key) != 64: + return f"[-] key:'{key}' Error!" + password = bytes.fromhex(key.strip()) + with open(db_path, "rb") as file: + blist = file.read() + + salt = blist[:16] + byteKey = hashlib.pbkdf2_hmac("sha1", password, salt, DEFAULT_ITER, KEY_SIZE) + first = blist[16:DEFAULT_PAGESIZE] + + mac_salt = bytes([(salt[i] ^ 58) for i in range(16)]) + mac_key = hashlib.pbkdf2_hmac("sha1", byteKey, mac_salt, 2, KEY_SIZE) + hash_mac = hmac.new(mac_key, first[:-32], hashlib.sha1) + hash_mac.update(b'\x01\x00\x00\x00') + + if hash_mac.digest() != first[-32:-12]: + return f"[-] Password Error! (key:'{key}'; db_path:'{db_path}'; out_path:'{out_path}' )" + + 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.encode()) + t = AES.new(byteKey, AES.MODE_CBC, first[-48:-32]) + decrypted = t.decrypt(first[:-48]) + deFile.write(decrypted) + deFile.write(first[-48:]) + + for i in newblist: + t = AES.new(byteKey, AES.MODE_CBC, i[-48:-32]) + decrypted = t.decrypt(i[:-48]) + deFile.write(decrypted) + deFile.write(i[-48:]) + return [True, db_path, out_path, key] + + +def batch_decrypt(key: str, db_path: Union[str, List[str]], out_path: str): + if not isinstance(key, str) or not isinstance(out_path, str) or not os.path.exists(out_path) or len(key) != 64: + return f"[-] (key:'{key}' or out_path:'{out_path}') Error!" + + process_list = [] + + if isinstance(db_path, str): + if not os.path.exists(db_path): + return f"[-] db_path:'{db_path}' not found!" + + 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: + return f"[-] db_path:'{db_path}' 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): + return f"[-] db_path:'{db_path}' not found!" + + 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: + return f"[-] db_path:'{db_path}' 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)) + return result + + +if __name__ == '__main__': + # 调用 decrypt 函数,并传入参数 + key = "2aafab10af7940328bb92ac9d2a8ab5fc07a685646b14f2e9ae6948a7060c0fc" + db_path = "D:\Project\Python\PyWxDump\pywxdump\decrypted" + out_path = "test" + result = batch_decrypt(key, db_path, out_path) + for i in result: + if isinstance(i, str): + print(i) + else: + print(f'[+] "{i[1]}" -> "{i[2]}"') diff --git a/app/decrypt/get_wx_info.py b/app/decrypt/get_wx_info.py new file mode 100644 index 0000000..c942c14 --- /dev/null +++ b/app/decrypt/get_wx_info.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*-# +# ------------------------------------------------------------------------------- +# Name: getwxinfo.py +# Description: +# Author: xaoyaoo +# Date: 2023/08/21 +# ------------------------------------------------------------------------------- +import argparse +import ctypes +import json + +import psutil +from win32com.client import Dispatch + +ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory +void_p = ctypes.c_void_p + + +# 读取内存中的字符串(非key部分) +def get_info_without_key(h_process, address, n_size=64): + array = ctypes.create_string_buffer(n_size) + if ReadProcessMemory(h_process, void_p(address), array, n_size, 0) == 0: return "None" + array = bytes(array).split(b"\x00")[0] if b"\x00" in array else bytes(array) + text = array.decode('utf-8', errors='ignore') + return text.strip() if text.strip() != "" else "None" + + +def get_info_wxid(h_process, address, n_size=32, address_len=8): + array = ctypes.create_string_buffer(address_len) + if ReadProcessMemory(h_process, void_p(address), array, address_len, 0) == 0: return "None" + address = int.from_bytes(array, byteorder='little') # 逆序转换为int地址(key地址) + wxid = get_info_without_key(h_process, address, n_size) + if not wxid.startswith("wxid_"): wxid = "None" + return wxid + + +# 读取内存中的key +def get_key(h_process, address, address_len=8): + array = ctypes.create_string_buffer(address_len) + if ReadProcessMemory(h_process, void_p(address), array, address_len, 0) == 0: return "None" + address = int.from_bytes(array, byteorder='little') # 逆序转换为int地址(key地址) + key = ctypes.create_string_buffer(32) + if ReadProcessMemory(h_process, void_p(address), key, 32, 0) == 0: return "None" + key_string = bytes(key).hex() + return key_string + + +# 读取微信信息(account,mobile,name,mail,wxid,key) +def read_info(version_list): + wechat_process = [] + result = [] + + for process in psutil.process_iter(['name', 'exe', 'pid', 'cmdline']): + if process.name() == 'WeChat.exe': + wechat_process.append(process) + + if len(wechat_process) == 0: + return "[-] WeChat No Run" + + for process in wechat_process: + tmp_rd = {} + + tmp_rd['pid'] = process.pid + tmp_rd['version'] = Dispatch("Scripting.FileSystemObject").GetFileVersion(process.exe()) + + bias_list = version_list.get(tmp_rd['version'], None) + if not isinstance(bias_list, list): + return f"[-] WeChat Current Version {tmp_rd['version']} Is Not Supported" + + wechat_base_address = 0 + for module in process.memory_maps(grouped=False): + if module.path and 'WeChatWin.dll' in module.path: + wechat_base_address = int(module.addr, 16) + break + if wechat_base_address == 0: + return f"[-] WeChat WeChatWin.dll Not Found" + + Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, process.pid) + + name_baseaddr = wechat_base_address + bias_list[0] + account__baseaddr = wechat_base_address + bias_list[1] + mobile_baseaddr = wechat_base_address + bias_list[2] + mail_baseaddr = wechat_base_address + bias_list[3] + key_baseaddr = wechat_base_address + bias_list[4] + wxid_baseaddr = wechat_base_address + bias_list[5] + + addrLen = 4 if tmp_rd['version'] in ["3.9.2.23", "3.9.2.26"] else 8 + + tmp_rd['account'] = get_info_without_key(Handle, account__baseaddr, 32) if bias_list[1] != 0 else "None" + tmp_rd['mobile'] = get_info_without_key(Handle, mobile_baseaddr, 64) if bias_list[2] != 0 else "None" + tmp_rd['name'] = get_info_without_key(Handle, name_baseaddr, 64) if bias_list[0] != 0 else "None" + tmp_rd['mail'] = get_info_without_key(Handle, mail_baseaddr, 64) if bias_list[3] != 0 else "None" + tmp_rd['wxid'] = get_info_wxid(Handle, wxid_baseaddr, 24, addrLen) if bias_list[5] != 0 else "None" + tmp_rd['key'] = get_key(Handle, key_baseaddr, addrLen) if bias_list[4] != 0 else "None" + result.append(tmp_rd) + + return result + + +def get_info(): + VERSION_LIST_PATH = "app/decrypt/version_list.json" + + with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f: + VERSION_LIST = json.load(f) + + result = read_info(VERSION_LIST) # 读取微信信息 + return result + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--vlfile", type=str, help="手机号", required=False) + parser.add_argument("--vldict", type=str, help="微信昵称", required=False) + + args = parser.parse_args() + + # 读取微信各版本偏移 + if args.vlfile: + VERSION_LIST_PATH = args.vlfile + with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f: + VERSION_LIST = json.load(f) + if args.vldict: + VERSION_LIST = json.loads(args.vldict) + + if not args.vlfile and not args.vldict: + VERSION_LIST_PATH = "./version_list.json" + + with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f: + VERSION_LIST = json.load(f) + + result = read_info(VERSION_LIST) # 读取微信信息 + + print("=" * 32) + if isinstance(result, str): # 输出报错 + print(result) + else: # 输出结果 + for i, rlt in enumerate(result): + for k, v in rlt.items(): + print(f"[+] {k:>7}: {v}") + print(end="-" * 32 + "\n" if i != len(result) - 1 else "") + print("=" * 32) diff --git a/app/decrypt/version_list.json b/app/decrypt/version_list.json new file mode 100644 index 0000000..b525952 --- /dev/null +++ b/app/decrypt/version_list.json @@ -0,0 +1,386 @@ +{ + "3.2.1.154": [ + 328121948, + 328122328, + 328123056, + 328121976, + 328123020, + 0 + ], + "3.3.0.115": [ + 31323364, + 31323744, + 31324472, + 31323392, + 31324436, + 0 + ], + "3.3.0.84": [ + 31315212, + 31315592, + 31316320, + 31315240, + 31316284, + 0 + ], + "3.3.0.93": [ + 31323364, + 31323744, + 31324472, + 31323392, + 31324436, + 0 + ], + "3.3.5.34": [ + 30603028, + 30603408, + 30604120, + 30603056, + 30604100, + 0 + ], + "3.3.5.42": [ + 30603012, + 30603392, + 30604120, + 30603040, + 30604084, + 0 + ], + "3.3.5.46": [ + 30578372, + 30578752, + 30579480, + 30578400, + 30579444, + 0 + ], + "3.4.0.37": [ + 31608116, + 31608496, + 31609224, + 31608144, + 31609188, + 0 + ], + "3.4.0.38": [ + 31604044, + 31604424, + 31605152, + 31604072, + 31605116, + 0 + ], + "3.4.0.50": [ + 31688500, + 31688880, + 31689608, + 31688528, + 31689572, + 0 + ], + "3.4.0.54": [ + 31700852, + 31701248, + 31700920, + 31700880, + 31701924, + 0 + ], + "3.4.5.27": [ + 32133788, + 32134168, + 32134896, + 32133816, + 32134860, + 0 + ], + "3.4.5.45": [ + 32147012, + 32147392, + 32147064, + 32147040, + 32148084, + 0 + ], + "3.5.0.20": [ + 35494484, + 35494864, + 35494536, + 35494512, + 35495556, + 0 + ], + "3.5.0.29": [ + 35507980, + 35508360, + 35508032, + 35508008, + 35509052, + 0 + ], + "3.5.0.33": [ + 35512140, + 35512520, + 35512192, + 35512168, + 35513212, + 0 + ], + "3.5.0.39": [ + 35516236, + 35516616, + 35516288, + 35516264, + 35517308, + 0 + ], + "3.5.0.42": [ + 35512140, + 35512520, + 35512192, + 35512168, + 35513212, + 0 + ], + "3.5.0.44": [ + 35510836, + 35511216, + 35510896, + 35510864, + 35511908, + 0 + ], + "3.5.0.46": [ + 35506740, + 35507120, + 35506800, + 35506768, + 35507812, + 0 + ], + "3.6.0.18": [ + 35842996, + 35843376, + 35843048, + 35843024, + 35844068, + 0 + ], + "3.6.5.7": [ + 35864356, + 35864736, + 35864408, + 35864384, + 35865428, + 0 + ], + "3.6.5.16": [ + 35909428, + 35909808, + 35909480, + 35909456, + 35910500, + 0 + ], + "3.7.0.26": [ + 37105908, + 37106288, + 37105960, + 37105936, + 37106980, + 0 + ], + "3.7.0.29": [ + 37105908, + 37106288, + 37105960, + 37105936, + 37106980, + 0 + ], + "3.7.0.30": [ + 37118196, + 37118576, + 37118248, + 37118224, + 37119268, + 0 + ], + "3.7.5.11": [ + 37883280, + 37884088, + 37883136, + 37883008, + 37884052, + 0 + ], + "3.7.5.23": [ + 37895736, + 37896544, + 37895592, + 37883008, + 37896508, + 0 + ], + "3.7.5.27": [ + 37895736, + 37896544, + 37895592, + 37895464, + 37896508, + 0 + ], + "3.7.5.31": [ + 37903928, + 37904736, + 37903784, + 37903656, + 37904700, + 0 + ], + "3.7.6.24": [ + 38978840, + 38979648, + 38978696, + 38978604, + 38979612, + 0 + ], + "3.7.6.29": [ + 38986376, + 38987184, + 38986232, + 38986104, + 38987148, + 0 + ], + "3.7.6.44": [ + 39016520, + 39017328, + 39016376, + 38986104, + 39017292, + 0 + ], + "3.8.0.31": [ + 46064088, + 46064912, + 46063944, + 38986104, + 46064876, + 0 + ], + "3.8.0.33": [ + 46059992, + 46060816, + 46059848, + 38986104, + 46060780, + 0 + ], + "3.8.0.41": [ + 46064024, + 46064848, + 46063880, + 38986104, + 46064812, + 0 + ], + "3.8.1.26": [ + 46409448, + 46410272, + 46409304, + 38986104, + 46410236, + 0 + ], + "3.9.0.28": [ + 48418376, + 48419280, + 48418232, + 38986104, + 48419244, + 0 + ], + "3.9.2.23": [ + 50320784, + 50321712, + 50320640, + 38986104, + 50321676, + 50592864 + ], + "3.9.2.26": [ + 50329040, + 50329968, + 50328896, + 38986104, + 50329932, + 0 + ], + "3.9.5.81": [ + 61650872, + 61652208, + 61650680, + 0, + 61652144, + 0 + ], + "3.9.5.91": [ + 61654904, + 61656240, + 61654712, + 38986104, + 61656176, + 61677112 + ], + "3.9.6.19": [ + 61997688, + 61997464, + 61997496, + 38986104, + 61998960, + 0 + ], + "3.9.6.33": [ + 62030600, + 62031936, + 62030408, + 0, + 62031872, + 0 + ], + "3.9.7.15": [ + 63482696, + 63484032, + 63482504, + 0, + 63483968, + 0 + ], + "3.9.7.25": [ + 63482760, + 63484096, + 63482568, + 0, + 63484032, + 0 + ], + "3.9.7.29": [ + 63486984, + 63488320, + 63486792, + 0, + 63488256, + 63488352 + ], + "3.9.8.15": [ + 64996632, + 64997968, + 64996440, + 0, + 64997904, + 65011632 + ] +} \ No newline at end of file diff --git a/decrypt_window.py b/decrypt_window.py new file mode 100644 index 0000000..2918b42 --- /dev/null +++ b/decrypt_window.py @@ -0,0 +1,38 @@ +import ctypes +import sys + +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import * + +from app.Ui import pc_decrypt + +ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport") + + +class ViewController(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle('解密') + self.setWindowIcon(QIcon('./app/data/icons/logo.svg')) + self.viewMainWIn = None + self.viewDecrypt = None + + def loadPCDecryptView(self): + """ + 登录界面 + :return: + """ + self.viewDecrypt = pc_decrypt.DecryptControl() + self.viewDecrypt.DecryptSignal.connect(self.show_success) + self.viewDecrypt.show() + + def show_success(self): + QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下") + + +if __name__ == '__main__': + app = QApplication(sys.argv) + view = ViewController() + view.loadPCDecryptView() + # view.show_success() + sys.exit(app.exec_()) diff --git a/doc/images/dirs.png b/doc/images/dirs.png new file mode 100644 index 0000000000000000000000000000000000000000..a4af2d2d7968526c76f8e30486a3e6333a57d4bd GIT binary patch literal 40806 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 literal 0 HcmV?d00001 diff --git a/doc/images/pc_decrypt_info.png b/doc/images/pc_decrypt_info.png new file mode 100644 index 0000000000000000000000000000000000000000..f3597ff4fd0685bef051ecfa3372e2f7492e6f14 GIT binary patch literal 14033 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 literal 0 HcmV?d00001 diff --git a/doc/images/setting.png b/doc/images/setting.png new file mode 100644 index 0000000000000000000000000000000000000000..799511a97c1d098bd325a5c1403114791a9f5407 GIT binary patch literal 17781 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 + image-20230520235113261 ![image-20230520235220104](doc/images/image-20230520235220104.png) @@ -50,7 +52,44 @@ ![image-20230520235431091](doc/images/image-20230520235431091.png) -## 使用 + + +# 使用 + +## 解密PC版微信数据库 + +
+ +### 1. 安装 + +```shell +git clone https://github.com/LC044/WeChatMsg +cd WeChatMsg +pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +### 2. 使用 + +1. 登录微信 +2. 运行程序 + ```shell + python decrypt_window.py + ``` +3. 点击获取信息 + + ![](./doc/images/pc_decrypt_info.png) +4. 设置微信安装路径 + 可以到微信->设置->文件管理查看 + ![](./doc/images/setting.png) + 点击**设置微信路径**按钮,选择该文件夹路径 +5. 获取到密钥和微信路径之后点击开始解密 +6. 解密后的数据库文件保存在./app/DataBase/Msg路径下 + +
+ +### 使用模拟器 + +
1. 根据[教程](https://blog.csdn.net/m0_59452630/article/details/124222235?spm=1001.2014.3001.5501)获得两个文件 - auth_info_key_prefs.xml——解析数据库密码 @@ -98,10 +137,16 @@ python main.py ![image-20230520235113261](doc/images/image-20230520235113261.png) +
+ ## 项目还有很多bug,希望大家能够及时反馈 项目地址:https://github.com/LC044/WeChatMsg +# 致谢 + +* PC微信解密工具:[https://github.com/xaoyaoo/PyWxDump](https://github.com/xaoyaoo/PyWxDump) + --- > 说明:该项目仅可用于交流学习,禁止任何非法用途,创作者不承担任何责任🙄 diff --git a/requirements.txt b/requirements.txt index acd23d29fa713e656e3bc8351bbafcc29330476d..638c6f709591575aa8cff4f307f29c6f156fbfe5 100644 GIT binary patch delta 126 zcmbQh+QznF0#jK5Loq`sLkUABLkdu3!O9a}K0#uRD003BV7uEm( delta 7 OcmZo;o4~qZ0uulU>jGo|