新增手动获取基址

This commit is contained in:
shuaikangzhou 2024-01-28 15:00:22 +08:00
parent 8f16ef5e60
commit c7995ca776
8 changed files with 681 additions and 90 deletions

View File

@ -1,77 +1,9 @@
import os import os
from collections import Counter from collections import Counter
from PyQt5.QtCore import QFile, QTextStream, QIODevice
import sys import sys
sys.path.append('.')
from app.DataBase import msg_db, MsgType from app.DataBase import msg_db, MsgType
from pyecharts import options as opts from pyecharts import options as opts
from pyecharts.charts import WordCloud, Calendar, Bar, Line from pyecharts.charts import WordCloud, Calendar, Bar, Line
from app.resources import resource_rc
var = resource_rc.qt_resource_name
charts_width = 800
charts_height = 450
wordcloud_width = 780
wordcloud_height = 720
def wordcloud(wxid, is_Annual_report=False, year='2023', who='1'):
import jieba
txt_messages = msg_db.get_messages_by_type(wxid, MsgType.TEXT, year)
if not txt_messages:
return {
'chart_data': None,
'keyword': "没有聊天你想分析啥",
'max_num': "0",
'dialogs': []
}
# text = ''.join(map(lambda x: x[7], txt_messages))
text = ''.join(map(lambda x: x[7] if x[4] == int(who) else '', txt_messages)) # 1“我”说的话0“Ta”说的话
total_msg_len = len(text)
# 使用jieba进行分词并加入停用词
words = jieba.cut(text)
# 统计词频
word_count = Counter(words)
# 过滤停用词
stopwords_file = './app000/data/stopwords.txt'
try:
with open(stopwords_file, "r", encoding="utf-8") as stopword_file:
stopwords = set(stopword_file.read().splitlines())
except:
file = QFile(':/data/stopwords.txt')
if file.open(QIODevice.ReadOnly | QIODevice.Text):
stream = QTextStream(file)
stream.setCodec('utf-8')
content = stream.readAll()
file.close()
stopwords = set(content.splitlines())
filtered_word_count = {word: count for word, count in word_count.items() if len(word) > 1 and word not in stopwords}
# 转换为词云数据格式
data = [(word, count) for word, count in filtered_word_count.items()]
# text_data = data
data.sort(key=lambda x: x[1], reverse=True)
text_data = data[:100] if len(data) > 100 else data
# 创建词云图
keyword, max_num = text_data[0]
w = (
WordCloud(init_opts=opts.InitOpts(width=f"{wordcloud_width}px", height=f"{wordcloud_height}px"))
.add(series_name="聊天文字", data_pair=text_data, word_size_range=[5, 40])
)
# return w.render_embed()
return {
'chart_data': w.dump_options_with_quotes(),
'keyword': keyword,
'max_num': str(max_num),
'dialogs': msg_db.get_messages_by_keyword(wxid, keyword, num=5, max_len=12)
}
def wordcloud_(wxid, time_range=None): def wordcloud_(wxid, time_range=None):
import jieba import jieba
@ -115,7 +47,7 @@ def wordcloud_(wxid, time_range=None):
# 创建词云图 # 创建词云图
keyword, max_num = text_data[0] keyword, max_num = text_data[0]
w = ( w = (
WordCloud(init_opts=opts.InitOpts(width=f"{wordcloud_width}px", height=f"{wordcloud_height}px")) WordCloud(init_opts=opts.InitOpts())
.add(series_name="聊天文字", data_pair=text_data, word_size_range=[5, 100]) .add(series_name="聊天文字", data_pair=text_data, word_size_range=[5, 100])
) )
# return w.render_embed() # return w.render_embed()
@ -267,7 +199,7 @@ def hour_count(wxid, is_Annual_report=False, year='2023'):
y_data = list(map(lambda x: x[1], msg_data)) y_data = list(map(lambda x: x[1], msg_data))
x_axis = list(map(lambda x: x[0], msg_data)) x_axis = list(map(lambda x: x[0], msg_data))
h = ( h = (
Line(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px")) Line(init_opts=opts.InitOpts())
.add_xaxis(xaxis_data=x_axis) .add_xaxis(xaxis_data=x_axis)
.add_yaxis( .add_yaxis(
series_name="聊天频率", series_name="聊天频率",

View File

@ -0,0 +1,272 @@
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: get_base_addr.py
# Description:
# Author: xaoyaoo
# Date: 2023/08/22
# -------------------------------------------------------------------------------
import argparse
import ctypes
import hashlib
import json
import multiprocessing
import os
import re
import sys
import psutil
from win32com.client import Dispatch
from pymem import Pymem
import pymem
import hmac
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
void_p = ctypes.c_void_p
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
DEFAULT_ITER = 64000
def validate_key(key, salt, first, mac_salt):
byteKey = hashlib.pbkdf2_hmac("sha1", key, salt, DEFAULT_ITER, KEY_SIZE)
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 True
else:
return False
def get_exe_bit(file_path):
"""
获取 PE 文件的位数: 32 位或 64
:param file_path: PE 文件路径(可执行文件)
:return: 如果遇到错误则返回 64
"""
try:
with open(file_path, 'rb') as f:
dos_header = f.read(2)
if dos_header != b'MZ':
print('get exe bit error: Invalid PE file')
return 64
# Seek to the offset of the PE signature
f.seek(60)
pe_offset_bytes = f.read(4)
pe_offset = int.from_bytes(pe_offset_bytes, byteorder='little')
# Seek to the Machine field in the PE header
f.seek(pe_offset + 4)
machine_bytes = f.read(2)
machine = int.from_bytes(machine_bytes, byteorder='little')
if machine == 0x14c:
return 32
elif machine == 0x8664:
return 64
else:
print('get exe bit error: Unknown architecture: %s' % hex(machine))
return 64
except IOError:
print('get exe bit error: File not found or cannot be opened')
return 64
def get_exe_version(file_path):
"""
获取 PE 文件的版本号
:param file_path: PE 文件路径(可执行文件)
:return: 如果遇到错误则返回
"""
file_version = Dispatch("Scripting.FileSystemObject").GetFileVersion(file_path)
return file_version
def find_all(c: bytes, string: bytes, base_addr=0):
"""
查找字符串中所有子串的位置
:param c: 子串 b'123'
:param string: 字符串 b'123456789123'
:return:
"""
return [base_addr + m.start() for m in re.finditer(re.escape(c), string)]
class BiasAddr:
def __init__(self, account, mobile, name, key, db_path):
self.account = account.encode("utf-8")
self.mobile = mobile.encode("utf-8")
self.name = name.encode("utf-8")
self.key = bytes.fromhex(key) if key else b""
self.db_path = db_path if db_path and os.path.exists(db_path) else ""
self.process_name = "WeChat.exe"
self.module_name = "WeChatWin.dll"
self.pm = None # Pymem 对象
self.is_WoW64 = None # True: 32位进程运行在64位系统上 False: 64位进程运行在64位系统上
self.process_handle = None # 进程句柄
self.pid = None # 进程ID
self.version = None # 微信版本号
self.process = None # 进程对象
self.exe_path = None # 微信路径
self.address_len = None # 4 if self.bits == 32 else 8 # 4字节或8字节
self.bits = 64 if sys.maxsize > 2 ** 32 else 32 # 系统32位或64位
def get_process_handle(self):
try:
self.pm = Pymem(self.process_name)
self.pm.check_wow64()
self.is_WoW64 = self.pm.is_WoW64
self.process_handle = self.pm.process_handle
self.pid = self.pm.process_id
self.process = psutil.Process(self.pid)
self.exe_path = self.process.exe()
self.version = get_exe_version(self.exe_path)
version_nums = list(map(int, self.version.split("."))) # 将版本号拆分为数字列表
if version_nums[0] <= 3 and version_nums[1] <= 9 and version_nums[2] <= 2:
self.address_len = 4
else:
self.address_len = 8
return True, ""
except pymem.exception.ProcessNotFound:
return False, "[-] WeChat No Run"
def search_memory_value(self, value: bytes, module_name="WeChatWin.dll"):
# 创建 Pymem 对象
module = pymem.process.module_from_name(self.pm.process_handle, module_name)
ret = self.pm.pattern_scan_module(value, module, return_multiple=True)
ret = ret[-1] - module.lpBaseOfDll if len(ret) > 0 else 0
return ret
def get_key_bias1(self):
try:
byteLen = self.address_len # 4 if self.bits == 32 else 8 # 4字节或8字节
keyLenOffset = 0x8c if self.bits == 32 else 0xd0
keyWindllOffset = 0x90 if self.bits == 32 else 0xd8
module = pymem.process.module_from_name(self.process_handle, self.module_name)
keyBytes = b'-----BEGIN PUBLIC KEY-----\n...'
publicKeyList = pymem.pattern.pattern_scan_all(self.process_handle, keyBytes, return_multiple=True)
keyaddrs = []
for addr in publicKeyList:
keyBytes = addr.to_bytes(byteLen, byteorder="little", signed=True) # 低位在前
may_addrs = pymem.pattern.pattern_scan_module(self.process_handle, module, keyBytes,
return_multiple=True)
if may_addrs != 0 and len(may_addrs) > 0:
for addr in may_addrs:
keyLen = self.pm.read_uchar(addr - keyLenOffset)
if keyLen != 32:
continue
keyaddrs.append(addr - keyWindllOffset)
return keyaddrs[-1] - module.lpBaseOfDll if len(keyaddrs) > 0 else 0
except:
return 0
def search_key(self, key: bytes):
key = re.escape(key) # 转义特殊字符
key_addr = self.pm.pattern_scan_all(key, return_multiple=False)
key = key_addr.to_bytes(self.address_len, byteorder='little', signed=True)
result = self.search_memory_value(key, self.module_name)
return result
def get_key_bias2(self, wx_db_path):
addr_len = get_exe_bit(self.exe_path) // 8
db_path = wx_db_path
def read_key_bytes(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_bytes = bytes(key)
return key_bytes
def verify_key(key, wx_db_path):
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
DEFAULT_ITER = 64000
with open(wx_db_path, "rb") as file:
blist = file.read(5000)
salt = blist[:16]
byteKey = hashlib.pbkdf2_hmac("sha1", key, 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 False
return True
phone_type1 = "iphone\x00"
phone_type2 = "android\x00"
phone_type3 = "ipad\x00"
pm = pymem.Pymem("WeChat.exe")
module_name = "WeChatWin.dll"
MicroMsg_path = os.path.join(db_path, "MSG", "MicroMsg.db")
module = pymem.process.module_from_name(pm.process_handle, module_name)
type1_addrs = pm.pattern_scan_module(phone_type1.encode(), module, return_multiple=True)
type2_addrs = pm.pattern_scan_module(phone_type2.encode(), module, return_multiple=True)
type3_addrs = pm.pattern_scan_module(phone_type3.encode(), module, return_multiple=True)
type_addrs = type1_addrs if len(type1_addrs) >= 2 else type2_addrs if len(
type2_addrs) >= 2 else type3_addrs if len(type3_addrs) >= 2 else "None"
if type_addrs == "None":
return 0
for i in type_addrs[::-1]:
for j in range(i, i - 2000, -addr_len):
key_bytes = read_key_bytes(pm.process_handle, j, addr_len)
if key_bytes == "None":
continue
if verify_key(key_bytes, MicroMsg_path):
return j - module.lpBaseOfDll
return 0
def run(self, logging_path=False, version_list_path=None):
if not self.get_process_handle()[0]:
return None
mobile_bias = self.search_memory_value(self.mobile, self.module_name)
name_bias = self.search_memory_value(self.name, self.module_name)
account_bias = self.search_memory_value(self.account, self.module_name)
key_bias = 0
key_bias = self.get_key_bias1()
key_bias = self.search_key(self.key) if key_bias <= 0 and self.key else key_bias
key_bias = self.get_key_bias2(self.db_path) if key_bias <= 0 and self.db_path else key_bias
rdata = {self.version: [name_bias, account_bias, mobile_bias, 0, key_bias]}
if version_list_path and os.path.exists(version_list_path):
with open(version_list_path, "r", encoding="utf-8") as f:
data = json.load(f)
data.update(rdata)
with open(version_list_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
if os.path.exists(logging_path) and isinstance(logging_path, str):
with open(logging_path, "a", encoding="utf-8") as f:
f.write("{版本号:昵称,账号,手机号,邮箱,KEY}" + "\n")
f.write(str(rdata) + "\n")
elif logging_path:
print("{版本号:昵称,账号,手机号,邮箱,KEY}")
print(rdata)
return rdata
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"

View File

@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'getBiasAddrUi.ui'
#
# Created by: PyQt5 UI code generator 5.15.10
#
# 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_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(650, 580)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.scrollArea = QtWidgets.QScrollArea(Form)
self.scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame)
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 632, 562))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.label_4.setMaximumSize(QtCore.QSize(16777215, 20))
self.label_4.setAlignment(QtCore.Qt.AlignCenter)
self.label_4.setObjectName("label_4")
self.verticalLayout_3.addWidget(self.label_4)
self.widget = QtWidgets.QWidget(self.scrollAreaWidgetContents)
self.widget.setStyleSheet("QWidget{\n"
" background-color:rgb(251,251,251);\n"
" border-radius: 10px;\n"
"}\n"
"\n"
"QPushButton{\n"
" background-color: rgb(250,252,253);\n"
" border-radius: 5px;\n"
" padding: 8px;\n"
" border-right: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-bottom: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-left: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
" border-top: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
"}\n"
"QPushButton:hover { \n"
" background-color: lightgray;\n"
"}")
self.widget.setObjectName("widget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(self.widget)
self.label.setMinimumSize(QtCore.QSize(80, 0))
self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.lineEdit_tel = QtWidgets.QLineEdit(self.widget)
self.lineEdit_tel.setObjectName("lineEdit_tel")
self.horizontalLayout.addWidget(self.lineEdit_tel)
self.verticalLayout_3.addWidget(self.widget)
self.widget_3 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
self.widget_3.setStyleSheet("QWidget{\n"
" background-color:rgb(251,251,251);\n"
" border-radius: 10px;\n"
"}\n"
"\n"
"QPushButton{\n"
" background-color: rgb(250,252,253);\n"
" border-radius: 5px;\n"
" padding: 8px;\n"
" border-right: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-bottom: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-left: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
" border-top: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
"}\n"
"QPushButton:hover { \n"
" background-color: lightgray;\n"
"}")
self.widget_3.setObjectName("widget_3")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_3)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_2 = QtWidgets.QLabel(self.widget_3)
self.label_2.setMinimumSize(QtCore.QSize(80, 0))
self.label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_2.setObjectName("label_2")
self.horizontalLayout_3.addWidget(self.label_2)
self.lineEdit_wx_alias = QtWidgets.QLineEdit(self.widget_3)
self.lineEdit_wx_alias.setObjectName("lineEdit_wx_alias")
self.horizontalLayout_3.addWidget(self.lineEdit_wx_alias)
self.verticalLayout_3.addWidget(self.widget_3)
self.widget_4 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
self.widget_4.setStyleSheet("QWidget{\n"
" background-color:rgb(251,251,251);\n"
" border-radius: 10px;\n"
"}\n"
"\n"
"QPushButton{\n"
" background-color: rgb(250,252,253);\n"
" border-radius: 5px;\n"
" padding: 8px;\n"
" border-right: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-bottom: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-left: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
" border-top: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
"}\n"
"QPushButton:hover { \n"
" background-color: lightgray;\n"
"}")
self.widget_4.setObjectName("widget_4")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget_4)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_3 = QtWidgets.QLabel(self.widget_4)
self.label_3.setMinimumSize(QtCore.QSize(80, 0))
self.label_3.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_3.setObjectName("label_3")
self.horizontalLayout_4.addWidget(self.label_3)
self.lineEdit_wx_name = QtWidgets.QLineEdit(self.widget_4)
self.lineEdit_wx_name.setObjectName("lineEdit_wx_name")
self.horizontalLayout_4.addWidget(self.lineEdit_wx_name)
self.verticalLayout_3.addWidget(self.widget_4)
self.btn_get_bias_addr = QtWidgets.QPushButton(self.scrollAreaWidgetContents)
self.btn_get_bias_addr.setObjectName("btn_get_bias_addr")
self.verticalLayout_3.addWidget(self.btn_get_bias_addr)
self.widget_2 = QtWidgets.QWidget(self.scrollAreaWidgetContents)
self.widget_2.setStyleSheet("QWidget{\n"
" background-color:rgb(251,251,251);\n"
" border-radius: 10px;\n"
"}\n"
"\n"
"QPushButton{\n"
" background-color: rgb(250,252,253);\n"
" border-radius: 5px;\n"
" padding: 8px;\n"
" border-right: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-bottom: 2px solid #888888; /* 按钮边框2px宽白色 */\n"
" border-left: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
" border-top: 1px solid #ffffff; /* 按钮边框2px宽白色 */\n"
"}\n"
"QPushButton:hover { \n"
" background-color: lightgray;\n"
"}")
self.widget_2.setObjectName("widget_2")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_2)
self.horizontalLayout_2.setContentsMargins(9, -1, -1, -1)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.commandLinkButton = QtWidgets.QCommandLinkButton(self.widget_2)
self.commandLinkButton.setEnabled(True)
self.commandLinkButton.setTabletTracking(False)
self.commandLinkButton.setFocusPolicy(QtCore.Qt.StrongFocus)
self.commandLinkButton.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
self.commandLinkButton.setToolTipDuration(-1)
self.commandLinkButton.setLayoutDirection(QtCore.Qt.LeftToRight)
self.commandLinkButton.setAutoFillBackground(False)
self.commandLinkButton.setCheckable(False)
self.commandLinkButton.setChecked(False)
self.commandLinkButton.setAutoRepeat(False)
self.commandLinkButton.setAutoExclusive(False)
self.commandLinkButton.setAutoDefault(False)
self.commandLinkButton.setDefault(False)
self.commandLinkButton.setObjectName("commandLinkButton")
self.horizontalLayout_2.addWidget(self.commandLinkButton)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.label_error_log = QtWidgets.QLabel(self.widget_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_error_log.sizePolicy().hasHeightForWidth())
self.label_error_log.setSizePolicy(sizePolicy)
self.label_error_log.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.label_error_log.setObjectName("label_error_log")
self.horizontalLayout_2.addWidget(self.label_error_log)
self.checkBox_send_error_log = QtWidgets.QCheckBox(self.widget_2)
self.checkBox_send_error_log.setText("")
self.checkBox_send_error_log.setIconSize(QtCore.QSize(64, 64))
self.checkBox_send_error_log.setChecked(True)
self.checkBox_send_error_log.setObjectName("checkBox_send_error_log")
self.horizontalLayout_2.addWidget(self.checkBox_send_error_log)
self.verticalLayout_3.addWidget(self.widget_2)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout.addWidget(self.scrollArea)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label_4.setText(_translate("Form", "为避免输入错误,下面信息请从微信里复制"))
self.label.setText(_translate("Form", "手机号:"))
self.lineEdit_tel.setPlaceholderText(_translate("Form", "填入微信绑定的手机号"))
self.label_2.setText(_translate("Form", "微信号:"))
self.lineEdit_wx_alias.setPlaceholderText(_translate("Form", "填入您的微信号"))
self.label_3.setText(_translate("Form", "微信昵称:"))
self.lineEdit_wx_name.setPlaceholderText(_translate("Form", "填入您的微信昵称"))
self.btn_get_bias_addr.setText(_translate("Form", "获取信息"))
self.commandLinkButton.setText(_translate("Form", "收集版本信息"))
self.commandLinkButton.setDescription(_translate("Form", "需要收集微信版本信息以支持更多用户"))
self.label_error_log.setText(_translate("Form", ""))

View File

@ -0,0 +1,145 @@
import json
import os.path
import requests
from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtWidgets import QWidget, QMessageBox
from app.components.QCursorGif import QCursorGif
from app.decrypt.get_bias_addr import BiasAddr
from .getBiasAddrUi import Ui_Form
Stylesheet = """
QPushButton{
background-color: rgb(250,252,253);
border-radius: 5px;
padding: 8px;
border-right: 2px solid #888888; /* 按钮边框2px宽白色 */
border-bottom: 2px solid #888888; /* 按钮边框2px宽白色 */
border-left: 1px solid #ffffff; /* 按钮边框2px宽白色 */
border-top: 1px solid #ffffff; /* 按钮边框2px宽白色 */
}
QPushButton:hover {
background-color: lightgray;
}
/*去掉item虚线边框*/
QListWidget, QListView, QTreeWidget, QTreeView {
outline: 0px;
border:none;
}
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
QListWidget {
min-width: 400px;
max-width: 400px;
min-height: 80px;
max-height: 80px;
color: black;
border:none;
}
QListWidget::item{
min-width: 80px;
max-width: 400px;
min-height: 80px;
max-height: 80px;
}
/*被选中时的背景颜色和左边框颜色*/
QListWidget::item:selected {
border-left:none;
color: black;
font-weight: bold;
}
QCheckBox::indicator {
background: rgb(251, 251, 251);
Width:60px;
Height:60px;
border-radius: 10px;
}
QCheckBox::indicator:unchecked{
Width:60px;
Height:60px;
image: url(:/icons/icons/按钮_关闭.svg);
}
QCheckBox::indicator:checked{
Width:60px;
Height:60px;
image: url(:/icons/icons/按钮_开启.svg);
}
"""
class GetBiasAddrControl(QWidget, Ui_Form, QCursorGif):
biasAddrSignal = pyqtSignal(dict)
def __init__(self, parent=None):
super(GetBiasAddrControl, self).__init__(parent)
self.thread = None
self.setStyleSheet(Stylesheet)
self.setupUi(self)
self.init_ui()
def init_ui(self):
self.initCursor([':/icons/icons/Cursors/%d.png' %
i for i in range(8)], self)
self.setCursorTimeout(100)
self.btn_get_bias_addr.clicked.connect(self.get_bias_addr)
self.commandLinkButton.clicked.connect(self.show_info)
self.checkBox_send_error_log.clicked.connect(self.set_error_log)
def set_error_log(self):
if self.checkBox_send_error_log.isChecked():
self.label_error_log.setText('')
else:
self.label_error_log.setText('')
def show_info(self):
QMessageBox.information(self, "收集版本信息",
"为了适配更多版本,需要收集微信的版本信息,该操作不会上传包括手机号、微信号、昵称等在内的任何信息\n示例数据:\n\"3.9.9.27\": [68065304, 0, 68065112, 0, 68066576]"
)
def upload(self, version_data):
url = "http://api.lc044.love/wxBiasAddr"
try:
requests.post(url, json=version_data)
print('版本信息上传成功')
except:
pass
def get_bias_addr(self):
account = self.lineEdit_wx_alias.text()
mobile = self.lineEdit_tel.text()
name = self.lineEdit_wx_name.text()
if not all([account, mobile, name]):
QMessageBox.critical(self, "错误",
"请把所有信息填写完整")
return
key = None
db_path = "test"
self.startBusy()
self.thread = MyThread(account, mobile, name, key, db_path)
self.thread.signal.connect(self.set_bias_addr)
self.thread.start()
def set_bias_addr(self, data):
if self.checkBox_send_error_log.isChecked():
self.upload(data)
self.stopBusy()
self.biasAddrSignal.emit(data)
class MyThread(QThread):
signal = pyqtSignal(dict)
def __init__(self, account, mobile, name, key, db_path):
super(MyThread, self).__init__()
self.account = account
self.mobile = mobile
self.name = name
self.key = key
self.db_path = db_path
def run(self):
bias_addr = BiasAddr(self.account, self.mobile, self.name, self.key, self.db_path)
data = bias_addr.run(logging_path=True)
self.signal.emit(data)

View File

@ -21,14 +21,17 @@ from ...Icon import Icon
class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif): class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
DecryptSignal = pyqtSignal(bool) DecryptSignal = pyqtSignal(bool)
get_wxidSignal = pyqtSignal(str) get_wxidSignal = pyqtSignal(str)
versionErrorSignal = pyqtSignal(str)
def __init__(self, parent=None): def __init__(self, parent=None):
super(DecryptControl, self).__init__(parent) super(DecryptControl, self).__init__(parent)
self.max_val = 0
self.setupUi(self) self.setupUi(self)
# 设置忙碌光标图片数组 # 设置忙碌光标图片数组
self.initCursor([':/icons/icons/Cursors/%d.png' % self.initCursor([':/icons/icons/Cursors/%d.png' %
i for i in range(8)], self) i for i in range(8)], self)
self.setCursorTimeout(100) self.setCursorTimeout(100)
self.version_list = None
self.btn_start.clicked.connect(self.decrypt) self.btn_start.clicked.connect(self.decrypt)
self.btn_getinfo.clicked.connect(self.get_info) self.btn_getinfo.clicked.connect(self.get_info)
self.btn_db_dir.clicked.connect(self.select_db_dir) self.btn_db_dir.clicked.connect(self.select_db_dir)
@ -53,7 +56,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
# @log # @log
def get_info(self): def get_info(self):
self.startBusy() self.startBusy()
self.get_info_thread = MyThread() self.get_info_thread = MyThread(self.version_list)
self.get_info_thread.signal.connect(self.set_info) self.get_info_thread.signal.connect(self.set_info)
self.get_info_thread.start() self.get_info_thread.start()
@ -62,8 +65,10 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
if result[0] == -1: if result[0] == -1:
QMessageBox.critical(self, "错误", "请登录微信") QMessageBox.critical(self, "错误", "请登录微信")
elif result[0] == -2: elif result[0] == -2:
self.versionErrorSignal.emit(result[1])
QMessageBox.critical(self, "错误", QMessageBox.critical(self, "错误",
"微信版本不匹配\n请更新微信版本为:3.9.9.27(去微信官网下载)\n或更新本软件") "微信版本不匹配\n请手动填写信息")
elif result[0] == -3: elif result[0] == -3:
QMessageBox.critical(self, "错误", "WeChat WeChatWin.dll Not Found") QMessageBox.critical(self, "错误", "WeChat WeChatWin.dll Not Found")
elif result[0] == -10086: elif result[0] == -10086:
@ -151,11 +156,12 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
# print("enter clicked") # print("enter clicked")
# 中间可以添加处理逻辑 # 中间可以添加处理逻辑
# QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下") # QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下")
self.progressBar_view(self.max_val)
self.DecryptSignal.emit(True) self.DecryptSignal.emit(True)
# self.close() # self.close()
def setProgressBarMaxNum(self, max_val): def setProgressBarMaxNum(self, max_val):
self.max_val = max_val
self.progressBar.setRange(0, max_val) self.progressBar.setRange(0, max_val)
def progressBar_view(self, value): def progressBar_view(self, value):
@ -184,7 +190,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
except: except:
with open('./info.json', 'w', encoding='utf-8') as f: with open('./info.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dic)) f.write(json.dumps(dic))
self.progressBar_view(self.max_val)
self.DecryptSignal.emit(True) self.DecryptSignal.emit(True)
self.close() self.close()
@ -271,8 +277,9 @@ class DecryptThread(QThread):
class MyThread(QThread): class MyThread(QThread):
signal = pyqtSignal(list) signal = pyqtSignal(list)
def __init__(self): def __init__(self,version_list = None):
super(MyThread, self).__init__() super(MyThread, self).__init__()
self.version_list = version_list
def __del__(self): def __del__(self):
pass pass
@ -283,8 +290,11 @@ class MyThread(QThread):
'version': version 'version': version
} }
try: try:
response = requests.post(url, json=data) response = requests.get(url, json=data)
print(response)
print(response.text)
if response.status_code == 200: if response.status_code == 200:
update_info = response.json() update_info = response.json()
return update_info return update_info
else: else:
@ -293,12 +303,15 @@ class MyThread(QThread):
return {} return {}
def run(self): def run(self):
file_path = './app/resources/data/version_list.json' if self.version_list:
if not os.path.exists(file_path): VERSION_LIST = self.version_list
resource_dir = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__))) else:
file_path = os.path.join(resource_dir, 'app', 'resources', 'data', 'version_list.json') file_path = './app/resources/data/version_list.json'
with open(file_path, "r", encoding="utf-8") as f: if not os.path.exists(file_path):
VERSION_LIST = json.loads(f.read()) resource_dir = getattr(sys, '_MEIPASS', os.path.abspath(os.path.dirname(__file__)))
file_path = os.path.join(resource_dir, 'app', 'resources', 'data', 'version_list.json')
with open(file_path, "r", encoding="utf-8") as f:
VERSION_LIST = json.loads(f.read())
try: try:
result = get_wx_info.get_info(VERSION_LIST) result = get_wx_info.get_info(VERSION_LIST)
if result == -1: if result == -1:
@ -313,6 +326,9 @@ class MyThread(QThread):
if version_bias.get(version): if version_bias.get(version):
logger.info(f"从云端获取内存基址:{version_bias}") logger.info(f"从云端获取内存基址:{version_bias}")
result = get_wx_info.get_info(version_bias) result = get_wx_info.get_info(version_bias)
else:
logger.info(f"从云端获取内存基址失败:{version}")
result = [-2,version]
except: except:
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
result = [-10086] result = [-10086]

