加快wxinfo获取,速度再次提升40%
This commit is contained in:
parent
9e3e4cb5ae
commit
d08ae98b26
@ -9,6 +9,27 @@ PROCESS_QUERY_INFORMATION = 0x0400
|
|||||||
PROCESS_VM_READ = 0x0010
|
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结构
|
# 定义PROCESSENTRY32结构
|
||||||
class PROCESSENTRY32(ctypes.Structure):
|
class PROCESSENTRY32(ctypes.Structure):
|
||||||
_fields_ = [("dwSize", ctypes.wintypes.DWORD),
|
_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)]
|
ctypes.POINTER(ctypes.wintypes.UINT)]
|
||||||
VerQueryValueW.restype = ctypes.wintypes.BOOL
|
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
|
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函数
|
||||||
VirtualQueryEx = kernel32.VirtualQueryEx
|
VirtualQueryEx = kernel32.VirtualQueryEx
|
||||||
VirtualQueryEx.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.LPCVOID, ctypes.POINTER(MEMORY_BASIC_INFORMATION),
|
VirtualQueryEx.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.LPCVOID, ctypes.POINTER(MEMORY_BASIC_INFORMATION),
|
||||||
@ -139,6 +152,10 @@ def get_memory_maps(pid):
|
|||||||
else:
|
else:
|
||||||
file_name = None
|
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({
|
memory_maps.append({
|
||||||
'BaseAddress': mbi.BaseAddress,
|
'BaseAddress': mbi.BaseAddress,
|
||||||
'RegionSize': mbi.RegionSize,
|
'RegionSize': mbi.RegionSize,
|
||||||
|
@ -14,8 +14,23 @@ import psutil
|
|||||||
import pymem
|
import pymem
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
from .utils import pattern_scan_all, verify_key, get_exe_version, get_exe_bit, info_error
|
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
|
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
|
@info_error
|
||||||
def get_info_wxid(h_process):
|
def get_info_wxid(h_process):
|
||||||
find_num = 100
|
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 = []
|
wxids = []
|
||||||
for addr in addrs:
|
for addr in addrs:
|
||||||
array = ctypes.create_string_buffer(80)
|
array = ctypes.create_string_buffer(80)
|
||||||
@ -69,6 +84,7 @@ def get_info_wxid(h_process):
|
|||||||
array = array.split(b"\\")[-1]
|
array = array.split(b"\\")[-1]
|
||||||
wxids.append(array.decode('utf-8', errors='ignore'))
|
wxids.append(array.decode('utf-8', errors='ignore'))
|
||||||
wxid = max(wxids, key=wxids.count) if wxids else "None"
|
wxid = max(wxids, key=wxids.count) if wxids else "None"
|
||||||
|
CloseHandle(h_process)
|
||||||
return wxid
|
return wxid
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +92,7 @@ def get_info_wxid(h_process):
|
|||||||
@info_error
|
@info_error
|
||||||
def get_info_filePath_base_wxid(h_process, wxid=""):
|
def get_info_filePath_base_wxid(h_process, wxid=""):
|
||||||
find_num = 10
|
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 = []
|
filePath = []
|
||||||
for addr in addrs:
|
for addr in addrs:
|
||||||
win_addr_len = 260
|
win_addr_len = 260
|
||||||
@ -86,6 +102,7 @@ def get_info_filePath_base_wxid(h_process, wxid=""):
|
|||||||
array = array.split(b"\00")[-1]
|
array = array.split(b"\00")[-1]
|
||||||
filePath.append(array.decode('utf-8', errors='ignore'))
|
filePath.append(array.decode('utf-8', errors='ignore'))
|
||||||
filePath = max(filePath, key=filePath.count) if filePath else "None"
|
filePath = max(filePath, key=filePath.count) if filePath else "None"
|
||||||
|
CloseHandle(h_process)
|
||||||
return filePath
|
return filePath
|
||||||
|
|
||||||
|
|
||||||
@ -157,7 +174,6 @@ def get_key(pid, db_path, addr_len):
|
|||||||
:param addr_len: 地址长度
|
:param addr_len: 地址长度
|
||||||
:return: 返回key
|
:return: 返回key
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def read_key_bytes(h_process, address, address_len=8):
|
def read_key_bytes(h_process, address, address_len=8):
|
||||||
array = ctypes.create_string_buffer(address_len)
|
array = ctypes.create_string_buffer(address_len)
|
||||||
if ReadProcessMemory(h_process, void_p(address), array, address_len, 0) == 0: return "None"
|
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_type2 = "android\x00"
|
||||||
phone_type3 = "ipad\x00"
|
phone_type3 = "ipad\x00"
|
||||||
|
|
||||||
pm = pymem.Pymem(pid)
|
|
||||||
module_name = "WeChatWin.dll"
|
|
||||||
|
|
||||||
MicroMsg_path = os.path.join(db_path, "MSG", "MicroMsg.db")
|
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)
|
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)
|
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)
|
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",
|
"account": "None", "mobile": "None", "name": "None", "mail": "None",
|
||||||
"wxid": "None", "key": "None", "filePath": "None"}
|
"wxid": "None", "key": "None", "filePath": "None"}
|
||||||
try:
|
try:
|
||||||
Handle = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
|
|
||||||
bias_list = version_list.get(rd['version'], None)
|
bias_list = version_list.get(rd['version'], None)
|
||||||
|
|
||||||
|
Handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)
|
||||||
|
|
||||||
addrLen = get_exe_bit(path) // 8
|
addrLen = get_exe_bit(path) // 8
|
||||||
if not isinstance(bias_list, list) or len(bias_list) <= 4:
|
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)"
|
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['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['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['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['wxid'] = get_info_wxid(Handle)
|
||||||
|
|
||||||
rd['filePath'] = get_info_filePath(rd['wxid']) if rd['wxid'] != "None" else "None"
|
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
|
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"]),
|
isKey = verify_key(
|
||||||
os.path.join(rd['filePath'], "MSG", "MicroMsg.db")) if rd['key'] != "None" and rd[
|
bytes.fromhex(rd["key"]),
|
||||||
|
os.path.join(rd['filePath'], "MSG", "MicroMsg.db")) if rd['key'] != "None" and rd[
|
||||||
'filePath'] != "None" else False
|
'filePath'] != "None" else False
|
||||||
|
|
||||||
if rd['filePath'] != "None" and rd['key'] == "None" and not isKey:
|
if rd['filePath'] != "None" and rd['key'] == "None" and not isKey:
|
||||||
rd['key'] = get_key(rd['pid'], rd['filePath'], addrLen)
|
rd['key'] = get_key(rd['pid'], rd['filePath'], addrLen)
|
||||||
|
CloseHandle(Handle)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error = f"[-] WeChat Get Info Error:{e}"
|
error = f"[-] WeChat Get Info Error:{e}"
|
||||||
if is_logging: print(error)
|
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