You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:45:00