获取key基址偏移可以根据微信文件夹获取,不需要输入key

This commit is contained in:
xaoyo
2023-10-09 11:30:51 +08:00
parent 2fc599a8f6
commit d2b31f0120
2 changed files with 120 additions and 23 deletions
+115 -22
View File
@@ -7,25 +7,47 @@
# -------------------------------------------------------------------------------
import argparse
import ctypes
import hashlib
import json
import multiprocessing
import os
import re
import time
import winreg
import threading
import psutil
import win32api
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
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.mobile = mobile.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.module_name = "WeChatWin.dll"
@@ -66,22 +88,20 @@ class BaseAddr:
pid = self.pm.process_id
# print(self.pm.process_base.lpBaseOfDll, self.pm.process_base.SizeOfImage)
batch = 4096
module_start_addr = 34199871460642
module_end_addr = 0
for process in psutil.process_iter(['name', 'exe', 'pid', 'cmdline']):
if process.name() == self.process_name:
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
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
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
@@ -93,19 +113,91 @@ class BaseAddr:
if len(key_addr) > 0:
key_addr = key_addr[0]
break
# print(key_addr)
# print(hex(key_addr))
key = key_addr.to_bytes(8, byteorder='little')
# print(key.hex())
result = self.search_memory_value(key, self.module_name)
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):
self.version = self.get_file_version(self.process_name)
if not self.islogin:
return "[-] WeChat No Run"
key_bias = self.search_key(self.key)
mobile_bias = self.search_memory_value(self.mobile)
name_bias = self.search_memory_value(self.name)
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]}
@@ -116,24 +208,25 @@ if __name__ == '__main__':
parser.add_argument("--name", type=str, help="微信昵称")
parser.add_argument("--account", type=str, help="微信账号")
parser.add_argument("--key", type=str, help="密钥")
parser.add_argument("--db_path", type=str, help="加密数据库路径(登录的微信文件夹路径)")
# 解析命令行参数
args = parser.parse_args()
# 检查是否缺少必要参数,并抛出错误
if not args.mobile or not args.name or not args.account or not args.key:
raise ValueError("缺少必要的命令行参数!请提供手机号、微信昵称、微信账号和密钥。")
if not args.mobile or not args.name or not args.account:
raise ValueError("缺少必要的命令行参数!请提供手机号、微信昵称、微信账号。")
if not args.key and not args.db_path:
raise ValueError("缺少必要的命令行参数!请提供密钥或加密数据库路径。")
# 从命令行参数获取值
mobile = args.mobile
name = args.name
account = args.account
key = args.key
db_path = args.db_path
# 调用 run 函数,并传入参数
# rdata = run(mobile, name, account, key)
# print(rdata)
rdata = BaseAddr(account, mobile, name, key).run()
rdata = BaseAddr(account, mobile, name, key, db_path).run()
print(rdata)