VirtualQueryEx返回异常mbi.RegionSize值的ctypes问题排查
内存扫描器中VirtualQueryEx返回异常RegionSize的问题排查
问题描述
开发内存扫描器时,使用VirtualQueryEx获取进程内存区域大小,但MEMORY_BASIC_INFORMATION的RegionSize字段返回异常庞大的数值(如135762539134976),明显不符合预期。相关代码定义及调用逻辑如下:
原代码定义
VirtualQueryEx = windll.kernel32.VirtualQueryEx VirtualQueryEx.restype = c_size_t class MEMORY_BASIC_INFORMATION(Structure): _fields_ = [ ("BaseAddress", c_ulonglong), ("AllocationBase", c_ulonglong), ("AllocationProtect", c_ulong), ("__alignment1", c_ulong), ("RegionSize", c_ulonglong), ("State", c_ulong), ("Protect", c_ulong), ("Type", c_ulong), ("__alignment2", c_ulong), ] VirtualQueryEx.argtypes = [ wintypes.HANDLE, # [in] HANDLE hProcess wintypes.LPCVOID, # [in] LPCVOID lpAdress POINTER(MEMORY_BASIC_INFORMATION), # [out] PMEMORY_BASIC_INFORMATION lpBuffer c_size_t, # [in] SIZE_T lpBuffer ]
调用代码
mbi = MEMORY_BASIC_INFORMATION() lpAdress = wintypes.LPVOID(None) # hProcess 为通过OpenProcess()获取的句柄 VirtualQueryEx( hProcess, lpAdress, byref(mbi), sizeof(mbi))
问题原因
核心问题是手动添加的对齐成员破坏了结构体的内存布局:
- Windows系统中,
MEMORY_BASIC_INFORMATION的内存对齐规则由系统自动处理,32位和64位系统下的对齐逻辑不同。 - 原代码中手动添加的
__alignment1和__alignment2成员,错误偏移了RegionSize字段的内存位置,导致读取到非目标区域的垃圾数据,从而出现异常大的数值。 - 直接使用
c_ulonglong作为指针类型不够严谨,应该用wintypes.LPVOID,它会根据系统位数自动适配32/64位指针长度。
修正方案
移除手动添加的对齐成员,让ctypes自动处理结构体对齐,并使用系统适配的类型定义结构体:
from ctypes import * from ctypes import wintypes VirtualQueryEx = windll.kernel32.VirtualQueryEx VirtualQueryEx.restype = c_size_t class MEMORY_BASIC_INFORMATION(Structure): _fields_ = [ ("BaseAddress", wintypes.LPVOID), ("AllocationBase", wintypes.LPVOID), ("AllocationProtect", wintypes.DWORD), ("RegionSize", c_size_t), ("State", wintypes.DWORD), ("Protect", wintypes.DWORD), ("Type", wintypes.DWORD), ] VirtualQueryEx.argtypes = [ wintypes.HANDLE, wintypes.LPCVOID, POINTER(MEMORY_BASIC_INFORMATION), c_size_t, ]
额外注意事项
调用OpenProcess时,需确保获取的句柄包含PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限,否则VirtualQueryEx可能调用失败或返回无效数据。
内容的提问来源于stack exchange,提问作者João P 2018
相关产品推荐
相关产品推荐

