Merge pull request #20 from LC044/master

pull
This commit is contained in:
SiYuan 2023-11-21 20:54:23 +08:00 committed by GitHub
commit edbe83ff0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 377 additions and 161 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ TEST
app/data/avatar
app/data/image2
app/data/emoji
app/DataBase/Msg/*
*.db
*.pyc
*.log

View File

@ -4,13 +4,15 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="修复修改wixd的bug">
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="更新wx选择的路径">
<change afterPath="$PROJECT_DIR$/app/util/path.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/DataBase/hard_link.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/hard_link.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/components/bubble_message.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/bubble_message.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/decrypt/decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/decrypt/decrypt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/decrypt/get_wx_info.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/decrypt/get_wx_info.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/Icon.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/Icon.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/mainview.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/util/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/util/__init__.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -30,10 +32,23 @@
<option name="myRunOnSave" value="true" />
</component>
<component name="Git.Settings">
<excluded-from-favorite>
<branch-storage>
<map>
<entry type="LOCAL">
<value>
<list>
<branch-info repo="$PROJECT_DIR$" source="master" />
</list>
</value>
</entry>
</map>
</branch-storage>
</excluded-from-favorite>
<option name="PUSH_AUTO_UPDATE" value="true" />
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="master" />
<entry key="$PROJECT_DIR$" value="dev_zsk" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
@ -54,12 +69,12 @@
<option name="branches">
<list>
<RecentBranch>
<option name="branchName" value="dev_zsk" />
<option name="lastUsedInstant" value="1700046130" />
<option name="branchName" value="master" />
<option name="lastUsedInstant" value="1700478623" />
</RecentBranch>
<RecentBranch>
<option name="branchName" value="master" />
<option name="lastUsedInstant" value="1700046129" />
<option name="branchName" value="dev_zsk" />
<option name="lastUsedInstant" value="1700046130" />
</RecentBranch>
</list>
</option>
@ -96,7 +111,7 @@
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"last_opened_file_path": "D:/Program Files/Python310/Scripts/pyuic5.exe",
"settings.editor.selected.configurable": "preferences.lookFeel"
"settings.editor.selected.configurable": "preferences.pluginManager"
}
}]]></component>
<component name="RecentsManager">
@ -106,28 +121,7 @@
<recent name="D:\Project\PythonProject\WeChatMsg\app\Ui" />
</key>
</component>
<component name="RunManager" selected="Python.decrypt_window">
<configuration name="bubble_message" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/components" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/components/bubble_message.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<component name="RunManager" selected="Python.main_pc">
<configuration name="decrypt_window" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -149,6 +143,48 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="hard_link" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/DataBase" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/DataBase/hard_link.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="main_pc" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -164,28 +200,7 @@
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main_pc.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="mainview" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/ui_pc" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/ui_pc/mainview.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
@ -212,7 +227,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@ -233,34 +248,13 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/components" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/components/test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.decrypt_window" />
<item itemvalue="Python.main_pc" />
<item itemvalue="Python.test (1)" />
<item itemvalue="Python.bubble_message" />
<item itemvalue="Python.test" />
<item itemvalue="Python.hard_link" />
<item itemvalue="Python.decrypt_window" />
<item itemvalue="Python.main" />
</list>
</recent_temporary>
</component>
@ -276,20 +270,6 @@
<option name="presentableId" value="Default" />
<updated>1672848140146</updated>
</task>
<task id="LOCAL-00034" summary="修改部分UI">
<created>1698592548209</created>
<option name="number" value="00034" />
<option name="presentableId" value="LOCAL-00034" />
<option name="project" value="LOCAL" />
<updated>1698592548210</updated>
</task>
<task id="LOCAL-00035" summary="update readme">
<created>1698681328723</created>
<option name="number" value="00035" />
<option name="presentableId" value="LOCAL-00035" />
<option name="project" value="LOCAL" />
<updated>1698681328723</updated>
</task>
<task id="LOCAL-00036" summary="重构一些class删除一些不必要的文件">
<created>1698765961025</created>
<option name="number" value="00036" />
@ -619,7 +599,21 @@
<option name="project" value="LOCAL" />
<updated>1700410804352</updated>
</task>
<option name="localTasksCounter" value="83" />
<task id="LOCAL-00083" summary="文字消息设置圆角">
<created>1700478493497</created>
<option name="number" value="00083" />
<option name="presentableId" value="LOCAL-00083" />
<option name="project" value="LOCAL" />
<updated>1700478493497</updated>
</task>
<task id="LOCAL-00084" summary="更新wx选择的路径">
<created>1700490633275</created>
<option name="number" value="00084" />
<option name="presentableId" value="LOCAL-00084" />
<option name="project" value="LOCAL" />
<updated>1700490633275</updated>
</task>
<option name="localTasksCounter" value="85" />
<servers />
</component>
<component name="UnknownFeatures">
@ -642,7 +636,7 @@
<entry key="branch">
<value>
<list>
<option value="origin/dev_zsk" />
<option value="master" />
</list>
</value>
</entry>
@ -655,8 +649,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="增加日志模块" />
<MESSAGE value="增加PC端微信解密条件的判断" />
<MESSAGE value="删除多余的Word文件" />
<MESSAGE value="修复无法查找wxid的bug" />
<MESSAGE value="修改UI" />
@ -680,7 +672,9 @@
<MESSAGE value="修复第一次启动的显示问题" />
<MESSAGE value="支持查找功能" />
<MESSAGE value="修复修改wixd的bug" />
<option name="LAST_COMMIT_MESSAGE" value="修复修改wixd的bug" />
<MESSAGE value="文字消息设置圆角" />
<MESSAGE value="更新wx选择的路径" />
<option name="LAST_COMMIT_MESSAGE" value="更新wx选择的路径" />
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
</component>
@ -699,24 +693,9 @@
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/decrypt/decrypt.py</url>
<line>105</line>
<line>103</line>
<option name="timeStamp" value="9" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>100</line>
<option name="timeStamp" value="10" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>98</line>
<option name="timeStamp" value="11" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>99</line>
<option name="timeStamp" value="12" />
</line-breakpoint>
</breakpoints>
<default-breakpoints>
<breakpoint type="python-exception">

78
app/DataBase/hard_link.py Normal file
View File

@ -0,0 +1,78 @@
import binascii
import os.path
import sqlite3
import threading
import xml.etree.ElementTree as ET
lock = threading.Lock()
DB = None
cursor = None
db_path = "./app/Database/Msg/HardLinkImage.db"
root_path = 'FileStorage/MsgAttach/'
if os.path.exists(db_path):
DB = sqlite3.connect(db_path, check_same_thread=False)
# '''创建游标'''
cursor = DB.cursor()
def init_database():
global DB
global cursor
if not DB:
if os.path.exists(db_path):
DB = sqlite3.connect(db_path, check_same_thread=False)
# '''创建游标'''
cursor = DB.cursor()
def get_image_by_md5(md5: bytes):
sql = '''
select Md5Hash,MD5,FileName,HardLinkImageID.Dir as DirName1,HardLinkImageID2.Dir as DirName2
from HardLinkImageAttribute
join HardLinkImageID on HardLinkImageAttribute.DirID1 = HardLinkImageID.DirID
join HardLinkImageID as HardLinkImageID2 on HardLinkImageAttribute.DirID2 = HardLinkImageID2.DirID
where MD5 = ?;
'''
try:
lock.acquire(True)
cursor.execute(sql, [md5, ])
result = cursor.fetchone()
return result
finally:
lock.release()
def get_md5_from_xml(content):
# 解析XML
root = ET.fromstring(content)
# 提取md5的值
md5_value = root.find(".//img").get("md5")
# print(md5_value)
return md5_value
def get_image(content, thumb=False):
md5 = get_md5_from_xml(content)
# md5 = 'bc37a58c32cb203ee9ac587b068e5853'
result = get_image_by_md5(binascii.unhexlify(md5))
if result:
# print(result)
dir1 = result[3]
dir2 = result[4]
data_image = result[2]
dir0 = 'Thumb' if thumb else 'Image'
dat_image = os.path.join(root_path, dir1, dir0, dir2, data_image)
return dat_image
# 6b02292eecea118f06be3a5b20075afc_t
if __name__ == '__main__':
msg_root_path = './Msg/'
db_path = "./Msg/HardLinkImage.db"
init_database()
content = '''<?xml version="1.0"?><msg>\n\t<img aeskey="bc37a58c32cb203ee9ac587b068e5853" encryver="1" cdnthumbaeskey="bc37a58c32cb203ee9ac587b068e5853" cdnthumburl="3057020100044b30490201000204d181705002032f5405020428a7b4de02046537869d042462313532363539632d663930622d343463302d616636662d333837646434633061626534020401150a020201000405004c4c6d00" cdnthumblength="3097" cdnthumbheight="120" cdnthumbwidth="68" cdnmidheight="0" cdnmidwidth="0" cdnhdheight="0" cdnhdwidth="0" cdnmidimgurl="3057020100044b30490201000204d181705002032f5405020428a7b4de02046537869d042462313532363539632d663930622d343463302d616636662d333837646434633061626534020401150a020201000405004c4c6d00" length="57667" md5="6844b812d5d514eb6878657e0bf4cdbb" originsourcemd5="1dfdfa24922270ea1cb5daba103f45ca" />\n\t<platform_signature></platform_signature>\n\t<imgdatahash></imgdatahash>\n</msg>\n'''
print(get_image(content))
print(get_image(content, thumb=False))
result = get_md5_from_xml(content)
print(result)

View File

@ -6,6 +6,9 @@ from PyQt5.QtCore import pyqtSignal, QThread
from . import msg
from ..log import log
if not os.path.exists('./data/聊天记录'):
os.mkdir('./data/聊天记录')
class Output(QThread):
"""

View File

@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QVBoxLayo
class MessageType:
Text = 1
Image = 2
Image = 3
class TextMessage(QLabel):
@ -104,20 +104,28 @@ class OpenImageThread(QThread):
class ImageMessage(QLabel):
def __init__(self, avatar, parent=None):
def __init__(self, image, image_link='', max_width=480, max_height=720, parent=None):
"""
param:image 图像路径或者QPixmap对象
param:image_link='' 点击图像打开的文件路径
"""
super().__init__(parent)
self.image = QLabel(self)
if isinstance(avatar, str):
self.setPixmap(QPixmap(avatar))
self.image_path = avatar
elif isinstance(avatar, QPixmap):
self.setPixmap(avatar)
self.setMaximumWidth(480)
self.setMaximumHeight(720)
self.setScaledContents(True)
if isinstance(image, str):
self.setPixmap(QPixmap(image))
self.image_path = image
elif isinstance(image, QPixmap):
self.setPixmap(image)
if image_link:
self.image_path = image_link
self.setMaximumWidth(max_width)
self.setMaximumHeight(max_height)
# self.setScaledContents(True)
def mousePressEvent(self, event):
if event.buttons() == Qt.LeftButton: # 左键按下
print('打开图像', self.image_path)
self.open_image_thread = OpenImageThread(self.image_path)
self.open_image_thread.start()

BIN
app/data/icons/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

91
app/decrypt/dat2pic.py Normal file
View File

@ -0,0 +1,91 @@
import os
# 图片字节头信息,
# [0][1]为jpg头信息
# [2][3]为png头信息
# [4][5]为gif头信息
pic_head = [0xff, 0xd8, 0x89, 0x50, 0x47, 0x49]
# 解密码
decode_code = 0
def get_code(file_path):
"""
自动判断文件类型并获取dat文件解密码
:param file_path: dat文件路径
:return: 如果文件为jpg/png/gif格式则返回解密码否则返回-1
"""
if os.path.isdir(file_path):
return -1, -1
if file_path[-4:] != ".dat":
return -1, -1
dat_file = open(file_path, "rb")
dat_read = dat_file.read(2)
print(dat_read)
head_index = 0
while head_index < len(pic_head):
# 使用第一个头信息字节来计算加密码
# 第二个字节来验证解密码是否正确
code = dat_read[0] ^ pic_head[head_index]
idf_code = dat_read[1] ^ code
head_index = head_index + 1
if idf_code == pic_head[head_index]:
dat_file.close()
return head_index, code
head_index = head_index + 1
print("not jpg, png, gif")
return -1, -1
def decode_dat(file_path, out_path):
"""
解密文件并生成图片
:param file_path: dat文件路径
:return:
"""
file_type, decode_code = get_code(file_path)
if decode_code == -1:
return
if file_type == 1:
pic_name = file_path.split("\\")[-1][:-4] + ".jpg"
elif file_type == 3:
pic_name = file_path[:-4] + ".png"
elif file_type == 5:
pic_name = file_path[:-4] + ".gif"
else:
pic_name = file_path[:-4] + ".jpg"
dat_file = open(file_path, "rb")
file_outpath = os.path.join(out_path, pic_name)
print(pic_name)
print(file_outpath)
pic_write = open(file_outpath, "wb")
for dat_data in dat_file:
for dat_byte in dat_data:
pic_data = dat_byte ^ decode_code
pic_write.write(bytes([pic_data]))
print(pic_name + "完成")
dat_file.close()
pic_write.close()
def find_datfile(dir_path, out_path):
"""
获取dat文件目录下所有的文件
:param dir_path: dat文件目录
:return:
"""
files_list = os.listdir(dir_path)
for file_name in files_list:
file_path = dir_path + "\\" + file_name
decode_dat(file_path, out_path)
if __name__ == "__main__":
path = r"D:\download\wechat\WeChat Files\wxid_0o18ef858vnu22\FileStorage\MsgAttach\febd8caf62dd403a7212aef63fd55910\Thumb\2023-11"
outpath = "D:\\test"
if not os.path.exists(outpath):
os.mkdir(outpath)
find_datfile(path, outpath)

View File

@ -65,7 +65,7 @@ def read_info(version_list, is_logging=False):
if len(wechat_process) == 0:
error = "[-] WeChat No Run"
if is_logging: print(error)
return error
return -1
for process in wechat_process:
tmp_rd = {}
@ -76,8 +76,9 @@ def read_info(version_list, is_logging=False):
bias_list = version_list.get(tmp_rd['version'], None)
if not isinstance(bias_list, list):
error = f"[-] WeChat Current Version {tmp_rd['version']} Is Not Supported"
if is_logging: print(error)
return error
if is_logging:
print(error)
return -2
wechat_base_address = 0
for module in process.memory_maps(grouped=False):
@ -86,8 +87,9 @@ def read_info(version_list, is_logging=False):
break
if wechat_base_address == 0:
error = f"[-] WeChat WeChatWin.dll Not Found"
if is_logging: print(error)
return error
if is_logging:
print(error)
return -3
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, process.pid)
@ -128,7 +130,7 @@ def get_info():
with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f:
VERSION_LIST = json.load(f)
result = read_info(VERSION_LIST) # 读取微信信息
result = read_info(VERSION_LIST, True) # 读取微信信息
return result

View File

@ -55,6 +55,10 @@ def singleton(cls):
class MePC:
def __init__(self):
self.avatar = QPixmap(Icon.Default_avatar_path)
self.wxid = ''
self.wx_dir = ''
self.name = ''
self.mobile = ''
def set_avatar(self, img_bytes):
if not img_bytes:

View File

@ -3,6 +3,7 @@ from PyQt5.QtGui import QIcon
class Icon:
Default_avatar_path = './app/data/icons/default_avatar.svg'
Default_image_path = './app/data/icons/404.png'
MainWindow_Icon = QIcon('./app/data/icons/logo.svg')
Default_avatar = QIcon(Default_avatar_path)
Output = QIcon('./app/data/icons/output.svg')

View File

@ -1,9 +1,12 @@
import traceback
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout
from app.DataBase import msg
from app.DataBase import msg, hard_link
from app.components.bubble_message import BubbleMessage, ChatWidget, Notice
from app.person import MePC
from app.util import get_abs_path
class ChatInfo(QWidget):
@ -84,7 +87,7 @@ class ChatInfo(QWidget):
is_send = message[4]
avatar = MePC().avatar if is_send else self.contact.avatar
timestamp = message[5]
if type_ == 1 or type_ == 3:
if type_ == 1:
if self.is_5_min(timestamp):
time_message = Notice(self.last_str_time)
self.last_str_time = str_time
@ -96,8 +99,23 @@ class ChatInfo(QWidget):
is_send
)
self.chat_window.add_message_item(bubble_message, 0)
elif type_ == 3:
if self.is_5_min(timestamp):
time_message = Notice(self.last_str_time)
self.last_str_time = str_time
self.chat_window.add_message_item(time_message, 0)
image_path = hard_link.get_image(content=str_content, thumb=False)
image_path = get_abs_path(image_path)
bubble_message = BubbleMessage(
image_path,
avatar,
type_,
is_send
)
self.chat_window.add_message_item(bubble_message, 0)
except:
print(message)
traceback.print_exc()
class ShowChatThread(QThread):

View File

@ -85,6 +85,10 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
wxid = dic.get('wxid')
if wxid:
me = MePC()
me.wxid = dic.get('wxid')
me.name = dic.get('name')
me.mobile = dic.get('mobile')
me.wx_dir = dic.get('wx_dir')
self.set_my_info(wxid)
else:
QMessageBox.information(
@ -158,11 +162,6 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
self.avatar.scaled(60, 60)
me = MePC()
me.set_avatar(img_bytes)
dic = {
'wxid': wxid
}
with open('./app/data/info.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dic))
self.myavatar.setScaledContents(True)
self.myavatar.setPixmap(self.avatar)

View File

@ -53,14 +53,14 @@ class Ui_Dialog(object):
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setStyleSheet("background:transparent;\n"
"\n"
"border-radius:5px;\n"
"border-top: 0px solid #b2e281;\n"
"border-bottom: 2px solid black;\n"
"border-right: 0px solid #b2e281;\n"
"border-left: 0px solid #b2e281;\n"
" border-radius:5px;\n"
" border-top: 0px solid #b2e281;\n"
" border-bottom: 2px solid black;\n"
" border-right: 0px solid #b2e281;\n"
" border-left: 0px solid #b2e281;\n"
"\n"
" \n"
"border-style:outset\n"
"\n"
" border-style:outset\n"
" ")
self.lineEdit.setFrame(False)
self.lineEdit.setObjectName("lineEdit")
@ -72,7 +72,7 @@ class Ui_Dialog(object):
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.label_key = QtWidgets.QLabel(Dialog)
self.label_key.setMaximumSize(QtCore.QSize(200, 16777215))
self.label_key.setMaximumSize(QtCore.QSize(400, 16777215))
self.label_key.setText("")
self.label_key.setObjectName("label_key")
self.gridLayout.addWidget(self.label_key, 5, 1, 1, 1)
@ -101,7 +101,7 @@ class Ui_Dialog(object):
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1)
self.label_db_dir = QtWidgets.QLabel(Dialog)
self.label_db_dir.setMaximumSize(QtCore.QSize(200, 300))
self.label_db_dir.setMaximumSize(QtCore.QSize(400, 300))
self.label_db_dir.setText("")
self.label_db_dir.setObjectName("label_db_dir")
self.gridLayout.addWidget(self.label_db_dir, 6, 1, 1, 1)

View File

@ -127,7 +127,7 @@
<widget class="QLabel" name="label_key">
<property name="maximumSize">
<size>
<width>200</width>
<width>400</width>
<height>16777215</height>
</size>
</property>
@ -189,7 +189,7 @@
<widget class="QLabel" name="label_db_dir">
<property name="maximumSize">
<size>
<width>200</width>
<width>400</width>
<height>300</height>
</size>
</property>

View File

@ -1,3 +1,4 @@
import json
import os.path
import time
import traceback
@ -35,11 +36,13 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
def get_info(self):
try:
result = get_wx_info.get_info()
print(result)
if result == -1:
QMessageBox.critical(self, "错误", "请登录微信")
elif result == -2:
QMessageBox.critical(self, "错误", "微信版本不匹配\n请更新微信版本为:3.9.8.15")
# print(result)
elif result == -3:
QMessageBox.critical(self, "错误", "WeChat WeChatWin.dll Not Found")
else:
self.ready = True
self.info = result[0]
@ -52,7 +55,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
self.lineEdit.setFocus()
self.checkBox.setChecked(True)
self.get_wxidSignal.emit(self.info['wxid'])
if self.wx_dir and os.path.exists(os.path.join(self.wx_dir, self.info['wxid'])):
if self.wx_dir and os.path.exists(os.path.join(self.wx_dir)):
self.label_ready.setText('已就绪')
except Exception as e:
print(e)
@ -71,7 +74,11 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
directory = QtWidgets.QFileDialog.getExistingDirectory(
self, "选取微信安装目录——能看到All Users文件夹",
"C:/") # 起始路径
if directory:
db_dir = os.path.join(directory, 'Msg')
if not os.path.exists(db_dir):
QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以wxid_xxx结尾")
return
self.label_db_dir.setText(directory)
self.wx_dir = directory
self.checkBox_2.setChecked(True)
@ -88,11 +95,12 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
if self.lineEdit.text() == 'None':
QMessageBox.critical(self, "错误", "请填入wxid")
return
db_dir = os.path.join(self.wx_dir, 'Msg')
if self.ready:
if not os.path.exists(os.path.join(self.wx_dir, self.info['wxid'])):
QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以WeChat Files结尾")
if not os.path.exists(db_dir):
QMessageBox.critical(self, "错误", "文件夹选择错误\n一般以wxid_xxx结尾")
return
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)
@ -103,6 +111,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
# print("enter clicked")
# 中间可以添加处理逻辑
# QMessageBox.about(self, "解密成功", "数据库文件存储在app/DataBase/Msg文件夹下")
self.DecryptSignal.emit('ok')
# self.close()
@ -121,6 +130,14 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
def btnExitClicked(self):
# print("Exit clicked")
dic = {
'wxid': self.info['wxid'],
'wx_dir': self.wx_dir,
'name': self.info['name'],
'mobile': self.info['mobile']
}
with open('./app/data/info.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dic))
self.DecryptSignal.emit('ok')
self.close()

View File

@ -0,0 +1 @@
from .path import get_abs_path

11
app/util/path.py Normal file
View File

@ -0,0 +1,11 @@
import os
from app.person import MePC
def get_abs_path(path):
return os.path.join(os.getcwd(), 'app/data/icons/404.png')
if path:
return os.path.join(MePC().wx_dir, path)
else:
return os.path.join(os.getcwd(), 'app/data/icons/404.png')

BIN
doc/images/path_select.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -40,7 +40,8 @@ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
![](./images/setting.png)
点击**设置微信路径**按钮,选择该文件夹路径
点击**设置微信路径**按钮选择该文件夹路径下的带有wxid_xxx的路径
![](./images/path_select.png)
5. 获取到密钥和微信路径之后点击开始解密

View File

@ -88,7 +88,9 @@ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
可以到微信->设置->文件管理查看
![](./doc/images/setting.png)
点击**设置微信路径**按钮,选择该文件夹路径
点击**设置微信路径**按钮选择该文件夹路径下的带有wxid_xxx的路径
![](./doc/images/path_select.png)
5. 获取到密钥和微信路径之后点击开始解密
6. 解密后的数据库文件保存在./app/DataBase/Msg路径下