View File

@ -78,6 +78,7 @@ class SettingControl(QWidget, Ui_Form):
def init_ui(self): def init_ui(self):
self.checkBox.setText('') self.checkBox.setText('')
self.checkBox_send_error_log.clicked.connect(self.set_error_log) self.checkBox_send_error_log.clicked.connect(self.set_error_log)
def set_error_log(self): def set_error_log(self):
if self.checkBox_send_error_log.isChecked(): if self.checkBox_send_error_log.isChecked():
self.label_error_log.setText('') self.label_error_log.setText('')

View File

@ -5,6 +5,7 @@ from PyQt5.QtWidgets import QWidget, QListWidgetItem, QLabel
from app.ui.Icon import Icon from app.ui.Icon import Icon
from .pc_decrypt import DecryptControl from .pc_decrypt import DecryptControl
from .setting.setting import SettingControl from .setting.setting import SettingControl
from .get_bias_addr.get_bias_addr import GetBiasAddrControl
from .toolUI import Ui_Dialog from .toolUI import Ui_Dialog
# 美化样式表 # 美化样式表
@ -68,14 +69,22 @@ class ToolWindow(QWidget, Ui_Dialog):
self.listWidget.currentRowChanged.connect(self.setCurrentIndex) self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
chat_item = QListWidgetItem(Icon.Decrypt_Icon, '解密', self.listWidget) chat_item = QListWidgetItem(Icon.Decrypt_Icon, '解密', self.listWidget)
contact_item = QListWidgetItem(Icon.Contact_Icon, '设置', self.listWidget) contact_item = QListWidgetItem(Icon.Contact_Icon, '设置', self.listWidget)
myinfo_item = QListWidgetItem(Icon.Home_Icon, '别点', self.listWidget) myinfo_item = QListWidgetItem(Icon.Home_Icon, '解密2', self.listWidget)
tool_item = QListWidgetItem(Icon.Home_Icon, '别点', self.listWidget) tool_item = QListWidgetItem(Icon.Home_Icon, '别点', self.listWidget)
decrypt_window = DecryptControl()
decrypt_window.get_wxidSignal.connect(self.get_info_signal) self.decrypt_window = DecryptControl()
decrypt_window.DecryptSignal.connect(self.decrypt_success_signal) self.decrypt_window.get_wxidSignal.connect(self.get_info_signal)
self.stackedWidget.addWidget(decrypt_window) self.decrypt_window.DecryptSignal.connect(self.decrypt_success_signal)
self.decrypt_window.versionErrorSignal.connect(self.show_decrypt2)
self.stackedWidget.addWidget(self.decrypt_window)
setting_window = SettingControl() setting_window = SettingControl()
self.stackedWidget.addWidget(setting_window) self.stackedWidget.addWidget(setting_window)
self.get_bias_addr_window = GetBiasAddrControl()
self.get_bias_addr_window.biasAddrSignal.connect(self.decrypt)
self.stackedWidget.addWidget(self.get_bias_addr_window)
label = QLabel('都说了不让你点', self) label = QLabel('都说了不让你点', self)
label.setFont(QFont("微软雅黑", 50)) label.setFont(QFont("微软雅黑", 50))
label.setAlignment(Qt.AlignCenter) label.setAlignment(Qt.AlignCenter)
@ -84,10 +93,19 @@ class ToolWindow(QWidget, Ui_Dialog):
# label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % ( # label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
# randint(0, 255), randint(0, 255), randint(0, 255))) # randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label)
self.stackedWidget.addWidget(label) self.stackedWidget.addWidget(label)
self.listWidget.setCurrentRow(0) self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0) self.stackedWidget.setCurrentIndex(0)
def decrypt(self, version_list):
self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0)
self.decrypt_window.version_list = version_list
self.decrypt_window.get_info()
def show_decrypt2(self, version):
self.listWidget.setCurrentRow(2)
self.stackedWidget.setCurrentIndex(2)
def setCurrentIndex(self, row): def setCurrentIndex(self, row):
self.stackedWidget.setCurrentIndex(row) self.stackedWidget.setCurrentIndex(row)

View File

@ -33,6 +33,7 @@ def get_code(dat_read):
return head_index, code return head_index, code
head_index = head_index + 1 head_index = head_index + 1
print("not jpg, png, gif") print("not jpg, png, gif")
return -1, -1
except: except:
logger.error(f'image解析发生了错误:\n\n{traceback.format_exc()}') logger.error(f'image解析发生了错误:\n\n{traceback.format_exc()}')
return -1, -1 return -1, -1
@ -48,8 +49,8 @@ def decode_dat(file_path, out_path):
return None return None
with open(file_path, 'rb') as file_in: with open(file_path, 'rb') as file_in:
data = file_in.read() data = file_in.read()
file_type, decode_code = get_code(data[:2]) data = get_code(data[:2])
file_type, decode_code = data
if decode_code == -1: if decode_code == -1:
return return