如何用Python实现Process Hacker的进程内存字符串检测自动化?
问题解决:扫描64位进程内存时的ctypes结构体错误
错误原因
MEMORY_BASIC_INFORMATION并非ctypes.wintypes内置类型,需要手动用ctypes定义该结构体,同时要适配64位进程的内存地址宽度(用c_ulonglong对应指针类型)。
修正后的代码
import psutil import ctypes import time # 定义适配64位进程的MEMORY_BASIC_INFORMATION结构体 class MEMORY_BASIC_INFORMATION(ctypes.Structure): _fields_ = [ ("BaseAddress", ctypes.c_ulonglong), ("AllocationBase", ctypes.c_ulonglong), ("AllocationProtect", ctypes.c_ulong), ("RegionSize", ctypes.c_ulonglong), ("State", ctypes.c_ulong), ("Protect", ctypes.c_ulong), ("Type", ctypes.c_ulong) ] # 核心配置 process_name = "gmod.exe" byte_pattern = b'exechack.cc' interval = 30 # 内存权限与状态常量 PAGE_READONLY = 0x02 PAGE_READWRITE = 0x04 PAGE_WRITECOPY = 0x08 PAGE_EXECUTE_READ = 0x20 PAGE_EXECUTE_READWRITE = 0x40 PAGE_EXECUTE_WRITECOPY = 0x80 MEM_COMMIT = 0x1000 while True: pid = None # 遍历进程列表查找目标PID for proc in psutil.process_iter(['pid', 'name']): if proc.info['name'].lower() == process_name.lower(): pid = proc.info['pid'] print(f"找到目标进程,PID: {pid}") break if pid: # 打开进程,获取查询内存和读取内存的权限 PROCESS_QUERY_INFORMATION = 0x0400 PROCESS_VM_READ = 0x0010 process_handle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid) if not process_handle: print("无法打开进程,权限不足或进程已终止") time.sleep(interval) continue start_address = ctypes.c_ulonglong(0) end_address = ctypes.c_ulonglong(0x7FFFFFFFFFFFFF) pattern_found = False while start_address.value < end_address.value: mbi = MEMORY_BASIC_INFORMATION() result = ctypes.windll.kernel32.VirtualQueryEx( process_handle, ctypes.c_void_p(start_address.value), ctypes.byref(mbi), ctypes.sizeof(mbi) ) if result == 0: print(f"VirtualQueryEx调用失败,错误码: {ctypes.GetLastError()}") break # 仅扫描已提交且可读取的内存区域 if (mbi.State == MEM_COMMIT) and (mbi.Protect in (PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY)): try: buffer = (ctypes.c_byte * mbi.RegionSize)() bytes_read = ctypes.c_ulonglong(0) success = ctypes.windll.kernel32.ReadProcessMemory( process_handle, ctypes.c_void_p(mbi.BaseAddress), ctypes.byref(buffer), mbi.RegionSize, ctypes.byref(bytes_read) ) if success and bytes_read.value > 0: if byte_pattern in buffer: print(f"检测到目标字符串!内存地址: 0x{mbi.BaseAddress:X}") pattern_found = True break except Exception as e: print(f"读取内存块失败: {e}") # 移动到下一个内存区域 start_address.value = mbi.BaseAddress + mbi.RegionSize if pattern_found: print("本次扫描已找到目标,等待下一轮检查") else: print("本次扫描未发现目标字符串") ctypes.windll.kernel32.CloseHandle(process_handle) else: print(f"未找到进程 {process_name}") time.sleep(interval)
关键修正说明
- 手动定义
MEMORY_BASIC_INFORMATION结构体,适配64位进程的指针宽度 - 修正
ReadProcessMemory的读取地址:原代码错误使用跳转后的start_address,改为读取当前区域的BaseAddress - 添加内存区域过滤逻辑,只扫描已提交且可读取的内存,避免无效操作和错误
- 提升进程打开权限,确保能正常查询和读取内存
- 增加错误捕获与输出,便于排查问题
内容的提问来源于stack exchange,提问作者Stanislav
相关产品推荐
相关产品推荐

