add auto get bias addr ,not need input key or wx folder path.

This commit is contained in:
xaoyo 2023-10-24 16:58:16 +08:00
parent 97f0df565a
commit 4b694146e7
10 changed files with 249 additions and 98 deletions

View File

@ -18,6 +18,7 @@
<details>
<summary><strong>更新日志(点击展开)</strong></summary>
* 2023.10.24 add auto get bias addr ,not need input key or wx folder path.
* 2023.10.17 add LICENSE
* 2023.10.16 添加"3.9.7.15"版本的偏移[#12](https://github.com/xaoyaoo/PyWxDump/issues/12)
,感谢@[GentlemanII](https://github.com/GentlemanII)
@ -73,7 +74,7 @@ PyWxDump
│ │ ├─ get_wx_info.py # 获取微信基本信息脚本
│ │ └─ get_wx_db.py # 获取本地所有的微信相关数据库
│ ├─ command.py # 命令行入口
│ └─ version_list.json # 微信版本列表
│ └─ version_list.json # 微信版本列表 (十进制)按顺序代表微信昵称、微信账号、微信手机号、微信邮箱默认0、微信KEY、微信原始IDwxid_******
├─ doc # 项目文档
│ ├─ python1.0_README.md # python1.0版本的README
│ ├─ wx数据库简述.md # wx数据库简述
@ -156,8 +157,8 @@ wxdump bias_addr -h
# --mobile MOBILE 手机号
# --name NAME 微信昵称
# --account ACCOUNT 微信账号
# --key KEY (与db_path二选一)密钥
# --db_path DB_PATH (与key二选一)已登录账号的微信文件夹路径
# --key KEY (可选)密钥
# --db_path DB_PATH (可选)已登录账号的微信文件夹路径
# -vlp VLP (可选)微信版本偏移文件路径
wxdump wx_info -h

View File

@ -51,7 +51,7 @@ KEY的基址即**2FFF970-000024=2FFF94C**
十进制地址为50329932
代码块中的五个十进制按顺序代表微信昵称、微信账号、微信手机号、微信邮箱高版本失效这个随便填、微信KEY
代码块中的五个十进制按顺序代表微信昵称、微信账号、微信手机号、微信邮箱高版本失效这个随便填、微信KEY、微信原始IDwxid_******
```jsx
{

View File

@ -135,7 +135,7 @@ python get_base_addr.py --mobile 152***** --name **** --account *** --key *****
return{'3.9.7.29': [63486984, 63488320, 63486792, 0, 63488256, 56006136]}
(十进制)按顺序代表微信昵称、微信账号、微信手机号、微信邮箱默认0、微信KEY、版本信息
(十进制)按顺序代表微信昵称、微信账号、微信手机号、微信邮箱默认0、微信KEY、微信原始IDwxid_******
[注]如果参数错误得到的对应地址偏移为0邮箱高版本失效默认为0

View File

@ -15,6 +15,7 @@ import re
import time
import winreg
import threading
import platform
import psutil
# import win32api
@ -55,6 +56,8 @@ class BiasAddr:
self.pm = Pymem("WeChat.exe")
self.bits = self.get_osbits()
self.islogin = True
def find_all(self, c: bytes, string: bytes, base_addr=0):
@ -73,55 +76,105 @@ class BiasAddr:
return file_version
self.islogin = False
def get_osbits(self):
return int(platform.architecture()[0][:-3])
def search_memory_value(self, value: bytes, module_name="WeChatWin.dll"):
# 创建 Pymem 对象
pm = self.pm
module = pymem.process.module_from_name(pm.process_handle, module_name)
# result = pymem.pattern.pattern_scan_module(pm.process_handle, module, value, return_multiple=True)
# result = result[-1]-module.lpBaseOfDll if len(result) > 0 else 0
mem_data = pm.read_bytes(module.lpBaseOfDll, module.SizeOfImage)
result = self.find_all(value, mem_data)
result = result[-1] if len(result) > 0 else 0
return result
def search_key(self, key: bytes):
pid = self.pm.process_id
# print(self.pm.process_base.lpBaseOfDll, self.pm.process_base.SizeOfImage)
module_start_addr = 34199871460642
module_end_addr = 0
process = psutil.Process(pid)
for module in process.memory_maps(grouped=False):
if "WeChat" in module.path:
start_addr = int(module.addr, 16)
end_addr = start_addr + module.rss
if module_start_addr > start_addr:
module_start_addr = start_addr
if module_end_addr < end_addr:
module_end_addr = end_addr
batch = 4096
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
array = ctypes.create_string_buffer(batch)
key_addr = 0
for i in range(module_start_addr, module_end_addr, batch):
if ReadProcessMemory(Handle, void_p(i), array, batch, None) == 0:
continue
hex_string = array.raw # 读取到的内存数据
key_addr = self.find_all(key, hex_string, i)
if len(key_addr) > 0:
key_addr = key_addr[0]
break
# print(hex(key_addr))
key = key_addr.to_bytes(8, byteorder='little')
# print(key.hex())
byteLen = 4 if self.bits == 32 else 8 # 4字节或8字节
key_addr = self.pm.pattern_scan_all(key, return_multiple=True)[-1] if len(key) > 0 else 0
key = key_addr.to_bytes(byteLen, byteorder='little', signed=True)
result = self.search_memory_value(key, self.module_name)
return result
def get_key_bias_test(self):
byteLen = 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
pm = self.pm
module = pymem.process.module_from_name(pm.process_handle, "WeChatWin.dll")
keyBytes = b'-----BEGIN PUBLIC KEY-----\n...'
publicKeyList = pymem.pattern.pattern_scan_all(self.pm.process_handle, keyBytes, return_multiple=True)
keyaddrs = []
for addr in publicKeyList:
keyBytes = addr.to_bytes(byteLen, byteorder="little", signed=True) # 低位在前
addrs = pymem.pattern.pattern_scan_module(pm.process_handle, module, keyBytes, return_multiple=True)
if addrs != 0:
keyaddrs += addrs
keyWinAddr = 0
for addr in keyaddrs:
keyLen = pm.read_uchar(addr - keyLenOffset)
if keyLen != 32:
continue
keyWinAddr = addr - keyWindllOffset
# keyaddr = int.from_bytes(pm.read_bytes(keyWinAddr, byteLen), byteorder='little')
# key = pm.read_bytes(keyaddr, 32)
# print("key", key.hex())
return keyWinAddr - module.lpBaseOfDll
def get_wxid_bias(self):
byteLen = 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
pm = self.pm
module = pymem.process.module_from_name(pm.process_handle, "WeChatWin.dll")
keyBytes = b'wxid_'
publicWxidList = pymem.pattern.pattern_scan_all(self.pm.process_handle, keyBytes, return_multiple=True)
import ahocorasick
def search_substrings(text, substrings):
A = ahocorasick.Automaton()
for index, s in enumerate(substrings):
A.add_word(s, (index, s))
A.make_automaton()
results = []
for end_index, (insert_order, original_value) in A.iter(text):
start_index = end_index - len(original_value) + 1
results.append(int(start_index / 2))
return results
patterns = []
for addr in publicWxidList:
keyBytes = addr.to_bytes(byteLen, byteorder="little", signed=True) # 低位在前
patterns.append(keyBytes.hex())
text = pm.read_bytes(module.lpBaseOfDll, module.SizeOfImage).hex()
wxidaddrs = search_substrings(text, patterns)
# print("wxidaddrs", wxidaddrs)
# wxidaddr = 0
# for addr in wxidaddrs:
# print(addr - 63488256)
# wxidaddr = int.from_bytes(pm.read_bytes(addr + module.lpBaseOfDll, byteLen), byteorder='little')
# print("wxidaddr", hex(wxidaddr))
# wxid = pm.read_bytes(wxidaddr, 24).split(b"\x00")[0]
# print("wxid", wxid)
return wxidaddrs[-2]
def get_key_bias(self, wx_db_path, account_bias=0):
wx_db_path = os.path.join(wx_db_path, "Msg", "MicroMsg.db")
if not os.path.exists(wx_db_path):
return False
return 0
def get_maybe_key(mem_data):
maybe_key = []
@ -202,13 +255,24 @@ class BiasAddr:
name_bias = self.search_memory_value(self.name)
account_bias = self.search_memory_value(self.account)
# version_bias = self.search_memory_value(self.version.encode("utf-8"))
if self.key:
key_bias = self.search_key(self.key)
elif self.db_path:
key_bias = self.get_key_bias(self.db_path, account_bias)
else:
try:
key_bias = self.get_key_bias_test()
except:
key_bias = 0
return {self.version: [name_bias, account_bias, mobile_bias, 0, key_bias]}
try:
wxid_bias = self.get_wxid_bias()
except:
wxid_bias = 0
if key_bias <= 0:
if self.key:
key_bias = self.search_key(self.key)
elif self.db_path:
key_bias = self.get_key_bias(self.db_path, account_bias)
else:
key_bias = 0
return {self.version: [name_bias, account_bias, mobile_bias, 0, key_bias, wxid_bias]}
if __name__ == '__main__':

View File

@ -11,6 +11,7 @@ import os
from . import *
# version_list_path = os.path.join(os.path.dirname(__file__), "version_list.json")
@ -30,8 +31,8 @@ class MainBiasAddr():
def run(self, args):
# 判断是否至少输入一个参数
if not args.key and not args.db_path:
self.sb_bias_addr.error("必须至少指定 --key 或 --db_path 参数中的一个")
# if not args.key and not args.db_path:
# self.sb_bias_addr.error("必须至少指定 --key 或 --db_path 参数中的一个")
# 从命令行参数获取值
mobile = args.mobile
@ -164,6 +165,10 @@ class MainAll():
args.vlp = VERSION_LIST_PATH
result_WxInfo = MainWxInfo().run(args)
keys = [i.get('key', "") for i in result_WxInfo]
if not keys:
print("[-] 未获取到密钥")
return
wxids = [i.get('wxid', "") for i in result_WxInfo]
args.require_list = 'all'
args.wf = None

View File

@ -4,328 +4,375 @@
328122328,
328123056,
328121976,
328123020
328123020,
0
],
"3.3.0.115": [
31323364,
31323744,
31324472,
31323392,
31324436
31324436,
0
],
"3.3.0.84": [
31315212,
31315592,
31316320,
31315240,
31316284
31316284,
0
],
"3.3.0.93": [
31323364,
31323744,
31324472,
31323392,
31324436
31324436,
0
],
"3.3.5.34": [
30603028,
30603408,
30604120,
30603056,
30604100
30604100,
0
],
"3.3.5.42": [
30603012,
30603392,
30604120,
30603040,
30604084
30604084,
0
],
"3.3.5.46": [
30578372,
30578752,
30579480,
30578400,
30579444
30579444,
0
],
"3.4.0.37": [
31608116,
31608496,
31609224,
31608144,
31609188
31609188,
0
],
"3.4.0.38": [
31604044,
31604424,
31605152,
31604072,
31605116
31605116,
0
],
"3.4.0.50": [
31688500,
31688880,
31689608,
31688528,
31689572
31689572,
0
],
"3.4.0.54": [
31700852,
31701248,
31700920,
31700880,
31701924
31701924,
0
],
"3.4.5.27": [
32133788,
32134168,
32134896,
32133816,
32134860
32134860,
0
],
"3.4.5.45": [
32147012,
32147392,
32147064,
32147040,
32148084
32148084,
0
],
"3.5.0.20": [
35494484,
35494864,
35494536,
35494512,
35495556
35495556,
0
],
"3.5.0.29": [
35507980,
35508360,
35508032,
35508008,
35509052
35509052,
0
],
"3.5.0.33": [
35512140,
35512520,
35512192,
35512168,
35513212
35513212,
0
],
"3.5.0.39": [
35516236,
35516616,
35516288,
35516264,
35517308
35517308,
0
],
"3.5.0.42": [
35512140,
35512520,
35512192,
35512168,
35513212
35513212,
0
],
"3.5.0.44": [
35510836,
35511216,
35510896,
35510864,
35511908
35511908,
0
],
"3.5.0.46": [
35506740,
35507120,
35506800,
35506768,
35507812
35507812,
0
],
"3.6.0.18": [
35842996,
35843376,
35843048,
35843024,
35844068
35844068,
0
],
"3.6.5.7": [
35864356,
35864736,
35864408,
35864384,
35865428
35865428,
0
],
"3.6.5.16": [
35909428,
35909808,
35909480,
35909456,
35910500
35910500,
0
],
"3.7.0.26": [
37105908,
37106288,
37105960,
37105936,
37106980
37106980,
0
],
"3.7.0.29": [
37105908,
37106288,
37105960,
37105936,
37106980
37106980,
0
],
"3.7.0.30": [
37118196,
37118576,
37118248,
37118224,
37119268
37119268,
0
],
"3.7.5.11": [
37883280,
37884088,
37883136,
37883008,
37884052
37884052,
0
],
"3.7.5.23": [
37895736,
37896544,
37895592,
37883008,
37896508
37896508,
0
],
"3.7.5.27": [
37895736,
37896544,
37895592,
37895464,
37896508
37896508,
0
],
"3.7.5.31": [
37903928,
37904736,
37903784,
37903656,
37904700
37904700,
0
],
"3.7.6.24": [
38978840,
38979648,
38978696,
38978604,
38979612
38979612,
0
],
"3.7.6.29": [
38986376,
38987184,
38986232,
38986104,
38987148
38987148,
0
],
"3.7.6.44": [
39016520,
39017328,
39016376,
38986104,
39017292
39017292,
0
],
"3.8.0.31": [
46064088,
46064912,
46063944,
38986104,
46064876
46064876,
0
],
"3.8.0.33": [
46059992,
46060816,
46059848,
38986104,
46060780
46060780,
0
],
"3.8.0.41": [
46064024,
46064848,
46063880,
38986104,
46064812
46064812,
0
],
"3.8.1.26": [
46409448,
46410272,
46409304,
38986104,
46410236
46410236,
0
],
"3.9.0.28": [
48418376,
48419280,
48418232,
38986104,
48419244
48419244,
0
],
"3.9.2.23": [
50320784,
50321712,
50320640,
38986104,
50321676
50321676,
0
],
"3.9.2.26": [
50329040,
50329968,
50328896,
38986104,
50329932
50329932,
0
],
"3.9.5.81": [
61650872,
61652208,
61650680,
0,
61652144
61652144,
0
],
"3.9.5.91": [
61654904,
61654680,
61654712,
38986104,
61656176
61656176,
0
],
"3.9.6.19": [
61997688,
61997464,
61997496,
38986104,
61998960
61998960,
0
],
"3.9.6.33": [
62030600,
62031936,
62030408,
0,
62031872
62031872,
0
],
"3.9.7.15": [
63482696,
63484032,
63482504,
0,
63483968
63483968,
0
],
"3.9.7.25": [
63482760,
63484096,
63482568,
0,
63484032
63484032,
0
],
"3.9.7.29": [
63486984,
63488320,
63486792,
0,
63488256
63488256,
63488352
]
}

View File

@ -44,7 +44,7 @@ def get_wechat_db(require_list: [list | str] = "all", msg_dir: str = None):
elif isinstance(require_list, list):
pattern = {}
for require in require_list:
pattern[require] = re.compile(r".*%s.*\.db$" % require)
pattern[require] = re.compile(r"%s.*\.db$" % require)
else:
return "[-] 参数错误"

View File

@ -23,18 +23,26 @@ def get_info_without_key(h_process, address, n_size=64):
return text.strip() if text.strip() != "" else "None"
def get_info_wxid(h_process, address, n_size=32):
array = ctypes.create_string_buffer(8)
if ReadProcessMemory(h_process, void_p(address), array, 8, 0) == 0: return "None"
address = int.from_bytes(array, byteorder='little') # 逆序转换为int地址key地址
wxid = get_info_without_key(h_process, address, n_size)
return wxid
# 读取内存中的key
def get_key(h_process, address):
array = ctypes.create_string_buffer(8)
if ReadProcessMemory(h_process, void_p(address), array, 8, 0) == 0: return "None"
key = ctypes.create_string_buffer(32)
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
# 读取微信信息(key, name, account, mobile, mail)
# 读取微信信息(account,mobile,name,mail,wxid,key)
def read_info(version_list):
wechat_process = []
result = []
@ -71,11 +79,14 @@ def read_info(version_list):
mobile_baseaddr = wechat_base_address + support_list[2]
mail_baseaddr = wechat_base_address + support_list[3]
key_baseaddr = wechat_base_address + support_list[4]
wxid_baseaddr = wechat_base_address + support_list[5]
tmp_rd['account'] = get_info_without_key(Handle, account__baseaddr, 32)
tmp_rd['mobile'] = get_info_without_key(Handle, mobile_baseaddr, 64)
tmp_rd['name'] = get_info_without_key(Handle, name_baseaddr, 64)
tmp_rd['mail'] = get_info_without_key(Handle, mail_baseaddr, 64) if support_list[3] != 0 else "None"
tmp_rd['wxid'] = get_info_wxid(Handle, wxid_baseaddr, 24) if support_list[5] != 0 else "None"
if not tmp_rd['wxid'].startswith("wxid_"): tmp_rd['wxid'] = "None"
tmp_rd['key'] = get_key(Handle, key_baseaddr)
result.append(tmp_rd)

View File

@ -3,7 +3,7 @@ from setuptools import setup, find_packages
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
version = "2.1.4"
version = "2.1.5"
setup(
name="pywxdump",
author="xaoyaoo",
@ -39,7 +39,8 @@ setup(
"silk-python",
"pyaudio",
"requests",
"pillow"
"pillow",
"pyahocorasick"
],
entry_points={
'console_scripts': [

22
tests/t2.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: t2.py
# Description:
# Author: xaoyaoo
# Date: 2023/10/21
# -------------------------------------------------------------------------------
import json
# from pywxdump import VERSION_LIST
with open(r'D:\_code\py_code\test\a2023\b0821wxdb\PyWxDump\pywxdump\version_list.json', 'r') as f:
VERSION_LIST = json.load(f)
for version in VERSION_LIST:
VERSION_LIST[version] = VERSION_LIST[version] + [0] if len(VERSION_LIST[version]) == 5 else VERSION_LIST[version]
with open(r'D:\_code\py_code\test\a2023\b0821wxdb\PyWxDump\pywxdump\version_list.json', 'w') as f:
json.dump(VERSION_LIST, f, indent=4, ensure_ascii=False)
if __name__ == '__main__':
pass