获取key基址偏移可以根据微信文件夹获取,不需要输入key
This commit is contained in:
parent
2fc599a8f6
commit
d2b31f0120
@ -7,25 +7,47 @@
|
|||||||
# -------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------
|
||||||
import argparse
|
import argparse
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import multiprocessing
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
import winreg
|
||||||
|
import threading
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
import win32api
|
import win32api
|
||||||
from pymem import Pymem
|
from pymem import Pymem
|
||||||
import pymem
|
import pymem
|
||||||
|
import hmac
|
||||||
|
|
||||||
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
|
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
|
||||||
void_p = ctypes.c_void_p
|
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
|
||||||
|
|
||||||
|
|
||||||
class BaseAddr:
|
class BaseAddr:
|
||||||
def __init__(self, account, mobile, name, key):
|
def __init__(self, account, mobile, name, key, db_path):
|
||||||
self.account = account.encode("utf-8")
|
self.account = account.encode("utf-8")
|
||||||
self.mobile = mobile.encode("utf-8")
|
self.mobile = mobile.encode("utf-8")
|
||||||
self.name = name.encode("utf-8")
|
self.name = name.encode("utf-8")
|
||||||
self.key = bytes.fromhex(key)
|
self.key = bytes.fromhex(key) if key else b""
|
||||||
|
self.db_path = db_path if db_path else ""
|
||||||
|
|
||||||
self.process_name = "WeChat.exe"
|
self.process_name = "WeChat.exe"
|
||||||
self.module_name = "WeChatWin.dll"
|
self.module_name = "WeChatWin.dll"
|
||||||
@ -66,22 +88,20 @@ class BaseAddr:
|
|||||||
pid = self.pm.process_id
|
pid = self.pm.process_id
|
||||||
# print(self.pm.process_base.lpBaseOfDll, self.pm.process_base.SizeOfImage)
|
# print(self.pm.process_base.lpBaseOfDll, self.pm.process_base.SizeOfImage)
|
||||||
|
|
||||||
batch = 4096
|
|
||||||
|
|
||||||
module_start_addr = 34199871460642
|
module_start_addr = 34199871460642
|
||||||
module_end_addr = 0
|
module_end_addr = 0
|
||||||
for process in psutil.process_iter(['name', 'exe', 'pid', 'cmdline']):
|
process = psutil.Process(pid)
|
||||||
if process.name() == self.process_name:
|
for module in process.memory_maps(grouped=False):
|
||||||
for module in process.memory_maps(grouped=False):
|
if "WeChat" in module.path:
|
||||||
if "WeChat" in module.path:
|
start_addr = int(module.addr, 16)
|
||||||
start_addr = int(module.addr, 16)
|
end_addr = start_addr + module.rss
|
||||||
end_addr = start_addr + module.rss
|
|
||||||
|
|
||||||
if module_start_addr > start_addr:
|
if module_start_addr > start_addr:
|
||||||
module_start_addr = start_addr
|
module_start_addr = start_addr
|
||||||
if module_end_addr < end_addr:
|
if module_end_addr < end_addr:
|
||||||
module_end_addr = end_addr
|
module_end_addr = end_addr
|
||||||
|
|
||||||
|
batch = 4096
|
||||||
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
|
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
|
||||||
array = ctypes.create_string_buffer(batch)
|
array = ctypes.create_string_buffer(batch)
|
||||||
key_addr = 0
|
key_addr = 0
|
||||||
@ -93,19 +113,91 @@ class BaseAddr:
|
|||||||
if len(key_addr) > 0:
|
if len(key_addr) > 0:
|
||||||
key_addr = key_addr[0]
|
key_addr = key_addr[0]
|
||||||
break
|
break
|
||||||
# print(key_addr)
|
|
||||||
|
# print(hex(key_addr))
|
||||||
key = key_addr.to_bytes(8, byteorder='little')
|
key = key_addr.to_bytes(8, byteorder='little')
|
||||||
|
# print(key.hex())
|
||||||
result = self.search_memory_value(key, self.module_name)
|
result = self.search_memory_value(key, self.module_name)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_key_bias(self, wx_db_path):
|
||||||
|
wx_db_path = os.path.join(wx_db_path, "Msg", "MicroMsg.db")
|
||||||
|
if not os.path.exists(wx_db_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
module_name = "WeChatWin.dll"
|
||||||
|
pm = self.pm
|
||||||
|
module = pymem.process.module_from_name(pm.process_handle, module_name)
|
||||||
|
start_addr = module.lpBaseOfDll
|
||||||
|
size = module.SizeOfImage
|
||||||
|
mem_data = pm.read_bytes(start_addr, size)
|
||||||
|
|
||||||
|
min_addr = 0xffffffffffffffffffffffff
|
||||||
|
max_addr = 0
|
||||||
|
for module1 in pm.list_modules():
|
||||||
|
if module1.lpBaseOfDll < min_addr:
|
||||||
|
min_addr = module1.lpBaseOfDll
|
||||||
|
if module1.lpBaseOfDll > max_addr:
|
||||||
|
max_addr = module1.lpBaseOfDll
|
||||||
|
|
||||||
|
def read_key(addr):
|
||||||
|
key = ctypes.create_string_buffer(35)
|
||||||
|
if ReadProcessMemory(pm.process_handle, void_p(addr - 1), key, 35, 0) == 0:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
if b"\x00\x00" in key.raw[1:33]:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
if b"\x00\x00" == key.raw[33:35] and b"\x90" == key.raw[0:1]:
|
||||||
|
return key.raw[1:33]
|
||||||
|
return b""
|
||||||
|
|
||||||
|
def get_maybe_key(mem_data):
|
||||||
|
maybe_key = []
|
||||||
|
for i in range(0, len(mem_data), 8):
|
||||||
|
addr = mem_data[i:i + 8]
|
||||||
|
addr = int.from_bytes(addr, byteorder='little')
|
||||||
|
# 去掉不可能的地址
|
||||||
|
if min_addr < addr < max_addr:
|
||||||
|
key = read_key(addr)
|
||||||
|
if key == b"":
|
||||||
|
continue
|
||||||
|
maybe_key.append([key, i])
|
||||||
|
return maybe_key
|
||||||
|
|
||||||
|
def verify_key(keys, wx_db_path):
|
||||||
|
|
||||||
|
with open(wx_db_path, "rb") as file:
|
||||||
|
blist = file.read(5000)
|
||||||
|
salt = blist[:16]
|
||||||
|
first = blist[16:DEFAULT_PAGESIZE]
|
||||||
|
mac_salt = bytes([(salt[i] ^ 58) for i in range(16)])
|
||||||
|
|
||||||
|
with multiprocessing.Pool(processes=8) as pool:
|
||||||
|
results = [pool.apply_async(validate_key, args=(key, salt, first, mac_salt)) for key, i in keys[-1::-1]]
|
||||||
|
results = [p.get() for p in results]
|
||||||
|
for i, result in enumerate(results[-1::-1]):
|
||||||
|
if result:
|
||||||
|
return keys[i]
|
||||||
|
return b"", 0
|
||||||
|
|
||||||
|
maybe_key = get_maybe_key(mem_data)
|
||||||
|
key, bais = verify_key(maybe_key, wx_db_path)
|
||||||
|
return bais
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.version = self.get_file_version(self.process_name)
|
self.version = self.get_file_version(self.process_name)
|
||||||
if not self.islogin:
|
if not self.islogin:
|
||||||
return "[-] WeChat No Run"
|
return "[-] WeChat No Run"
|
||||||
key_bias = self.search_key(self.key)
|
|
||||||
mobile_bias = self.search_memory_value(self.mobile)
|
mobile_bias = self.search_memory_value(self.mobile)
|
||||||
name_bias = self.search_memory_value(self.name)
|
name_bias = self.search_memory_value(self.name)
|
||||||
account_bias = self.search_memory_value(self.account)
|
account_bias = self.search_memory_value(self.account)
|
||||||
|
if self.key:
|
||||||
|
key_bias = self.search_key(self.key)
|
||||||
|
elif self.db_path:
|
||||||
|
key_bias = self.get_key_bias(self.db_path)
|
||||||
|
else:
|
||||||
|
key_bias = 0
|
||||||
return {self.version: [name_bias, account_bias, mobile_bias, 0, key_bias]}
|
return {self.version: [name_bias, account_bias, mobile_bias, 0, key_bias]}
|
||||||
|
|
||||||
|
|
||||||
@ -116,24 +208,25 @@ if __name__ == '__main__':
|
|||||||
parser.add_argument("--name", type=str, help="微信昵称")
|
parser.add_argument("--name", type=str, help="微信昵称")
|
||||||
parser.add_argument("--account", type=str, help="微信账号")
|
parser.add_argument("--account", type=str, help="微信账号")
|
||||||
parser.add_argument("--key", type=str, help="密钥")
|
parser.add_argument("--key", type=str, help="密钥")
|
||||||
|
parser.add_argument("--db_path", type=str, help="加密数据库路径(登录的微信文件夹路径)")
|
||||||
|
|
||||||
# 解析命令行参数
|
# 解析命令行参数
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# 检查是否缺少必要参数,并抛出错误
|
# 检查是否缺少必要参数,并抛出错误
|
||||||
if not args.mobile or not args.name or not args.account or not args.key:
|
if not args.mobile or not args.name or not args.account:
|
||||||
raise ValueError("缺少必要的命令行参数!请提供手机号、微信昵称、微信账号和密钥。")
|
raise ValueError("缺少必要的命令行参数!请提供手机号、微信昵称、微信账号。")
|
||||||
|
if not args.key and not args.db_path:
|
||||||
|
raise ValueError("缺少必要的命令行参数!请提供密钥或加密数据库路径。")
|
||||||
# 从命令行参数获取值
|
# 从命令行参数获取值
|
||||||
mobile = args.mobile
|
mobile = args.mobile
|
||||||
name = args.name
|
name = args.name
|
||||||
account = args.account
|
account = args.account
|
||||||
key = args.key
|
key = args.key
|
||||||
|
db_path = args.db_path
|
||||||
|
|
||||||
# 调用 run 函数,并传入参数
|
# 调用 run 函数,并传入参数
|
||||||
# rdata = run(mobile, name, account, key)
|
rdata = BaseAddr(account, mobile, name, key, db_path).run()
|
||||||
# print(rdata)
|
|
||||||
rdata = BaseAddr(account, mobile, name, key).run()
|
|
||||||
|
|
||||||
print(rdata)
|
print(rdata)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# <center>PyWxDump</center>
|
# <center>PyWxDump</center>
|
||||||
|
|
||||||
* 更新日志(如果有[version_list.json](./Program/version_list.json)缺少的版本,请帮忙添加。)
|
* 更新日志(如果有[version_list.json](./Program/version_list.json)缺少的版本,请帮忙添加。)
|
||||||
|
* 2023.10.09 获取key基址偏移可以根据微信文件夹获取,不需要输入key
|
||||||
* 2023.10.09 优化代码,删减没必要代码,重新修改获取基址代码,加快运行速度(需要安装新的库 pymem)
|
* 2023.10.09 优化代码,删减没必要代码,重新修改获取基址代码,加快运行速度(需要安装新的库 pymem)
|
||||||
* 2023.10.07 修改获取基址内存搜索方式,防止进入死循环
|
* 2023.10.07 修改获取基址内存搜索方式,防止进入死循环
|
||||||
* 2023.10.07 增加了3.9.7.29版本的偏移地址
|
* 2023.10.07 增加了3.9.7.29版本的偏移地址
|
||||||
@ -113,7 +114,10 @@ print(data)
|
|||||||
**3.1 通过python脚本获取**
|
**3.1 通过python脚本获取**
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python get_base_addr.py --mobile 152******** --name ****** --account ****** --key **********************************************
|
python get_base_addr.py --mobile 152***** --name **** --account *** --key ********** --db_path "****\WeChat Files\wxid_******"
|
||||||
|
```
|
||||||
|
|
||||||
|
# mobile、name、account为必填参数, key、db_path二者必填其一,使用key时,执行速度快,db_path时,执行速度慢(大约需要10s-60s,也可能更长)
|
||||||
|
|
||||||
# return:{'3.9.7.29': [63486984, 63488320, 63486792, 0, 63488256]}
|
# return:{'3.9.7.29': [63486984, 63488320, 63486792, 0, 63488256]}
|
||||||
# (十进制)按顺序代表:微信昵称、微信账号、微信手机号、微信邮箱(默认0)、微信KEY
|
# (十进制)按顺序代表:微信昵称、微信账号、微信手机号、微信邮箱(默认0)、微信KEY
|
||||||
|
Loading…
Reference in New Issue
Block a user