加快wxinfo获取,速度再次提升40%
This commit is contained in:
parent
9e3e4cb5ae
commit
d08ae98b26
@ -9,6 +9,27 @@ PROCESS_QUERY_INFORMATION = 0x0400
|
||||
PROCESS_VM_READ = 0x0010
|
||||
|
||||
|
||||
# MEMORY_BASIC_INFORMATION 结构体定义
|
||||
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('BaseAddress', ctypes.wintypes.LPVOID),
|
||||
('AllocationBase', ctypes.wintypes.LPVOID),
|
||||
('AllocationProtect', ctypes.wintypes.DWORD),
|
||||
('RegionSize', ctypes.c_size_t),
|
||||
('State', ctypes.wintypes.DWORD),
|
||||
('Protect', ctypes.wintypes.DWORD),
|
||||
('Type', ctypes.wintypes.DWORD)
|
||||
]
|
||||
|
||||
|
||||
class MODULEINFO(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("lpBaseOfDll", ctypes.c_void_p), # remote pointer
|
||||
("SizeOfImage", ctypes.c_ulong),
|
||||
("EntryPoint", ctypes.c_void_p), # remote pointer
|
||||
]
|
||||
|
||||
|
||||
# 定义PROCESSENTRY32结构
|
||||
class PROCESSENTRY32(ctypes.Structure):
|
||||
_fields_ = [("dwSize", ctypes.wintypes.DWORD),
|
||||
@ -74,23 +95,15 @@ VerQueryValueW.argtypes = [ctypes.c_void_p, ctypes.wintypes.LPCWSTR, ctypes.POIN
|
||||
ctypes.POINTER(ctypes.wintypes.UINT)]
|
||||
VerQueryValueW.restype = ctypes.wintypes.BOOL
|
||||
|
||||
# 获取模块信息
|
||||
GetModuleInformation = psapi.GetModuleInformation
|
||||
GetModuleInformation.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.HMODULE, ctypes.POINTER(MODULEINFO),
|
||||
ctypes.wintypes.DWORD]
|
||||
GetModuleInformation.restype = ctypes.c_bool
|
||||
|
||||
# 读取进程内存
|
||||
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
|
||||
|
||||
|
||||
# MEMORY_BASIC_INFORMATION 结构体定义
|
||||
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('BaseAddress', ctypes.wintypes.LPVOID),
|
||||
('AllocationBase', ctypes.wintypes.LPVOID),
|
||||
('AllocationProtect', ctypes.wintypes.DWORD),
|
||||
('RegionSize', ctypes.c_size_t),
|
||||
('State', ctypes.wintypes.DWORD),
|
||||
('Protect', ctypes.wintypes.DWORD),
|
||||
('Type', ctypes.wintypes.DWORD)
|
||||
]
|
||||
|
||||
|
||||
# 定义VirtualQueryEx函数
|
||||
VirtualQueryEx = kernel32.VirtualQueryEx
|
||||
VirtualQueryEx.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.LPCVOID, ctypes.POINTER(MEMORY_BASIC_INFORMATION),
|
||||
@ -139,6 +152,10 @@ def get_memory_maps(pid):
|
||||
else:
|
||||
file_name = None
|
||||
|
||||
# module_info = MODULEINFO()
|
||||
# if GetModuleInformation(hProcess, mbi.BaseAddress, ctypes.byref(module_info), ctypes.sizeof(module_info)):
|
||||
# file_name = get_file_version_info(module_info.lpBaseOfDll)
|
||||
|
||||
memory_maps.append({
|
||||
'BaseAddress': mbi.BaseAddress,
|
||||
'RegionSize': mbi.RegionSize,
|
||||
|
@ -14,8 +14,23 @@ import psutil
|
||||
import pymem
|
||||
from typing import List, Union
|
||||
from .utils import pattern_scan_all, verify_key, get_exe_version, get_exe_bit, info_error
|
||||
from .memory_search import search_memory
|
||||
import ctypes.wintypes as wintypes
|
||||
|
||||
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
|
||||
# 定义常量
|
||||
PROCESS_QUERY_INFORMATION = 0x0400
|
||||
PROCESS_VM_READ = 0x0010
|
||||
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
OpenProcess = kernel32.OpenProcess
|
||||
OpenProcess.restype = wintypes.HANDLE
|
||||
OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD]
|
||||
|
||||
CloseHandle = kernel32.CloseHandle
|
||||
CloseHandle.restype = wintypes.BOOL
|
||||
CloseHandle.argtypes = [wintypes.HANDLE]
|
||||
|
||||
ReadProcessMemory = kernel32.ReadProcessMemory
|
||||
void_p = ctypes.c_void_p
|
||||
|
||||
|
||||
@ -59,7 +74,7 @@ def get_info_name(h_process, address, address_len=8, n_size=64):
|
||||
@info_error
|
||||
def get_info_wxid(h_process):
|
||||
find_num = 100
|
||||
addrs = pattern_scan_all(h_process, br'\\Msg\\FTSContact', return_multiple=True, find_num=find_num)
|
||||
addrs = search_memory(h_process, br'\\Msg\\FTSContact', max_num=find_num)
|
||||
wxids = []
|
||||
for addr in addrs:
|
||||
array = ctypes.create_string_buffer(80)
|
||||
@ -69,6 +84,7 @@ def get_info_wxid(h_process):
|
||||
array = array.split(b"\\")[-1]
|
||||
wxids.append(array.decode('utf-8', errors='ignore'))
|
||||
wxid = max(wxids, key=wxids.count) if wxids else "None"
|
||||
CloseHandle(h_process)
|
||||
return wxid
|
||||
|
||||
|
||||
@ -76,7 +92,7 @@ def get_info_wxid(h_process):
|
||||
@info_error
|
||||
def get_info_filePath_base_wxid(h_process, wxid=""):
|
||||
find_num = 10
|
||||
addrs = pattern_scan_all(h_process, wxid.encode() + br'\\Msg\\FTSContact', return_multiple=True, find_num=find_num)
|
||||
addrs = search_memory(h_process, wxid.encode() + br'\\Msg\\FTSContact', max_num=find_num)
|
||||
filePath = []
|
||||
for addr in addrs:
|
||||
win_addr_len = 260
|
||||
@ -86,6 +102,7 @@ def get_info_filePath_base_wxid(h_process, wxid=""):
|
||||
array = array.split(b"\00")[-1]
|
||||
filePath.append(array.decode('utf-8', errors='ignore'))
|
||||
filePath = max(filePath, key=filePath.count) if filePath else "None"
|
||||
CloseHandle(h_process)
|
||||
return filePath
|
||||
|
||||
|
||||
@ -157,7 +174,6 @@ def get_key(pid, db_path, addr_len):
|
||||
:param addr_len: 地址长度
|
||||
:return: 返回key
|
||||
"""
|
||||
|
||||
def read_key_bytes(h_process, address, address_len=8):
|
||||
array = ctypes.create_string_buffer(address_len)
|
||||
if ReadProcessMemory(h_process, void_p(address), array, address_len, 0) == 0: return "None"
|
||||
@ -171,11 +187,27 @@ def get_key(pid, db_path, addr_len):
|
||||
phone_type2 = "android\x00"
|
||||
phone_type3 = "ipad\x00"
|
||||
|
||||
pm = pymem.Pymem(pid)
|
||||
module_name = "WeChatWin.dll"
|
||||
|
||||
MicroMsg_path = os.path.join(db_path, "MSG", "MicroMsg.db")
|
||||
|
||||
# start_adress = 0
|
||||
# end_adress = 0x7FFFFFFFFFFFFFFF
|
||||
#
|
||||
# memory_maps = get_memory_maps(pid)
|
||||
# for module in memory_maps:
|
||||
# if module.FileName and 'WeChatWin.dll' in module.FileName:
|
||||
# start_adress = module.BaseAddress
|
||||
# end_adress = module.BaseAddress + module.RegionSize
|
||||
# # print(start_adress, end_adress)
|
||||
# hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)
|
||||
# type1_addrs = search_memory(hProcess, phone_type1.encode(), start_adress, end_adress)
|
||||
# type2_addrs = search_memory(hProcess, phone_type2.encode(), start_adress, end_adress)
|
||||
# type3_addrs = search_memory(hProcess, phone_type3.encode(), start_adress, end_adress)
|
||||
#
|
||||
# print(type1_addrs, type2_addrs, type3_addrs)
|
||||
|
||||
|
||||
pm = pymem.Pymem(pid)
|
||||
module_name = "WeChatWin.dll"
|
||||
type1_addrs = pm.pattern_scan_module(phone_type1.encode(), module_name, return_multiple=True)
|
||||
type2_addrs = pm.pattern_scan_module(phone_type2.encode(), module_name, return_multiple=True)
|
||||
type3_addrs = pm.pattern_scan_module(phone_type3.encode(), module_name, return_multiple=True)
|
||||
@ -210,9 +242,10 @@ def get_details(pid, version_list: dict = None, is_logging: bool = False):
|
||||
"account": "None", "mobile": "None", "name": "None", "mail": "None",
|
||||
"wxid": "None", "key": "None", "filePath": "None"}
|
||||
try:
|
||||
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
|
||||
bias_list = version_list.get(rd['version'], None)
|
||||
|
||||
Handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)
|
||||
|
||||
addrLen = get_exe_bit(path) // 8
|
||||
if not isinstance(bias_list, list) or len(bias_list) <= 4:
|
||||
error = f"[-] WeChat Current Version Is Not Supported(maybe not get account,mobile,name,mail)"
|
||||
@ -240,19 +273,22 @@ def get_details(pid, version_list: dict = None, is_logging: bool = False):
|
||||
rd['mobile'] = get_info_string(Handle, mobile_baseaddr, 64) if bias_list[2] != 0 else "None"
|
||||
rd['name'] = get_info_name(Handle, name_baseaddr, addrLen, 64) if bias_list[0] != 0 else "None"
|
||||
rd['mail'] = get_info_string(Handle, mail_baseaddr, 64) if bias_list[3] != 0 else "None"
|
||||
rd['key'] = get_info_with_key(Handle, key_baseaddr, addrLen) if bias_list[4] != 0 else "None"
|
||||
# rd['key'] = get_info_with_key(Handle, key_baseaddr, addrLen) if bias_list[4] != 0 else "None"
|
||||
|
||||
rd['wxid'] = get_info_wxid(Handle)
|
||||
|
||||
rd['filePath'] = get_info_filePath(rd['wxid']) if rd['wxid'] != "None" else "None"
|
||||
if rd['wxid'] != "None" and rd['filePath'] == "None": # 通过wxid获取filePath,如果filePath为空则通过wxid获取filePath
|
||||
rd['filePath'] = get_info_filePath_base_wxid(Handle, rd['wxid'])
|
||||
rd['filePath'] = get_info_filePath_base_wxid(Handle, wxid=rd['wxid'])
|
||||
|
||||
isKey = verify_key(bytes.fromhex(rd["key"]),
|
||||
os.path.join(rd['filePath'], "MSG", "MicroMsg.db")) if rd['key'] != "None" and rd[
|
||||
isKey = verify_key(
|
||||
bytes.fromhex(rd["key"]),
|
||||
os.path.join(rd['filePath'], "MSG", "MicroMsg.db")) if rd['key'] != "None" and rd[
|
||||
'filePath'] != "None" else False
|
||||
|
||||
if rd['filePath'] != "None" and rd['key'] == "None" and not isKey:
|
||||
rd['key'] = get_key(rd['pid'], rd['filePath'], addrLen)
|
||||
CloseHandle(Handle)
|
||||
except Exception as e:
|
||||
error = f"[-] WeChat Get Info Error:{e}"
|
||||
if is_logging: print(error)
|
||||
|
118
pywxdump/wx_info/memory_search.py
Normal file
118
pywxdump/wx_info/memory_search.py
Normal file
@ -0,0 +1,118 @@
|
||||
import ctypes
|
||||
import ctypes.wintypes as wintypes
|
||||
import logging
|
||||
from ctypes.wintypes import HANDLE
|
||||
import re
|
||||
import sys
|
||||
|
||||
# 定义常量
|
||||
PROCESS_QUERY_INFORMATION = 0x0400
|
||||
PROCESS_VM_READ = 0x0010
|
||||
|
||||
PAGE_EXECUTE = 0x10
|
||||
PAGE_EXECUTE_READ = 0x20
|
||||
PAGE_EXECUTE_READWRITE = 0x40
|
||||
PAGE_EXECUTE_WRITECOPY = 0x80
|
||||
PAGE_NOACCESS = 0x01
|
||||
PAGE_READONLY = 0x02
|
||||
PAGE_READWRITE = 0x04
|
||||
PAGE_WRITECOPY = 0x08
|
||||
PAGE_GUARD = 0x100
|
||||
PAGE_NOCACHE = 0x200
|
||||
PAGE_WRITECOMBINE = 0x400
|
||||
|
||||
MEM_COMMIT = 0x1000
|
||||
MEM_FREE = 0x10000
|
||||
MEM_RESERVE = 0x2000
|
||||
MEM_DECOMMIT = 0x4000
|
||||
MEM_RELEASE = 0x8000
|
||||
|
||||
|
||||
# 定义结构体
|
||||
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("BaseAddress", ctypes.c_void_p),
|
||||
("AllocationBase", ctypes.c_void_p),
|
||||
("AllocationProtect", wintypes.DWORD),
|
||||
("RegionSize", ctypes.c_size_t),
|
||||
("State", wintypes.DWORD),
|
||||
("Protect", wintypes.DWORD),
|
||||
("Type", wintypes.DWORD),
|
||||
]
|
||||
|
||||
|
||||
# 加载Windows API函数
|
||||
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
||||
|
||||
OpenProcess = kernel32.OpenProcess
|
||||
OpenProcess.restype = wintypes.HANDLE
|
||||
OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD]
|
||||
|
||||
ReadProcessMemory = kernel32.ReadProcessMemory
|
||||
|
||||
VirtualQueryEx = kernel32.VirtualQueryEx
|
||||
VirtualQueryEx.restype = ctypes.c_size_t
|
||||
VirtualQueryEx.argtypes = [wintypes.HANDLE, ctypes.c_void_p, ctypes.POINTER(MEMORY_BASIC_INFORMATION), ctypes.c_size_t]
|
||||
|
||||
CloseHandle = kernel32.CloseHandle
|
||||
CloseHandle.restype = wintypes.BOOL
|
||||
CloseHandle.argtypes = [wintypes.HANDLE]
|
||||
|
||||
|
||||
def search_memory(hProcess, pattern=br'\\Msg\\FTSContact', max_num=100,start_address=0x0,end_address=0x7FFFFFFFFFFFFFFF):
|
||||
"""
|
||||
在进程内存中搜索字符串
|
||||
:param p: 进程ID或者进程句柄
|
||||
:param pattern: 要搜索的字符串
|
||||
:param max_num: 最多找到的数量
|
||||
"""
|
||||
result = []
|
||||
# 打开进程
|
||||
if not hProcess:
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
|
||||
mbi = MEMORY_BASIC_INFORMATION()
|
||||
|
||||
address = start_address
|
||||
max_address = end_address if sys.maxsize > 2 ** 32 else 0x7fff0000
|
||||
pattern = re.compile(pattern)
|
||||
|
||||
while address < max_address:
|
||||
if VirtualQueryEx(hProcess, address, ctypes.byref(mbi), ctypes.sizeof(mbi)) == 0:
|
||||
break
|
||||
# 读取内存数据
|
||||
allowed_protections = [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PAGE_READONLY, ]
|
||||
if mbi.State != MEM_COMMIT or mbi.Protect not in allowed_protections:
|
||||
address += mbi.RegionSize
|
||||
continue
|
||||
|
||||
# 使用正确的类型来避免OverflowError
|
||||
base_address_c = ctypes.c_ulonglong(mbi.BaseAddress)
|
||||
region_size_c = ctypes.c_size_t(mbi.RegionSize)
|
||||
|
||||
page_bytes = ctypes.create_string_buffer(mbi.RegionSize)
|
||||
bytes_read = ctypes.c_size_t()
|
||||
|
||||
if ReadProcessMemory(hProcess, base_address_c, page_bytes, region_size_c, ctypes.byref(bytes_read)) == 0:
|
||||
address += mbi.RegionSize
|
||||
continue
|
||||
# 搜索字符串 re print(page_bytes.raw)
|
||||
find = [address + match.start() for match in pattern.finditer(page_bytes, re.DOTALL)]
|
||||
if find:
|
||||
result.extend(find)
|
||||
if len(result) >= max_num:
|
||||
break
|
||||
address += mbi.RegionSize
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 示例用法
|
||||
pid = 29320 # 将此替换为你要查询的进程ID
|
||||
try:
|
||||
maps = search_memory(pid)
|
||||
print(len(maps))
|
||||
for m in maps:
|
||||
print(hex(m))
|
||||
except Exception as e:
|
||||
logging.error(e, exc_info=True)
|
Loading…
Reference in New Issue
Block a user