2023-10-14 21:48:35 +08:00
|
|
|
|
# -*- coding: utf-8 -*-#
|
|
|
|
|
# -------------------------------------------------------------------------------
|
|
|
|
|
# Name: main.py.py
|
|
|
|
|
# Description:
|
|
|
|
|
# Author: xaoyaoo
|
|
|
|
|
# Date: 2023/10/14
|
|
|
|
|
# -------------------------------------------------------------------------------
|
|
|
|
|
import argparse
|
2023-12-11 18:59:16 +08:00
|
|
|
|
import os
|
2023-11-22 18:33:49 +08:00
|
|
|
|
import sys
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-27 10:12:12 +08:00
|
|
|
|
from pywxdump import *
|
2023-12-18 22:36:11 +08:00
|
|
|
|
import pywxdump
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-30 17:50:17 +08:00
|
|
|
|
wxdump_ascii = r"""
|
|
|
|
|
██████╗ ██╗ ██╗██╗ ██╗██╗ ██╗██████╗ ██╗ ██╗███╗ ███╗██████╗
|
|
|
|
|
██╔══██╗╚██╗ ██╔╝██║ ██║╚██╗██╔╝██╔══██╗██║ ██║████╗ ████║██╔══██╗
|
|
|
|
|
██████╔╝ ╚████╔╝ ██║ █╗ ██║ ╚███╔╝ ██║ ██║██║ ██║██╔████╔██║██████╔╝
|
|
|
|
|
██╔═══╝ ╚██╔╝ ██║███╗██║ ██╔██╗ ██║ ██║██║ ██║██║╚██╔╝██║██╔═══╝
|
|
|
|
|
██║ ██║ ╚███╔███╔╝██╔╝ ██╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║
|
|
|
|
|
╚═╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
|
|
|
|
|
"""
|
2023-10-15 10:37:19 +08:00
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
|
|
|
|
class MainBiasAddr():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "bias"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'bias_addr' 子命令解析器
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_bias_addr = parser.add_parser(self.mode, help="获取微信基址偏移")
|
2023-11-22 18:33:49 +08:00
|
|
|
|
sb_bias_addr.add_argument("--mobile", type=str, help="手机号", metavar="", required=True)
|
|
|
|
|
sb_bias_addr.add_argument("--name", type=str, help="微信昵称", metavar="", required=True)
|
|
|
|
|
sb_bias_addr.add_argument("--account", type=str, help="微信账号", metavar="", required=True)
|
|
|
|
|
sb_bias_addr.add_argument("--key", type=str, metavar="", help="(可选)密钥")
|
|
|
|
|
sb_bias_addr.add_argument("--db_path", type=str, metavar="", help="(可选)已登录账号的微信文件夹路径")
|
|
|
|
|
sb_bias_addr.add_argument("-vlp", '--version_list_path', type=str, metavar="",
|
2023-11-15 15:04:45 +08:00
|
|
|
|
help="(可选)微信版本偏移文件路径,如有,则自动更新",
|
2023-10-15 10:37:19 +08:00
|
|
|
|
default=None)
|
2023-10-14 23:53:06 +08:00
|
|
|
|
self.sb_bias_addr = sb_bias_addr
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return sb_bias_addr
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 判断是否至少输入一个参数
|
2023-10-24 16:58:16 +08:00
|
|
|
|
# if not args.key and not args.db_path:
|
|
|
|
|
# self.sb_bias_addr.error("必须至少指定 --key 或 --db_path 参数中的一个")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
mobile = args.mobile
|
|
|
|
|
name = args.name
|
|
|
|
|
account = args.account
|
|
|
|
|
key = args.key
|
|
|
|
|
db_path = args.db_path
|
2023-11-15 15:04:45 +08:00
|
|
|
|
vlp = args.version_list_path
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 调用 run 函数,并传入参数
|
2023-11-15 15:04:45 +08:00
|
|
|
|
rdata = BiasAddr(account, mobile, name, key, db_path).run(True, vlp)
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return rdata
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MainWxInfo():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "info"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'wx_info' 子命令解析器
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_wx_info = parser.add_parser(self.mode, help="获取微信信息")
|
2023-11-22 18:33:49 +08:00
|
|
|
|
sb_wx_info.add_argument("-vlp", '--version_list_path', metavar="", type=str,
|
|
|
|
|
help="(可选)微信版本偏移文件路径", default=VERSION_LIST_PATH)
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return sb_wx_info
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 读取微信各版本偏移
|
2023-11-22 18:33:49 +08:00
|
|
|
|
path = args.version_list_path
|
2023-11-15 15:04:45 +08:00
|
|
|
|
version_list = json.load(open(path, "r", encoding="utf-8"))
|
|
|
|
|
result = read_info(version_list, True) # 读取微信信息
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MainWxDbPath():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "db_path"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'wx_db_path' 子命令解析器
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_wx_db_path = parser.add_parser(self.mode, help="获取微信文件夹路径")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
sb_wx_db_path.add_argument("-r", "--require_list", type=str,
|
|
|
|
|
help="(可选)需要的数据库名称(eg: -r MediaMSG;MicroMsg;FTSMSG;MSG;Sns;Emotion )",
|
2023-10-14 23:53:06 +08:00
|
|
|
|
default="all", metavar="")
|
|
|
|
|
sb_wx_db_path.add_argument("-wf", "--wx_files", type=str, help="(可选)'WeChat Files'路径", default=None,
|
|
|
|
|
metavar="")
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_wx_db_path.add_argument("-id", "--wxid", type=str, help="(可选)wxid_,用于确认用户文件夹",
|
|
|
|
|
default=None, metavar="")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return sb_wx_db_path
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
require_list = args.require_list
|
2023-11-10 11:04:25 +08:00
|
|
|
|
msg_dir = args.wx_files
|
2023-11-15 15:04:45 +08:00
|
|
|
|
wxid = args.wxid
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
user_dirs = get_wechat_db(require_list, msg_dir, wxid, True) # 获取微信数据库路径
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return user_dirs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MainDecrypt():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "decrypt"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'decrypt' 子命令解析器
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_decrypt = parser.add_parser(self.mode, help="解密微信数据库")
|
2023-10-14 23:53:06 +08:00
|
|
|
|
sb_decrypt.add_argument("-k", "--key", type=str, help="密钥", required=True, metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-i", "--db_path", type=str, help="数据库路径(目录or文件)", required=True, metavar="")
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_decrypt.add_argument("-o", "--out_path", type=str, default=os.path.join(os.getcwd(), "decrypted"),
|
|
|
|
|
help="输出路径(必须是目录)[默认为当前路径下decrypted文件夹]", required=False,
|
2023-10-14 23:53:06 +08:00
|
|
|
|
metavar="")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return sb_decrypt
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
key = args.key
|
|
|
|
|
db_path = args.db_path
|
|
|
|
|
out_path = args.out_path
|
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
if not os.path.exists(db_path):
|
2023-12-03 09:43:33 +08:00
|
|
|
|
print(f"[-] 数据库路径不存在:{db_path}")
|
2023-11-15 15:04:45 +08:00
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(out_path):
|
|
|
|
|
os.makedirs(out_path)
|
|
|
|
|
print(f"[+] 创建输出文件夹:{out_path}")
|
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 调用 decrypt 函数,并传入参数
|
2023-11-15 15:04:45 +08:00
|
|
|
|
result = batch_decrypt(key, db_path, out_path, True)
|
|
|
|
|
return result
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
2023-12-06 13:30:46 +08:00
|
|
|
|
class MainMerge():
|
|
|
|
|
def init_parses(self, parser):
|
|
|
|
|
self.mode = "merge"
|
|
|
|
|
# 添加 'decrypt' 子命令解析器
|
2023-12-09 22:48:33 +08:00
|
|
|
|
sb_merge = parser.add_parser(self.mode, help="[测试功能]合并微信数据库(MSG.db or MediaMSG.db)")
|
2023-12-11 18:59:16 +08:00
|
|
|
|
sb_merge.add_argument("-i", "--db_path", type=str, help="数据库路径(文件路径,使用英文[,]分割)", required=True,
|
|
|
|
|
metavar="")
|
2023-12-06 13:30:46 +08:00
|
|
|
|
sb_merge.add_argument("-o", "--out_path", type=str, default=os.path.join(os.getcwd(), "decrypted"),
|
2023-12-11 18:59:16 +08:00
|
|
|
|
help="输出路径(目录或文件名)[默认为当前路径下decrypted文件夹下merge_***.db]",
|
|
|
|
|
required=False,
|
2023-12-06 13:30:46 +08:00
|
|
|
|
metavar="")
|
|
|
|
|
return sb_merge
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
db_path = args.db_path
|
|
|
|
|
out_path = args.out_path
|
|
|
|
|
|
|
|
|
|
db_path = db_path.split(",")
|
2023-12-11 18:59:16 +08:00
|
|
|
|
db_path = [i.strip() for i in db_path]
|
|
|
|
|
dbpaths = []
|
2023-12-06 13:30:46 +08:00
|
|
|
|
for i in db_path:
|
2023-12-11 18:59:16 +08:00
|
|
|
|
if not os.path.exists(i): # 判断路径是否存在
|
2023-12-06 13:30:46 +08:00
|
|
|
|
print(f"[-] 数据库路径不存在:{i}")
|
|
|
|
|
return
|
2023-12-11 18:59:16 +08:00
|
|
|
|
if os.path.isdir(i): # 如果是文件夹,则获取文件夹下所有的db文件
|
|
|
|
|
dbpaths += [os.path.join(i, j) for j in os.listdir(i) if j.endswith(".db")]
|
|
|
|
|
else: # 如果是文件,则直接添加
|
|
|
|
|
dbpaths.append(i)
|
2023-12-06 13:30:46 +08:00
|
|
|
|
|
2023-12-10 00:16:05 +08:00
|
|
|
|
if (not out_path.endswith(".db")) and (not os.path.exists(out_path)):
|
2023-12-06 13:30:46 +08:00
|
|
|
|
os.makedirs(out_path)
|
|
|
|
|
print(f"[+] 创建输出文件夹:{out_path}")
|
|
|
|
|
|
2023-12-10 00:16:05 +08:00
|
|
|
|
print(f"[*] 合并中...(用时较久,耐心等待)")
|
|
|
|
|
|
2023-12-11 18:59:16 +08:00
|
|
|
|
result = merge_db(dbpaths, out_path)
|
2023-12-06 13:30:46 +08:00
|
|
|
|
|
2023-12-11 18:56:04 +08:00
|
|
|
|
print(f"[+] 合并完成:{result}")
|
2023-12-06 13:30:46 +08:00
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
2023-11-11 17:02:22 +08:00
|
|
|
|
class MainShowChatRecords():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "dbshow"
|
2023-11-11 17:02:22 +08:00
|
|
|
|
# 添加 'decrypt' 子命令解析器
|
2023-12-01 16:48:01 +08:00
|
|
|
|
sb_decrypt = parser.add_parser(self.mode, help="聊天记录查看")
|
2023-11-11 17:02:22 +08:00
|
|
|
|
sb_decrypt.add_argument("-msg", "--msg_path", type=str, help="解密后的 MSG.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-micro", "--micro_path", type=str, help="解密后的 MicroMsg.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-media", "--media_path", type=str, help="解密后的 MediaMSG.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_decrypt.add_argument("-fs", "--filestorage_path", type=str,
|
|
|
|
|
help="(可选)文件夹FileStorage的路径(用于显示图片)", required=False,
|
2023-11-11 17:02:22 +08:00
|
|
|
|
metavar="")
|
|
|
|
|
return sb_decrypt
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
try:
|
|
|
|
|
from flask import Flask, request, jsonify, render_template, g
|
2023-11-15 15:04:45 +08:00
|
|
|
|
import logging
|
2023-11-11 17:02:22 +08:00
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
print("[-] 请安装flask( pip install flask )")
|
|
|
|
|
return
|
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
if not os.path.exists(args.msg_path) or not os.path.exists(args.micro_path) or not os.path.exists(
|
|
|
|
|
args.media_path):
|
|
|
|
|
print(os.path.exists(args.msg_path), os.path.exists(args.micro_path), os.path.exists(args.media_path))
|
|
|
|
|
print("[-] 输入数据库路径不存在")
|
|
|
|
|
return
|
|
|
|
|
|
2023-11-11 17:02:22 +08:00
|
|
|
|
app = Flask(__name__, template_folder='./show_chat/templates')
|
2023-11-15 15:04:45 +08:00
|
|
|
|
app.logger.setLevel(logging.ERROR)
|
2023-11-11 17:02:22 +08:00
|
|
|
|
|
|
|
|
|
@app.before_request
|
|
|
|
|
def before_request():
|
2023-11-15 15:04:45 +08:00
|
|
|
|
|
2023-11-11 17:02:22 +08:00
|
|
|
|
g.MSG_ALL_db_path = args.msg_path
|
|
|
|
|
g.MicroMsg_db_path = args.micro_path
|
|
|
|
|
g.MediaMSG_all_db_path = args.media_path
|
|
|
|
|
g.FileStorage_path = args.filestorage_path
|
|
|
|
|
g.USER_LIST = get_user_list(args.msg_path, args.micro_path)
|
|
|
|
|
|
|
|
|
|
app.register_blueprint(app_show_chat)
|
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
print("[+] 请使用浏览器访问 http://127.0.0.1:5000/ 查看聊天记录")
|
2023-12-12 09:59:43 +08:00
|
|
|
|
app.run(host='0.0.0.0', port=5000, debug=False)
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
2023-11-16 18:55:45 +08:00
|
|
|
|
class MainExportChatRecords():
|
|
|
|
|
def init_parses(self, parser):
|
|
|
|
|
self.mode = "export"
|
|
|
|
|
# 添加 'decrypt' 子命令解析器
|
2023-12-01 16:48:01 +08:00
|
|
|
|
sb_decrypt = parser.add_parser(self.mode, help="聊天记录导出为html")
|
2023-11-27 10:12:12 +08:00
|
|
|
|
sb_decrypt.add_argument("-u", "--username", type=str, help="微信账号(聊天对象账号)", required=True, metavar="")
|
2023-11-16 18:55:45 +08:00
|
|
|
|
sb_decrypt.add_argument("-o", "--outpath", type=str, help="导出路径", required=True, metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-msg", "--msg_path", type=str, help="解密后的 MSG.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-micro", "--micro_path", type=str, help="解密后的 MicroMsg.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-media", "--media_path", type=str, help="解密后的 MediaMSG.db 的路径", required=True,
|
|
|
|
|
metavar="")
|
|
|
|
|
sb_decrypt.add_argument("-fs", "--filestorage_path", type=str,
|
|
|
|
|
help="(可选)文件夹FileStorage的路径(用于显示图片)", required=False,
|
|
|
|
|
metavar="")
|
|
|
|
|
return sb_decrypt
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 从命令行参数获取值
|
|
|
|
|
try:
|
|
|
|
|
from flask import Flask, request, jsonify, render_template, g
|
|
|
|
|
import logging
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
2023-11-27 10:12:12 +08:00
|
|
|
|
print("[-] 请安装flask( pip install flask)")
|
2023-11-16 18:55:45 +08:00
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(args.msg_path) or not os.path.exists(args.micro_path) or not os.path.exists(
|
|
|
|
|
args.media_path):
|
|
|
|
|
print(os.path.exists(args.msg_path), os.path.exists(args.micro_path), os.path.exists(args.media_path))
|
|
|
|
|
print("[-] 输入数据库路径不存在")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(args.outpath):
|
|
|
|
|
os.makedirs(args.outpath)
|
|
|
|
|
print(f"[+] 创建输出文件夹:{args.outpath}")
|
|
|
|
|
|
|
|
|
|
export(args.username, args.outpath, args.msg_path, args.micro_path, args.media_path, args.filestorage_path)
|
|
|
|
|
print(f"[+] 导出成功{args.outpath}")
|
|
|
|
|
|
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
class MainAll():
|
|
|
|
|
def init_parses(self, parser):
|
2023-11-15 15:04:45 +08:00
|
|
|
|
self.mode = "all"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'all' 子命令解析器
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_all = parser.add_parser(self.mode, help="获取微信信息,解密微信数据库,查看聊天记录")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
return sb_all
|
|
|
|
|
|
|
|
|
|
def run(self, args):
|
|
|
|
|
# 获取微信信息
|
2023-11-15 15:04:45 +08:00
|
|
|
|
WxInfo = read_info(VERSION_LIST, True)
|
|
|
|
|
|
|
|
|
|
for user in WxInfo:
|
|
|
|
|
key = user.get("key", "")
|
|
|
|
|
if not key:
|
|
|
|
|
print("[-] 未获取到密钥")
|
|
|
|
|
return
|
|
|
|
|
wxid = user.get("wxid", None)
|
2023-12-18 08:28:26 +08:00
|
|
|
|
filePath = user.get("filePath", None)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
|
|
|
|
|
WxDbPath = get_wechat_db('all', None, wxid=wxid, is_logging=True) # 获取微信数据库路径
|
2023-12-03 19:43:20 +08:00
|
|
|
|
if isinstance(WxDbPath, str): # 如果返回的是字符串,则表示出错
|
|
|
|
|
print(WxDbPath)
|
|
|
|
|
return
|
2023-11-15 15:04:45 +08:00
|
|
|
|
wxdbpaths = [path for user_dir in WxDbPath.values() for paths in user_dir.values() for path in paths]
|
|
|
|
|
if len(wxdbpaths) == 0:
|
|
|
|
|
print("[-] 未获取到数据库路径")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
wxdblen = len(wxdbpaths)
|
|
|
|
|
print(f"[+] 共发现 {wxdblen} 个微信数据库")
|
|
|
|
|
print("=" * 32)
|
|
|
|
|
|
|
|
|
|
out_path = os.path.join(os.getcwd(), "decrypted", wxid) if wxid else os.path.join(os.getcwd(), "decrypted")
|
|
|
|
|
print(f"[*] 解密后文件夹:{out_path} ")
|
|
|
|
|
print(f"[*] 解密中...(用时较久,耐心等待)")
|
|
|
|
|
if not os.path.exists(out_path):
|
|
|
|
|
os.makedirs(out_path)
|
|
|
|
|
|
|
|
|
|
# 判断out_path是否为空目录
|
|
|
|
|
if os.listdir(out_path):
|
|
|
|
|
isdel = input(f"[*] 输出文件夹不为空({out_path})\n 是否删除?(y/n):")
|
|
|
|
|
if isdel.lower() == 'y' or isdel.lower() == 'yes':
|
|
|
|
|
for root, dirs, files in os.walk(out_path, topdown=False):
|
|
|
|
|
for name in files:
|
|
|
|
|
os.remove(os.path.join(root, name))
|
|
|
|
|
for name in dirs:
|
|
|
|
|
os.rmdir(os.path.join(root, name))
|
|
|
|
|
|
|
|
|
|
# 调用 decrypt 函数,并传入参数 # 解密
|
|
|
|
|
code, ret = batch_decrypt(key, wxdbpaths, out_path, False)
|
|
|
|
|
if not code:
|
|
|
|
|
print(ret)
|
|
|
|
|
return
|
|
|
|
|
print("[+] 解密完成")
|
|
|
|
|
print("-" * 32)
|
|
|
|
|
errors = []
|
|
|
|
|
out_dbs = []
|
|
|
|
|
for code1, ret1 in ret:
|
|
|
|
|
if code1 == False:
|
|
|
|
|
errors.append(ret1)
|
|
|
|
|
else:
|
|
|
|
|
print(
|
|
|
|
|
f'[+] success "{os.path.relpath(ret1[0], os.path.commonprefix(wxdbpaths))}" -> "{os.path.relpath(ret1[1], os.getcwd())}"')
|
|
|
|
|
out_dbs.append(ret1[1])
|
|
|
|
|
print("-" * 32)
|
2023-11-22 18:33:49 +08:00
|
|
|
|
print(
|
2023-12-12 09:43:13 +08:00
|
|
|
|
"[-] " + f"警告:共 {len(errors)} 个文件未解密(可能原因:非当前登录用户数据库;非加密数据库),详见{out_path}下‘未解密.txt’;")
|
2023-11-15 15:04:45 +08:00
|
|
|
|
# print("; ".join([f'"{wxdbpaths[i]}"' for i in errors]))
|
2023-12-12 09:43:13 +08:00
|
|
|
|
with open(os.path.join(out_path, "未解密.txt"), "w", encoding="utf-8") as f:
|
2023-11-22 18:33:49 +08:00
|
|
|
|
f.write("\n".join([f'{i}' for i in errors]))
|
2023-11-15 15:04:45 +08:00
|
|
|
|
print("=" * 32)
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
if len(out_dbs) <= 0:
|
|
|
|
|
print("[-] 未获取到解密后的数据库路径")
|
|
|
|
|
return
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-12-18 08:28:26 +08:00
|
|
|
|
FileStorage_path = os.path.join(filePath, "FileStorage") if filePath else "FileStorage"
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
# 查看聊天记录
|
|
|
|
|
MSGDB = [i for i in out_dbs if "de_MSG" in i]
|
|
|
|
|
MSGDB = MSGDB[-1] if MSGDB else None
|
|
|
|
|
MicroMsgDB = [i for i in out_dbs if "de_MicroMsg" in i]
|
|
|
|
|
MicroMsgDB = MicroMsgDB[-1] if MicroMsgDB else None
|
|
|
|
|
MediaMSGDB = [i for i in out_dbs if "de_MediaMSG" in i]
|
|
|
|
|
MediaMSGDB = MediaMSGDB[-1] if MediaMSGDB else None
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
args.msg_path = MSGDB
|
|
|
|
|
args.micro_path = MicroMsgDB
|
|
|
|
|
args.media_path = MediaMSGDB
|
|
|
|
|
args.filestorage_path = FileStorage_path
|
|
|
|
|
MainShowChatRecords().run(args)
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-12-18 22:36:11 +08:00
|
|
|
|
PYWXDUMP_VERSION = pywxdump.__version__
|
2023-11-22 18:33:49 +08:00
|
|
|
|
|
|
|
|
|
class CustomArgumentParser(argparse.ArgumentParser):
|
|
|
|
|
def format_help(self):
|
|
|
|
|
# 首先显示软件简介
|
|
|
|
|
# 定义软件简介文本并进行格式化
|
2023-11-30 17:50:17 +08:00
|
|
|
|
line_len = 70
|
2023-12-18 22:36:11 +08:00
|
|
|
|
PYWXDUMP_VERSION = pywxdump.__version__
|
2023-11-30 17:50:17 +08:00
|
|
|
|
wxdump_line = '\n'.join([f'\033[36m{line:^{line_len}}\033[0m' for line in wxdump_ascii.split('\n') if line])
|
|
|
|
|
first_line = f'\033[36m{" PyWxDump v" + PYWXDUMP_VERSION + " ":=^{line_len}}\033[0m'
|
2023-11-30 18:14:35 +08:00
|
|
|
|
brief = 'PyWxDump功能:获取账号信息、解密数据库、查看聊天记录、导出聊天记录为html等'
|
2023-11-22 18:33:49 +08:00
|
|
|
|
other = '更多详情请查看: \033[4m\033[1mhttps://github.com/xaoyaoo/PyWxDump\033[0m'
|
|
|
|
|
|
2023-11-30 18:14:35 +08:00
|
|
|
|
separator = f'\033[36m{" options ":-^{line_len}}\033[0m'
|
2023-11-22 18:33:49 +08:00
|
|
|
|
|
|
|
|
|
# 获取帮助信息并添加到软件简介下方
|
|
|
|
|
help_text = super().format_help().strip()
|
|
|
|
|
|
2023-11-30 18:14:35 +08:00
|
|
|
|
return f'\n{wxdump_line}\n\n{first_line}\n{brief}\n{separator}\n{help_text}\n{separator}\n{other}\n{first_line}\n'
|
2023-11-22 18:33:49 +08:00
|
|
|
|
|
|
|
|
|
|
2023-10-14 23:53:06 +08:00
|
|
|
|
def console_run():
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 创建命令行参数解析器
|
2023-11-22 18:33:49 +08:00
|
|
|
|
parser = CustomArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
2023-12-18 22:36:11 +08:00
|
|
|
|
PYWXDUMP_VERSION = pywxdump.__version__
|
2023-11-22 18:33:49 +08:00
|
|
|
|
parser.add_argument('-V', '--version', action='version', version=f"PyWxDump v{PYWXDUMP_VERSION}")
|
2023-11-15 16:17:50 +08:00
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加子命令解析器
|
2023-10-14 23:53:06 +08:00
|
|
|
|
subparsers = parser.add_subparsers(dest="mode", help="""运行模式:""", required=True, metavar="mode")
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes = {}
|
|
|
|
|
# 添加 'bias' 子命令解析器
|
2023-10-14 21:48:35 +08:00
|
|
|
|
main_bias_addr = MainBiasAddr()
|
|
|
|
|
sb_bias_addr = main_bias_addr.init_parses(subparsers)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[main_bias_addr.mode] = main_bias_addr
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
# 添加 'info' 子命令解析器
|
2023-10-14 21:48:35 +08:00
|
|
|
|
main_wx_info = MainWxInfo()
|
|
|
|
|
sb_wx_info = main_wx_info.init_parses(subparsers)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[main_wx_info.mode] = main_wx_info
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
# 添加 'db_path' 子命令解析器
|
2023-10-14 21:48:35 +08:00
|
|
|
|
main_wx_db_path = MainWxDbPath()
|
|
|
|
|
sb_wx_db_path = main_wx_db_path.init_parses(subparsers)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[main_wx_db_path.mode] = main_wx_db_path
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
|
|
|
|
# 添加 'decrypt' 子命令解析器
|
|
|
|
|
main_decrypt = MainDecrypt()
|
|
|
|
|
sb_decrypt = main_decrypt.init_parses(subparsers)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[main_decrypt.mode] = main_decrypt
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-12-06 13:30:46 +08:00
|
|
|
|
# 添加 'merge' 子命令解析器
|
|
|
|
|
main_merge = MainMerge()
|
|
|
|
|
sb_merge = main_merge.init_parses(subparsers)
|
|
|
|
|
modes[main_merge.mode] = main_merge
|
|
|
|
|
|
2023-11-15 15:04:45 +08:00
|
|
|
|
# 添加 '' 子命令解析器
|
2023-11-11 17:02:22 +08:00
|
|
|
|
main_show_chat_records = MainShowChatRecords()
|
2023-11-15 15:04:45 +08:00
|
|
|
|
sb_dbshow = main_show_chat_records.init_parses(subparsers)
|
|
|
|
|
modes[main_show_chat_records.mode] = main_show_chat_records
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-16 18:55:45 +08:00
|
|
|
|
# 添加 'export' 子命令解析器
|
|
|
|
|
main_export_chat_records = MainExportChatRecords()
|
|
|
|
|
sb_export = main_export_chat_records.init_parses(subparsers)
|
|
|
|
|
modes[main_export_chat_records.mode] = main_export_chat_records
|
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 添加 'all' 子命令解析器
|
|
|
|
|
main_all = MainAll()
|
|
|
|
|
sb_all = main_all.init_parses(subparsers)
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[main_all.mode] = main_all
|
2023-10-14 21:48:35 +08:00
|
|
|
|
|
2023-11-22 18:33:49 +08:00
|
|
|
|
# 检查是否需要显示帮助信息
|
|
|
|
|
if len(sys.argv) == 1:
|
|
|
|
|
sys.argv.append('-h')
|
2023-11-22 18:40:37 +08:00
|
|
|
|
elif len(sys.argv) == 2 and sys.argv[1] in modes.keys() and sys.argv[1] not in [main_all.mode, main_wx_info.mode,
|
|
|
|
|
main_wx_db_path.mode]:
|
2023-11-22 18:33:49 +08:00
|
|
|
|
sys.argv.append('-h')
|
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
args = parser.parse_args() # 解析命令行参数
|
|
|
|
|
|
2023-10-14 23:53:06 +08:00
|
|
|
|
if not any(vars(args).values()):
|
|
|
|
|
parser.print_help()
|
2023-11-15 15:04:45 +08:00
|
|
|
|
|
2023-10-14 21:48:35 +08:00
|
|
|
|
# 根据不同的 'mode' 参数,执行不同的操作
|
2023-11-15 15:04:45 +08:00
|
|
|
|
modes[args.mode].run(args)
|
2023-10-14 23:53:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
console_run()
|