MacOS下用Python读取外部程序内存地址值时崩溃,求解决方案
在MacOS上用Python读取其他进程内存的问题解决
原代码的直接错误
你写的代码里,x是字符串类型的地址,但ctypes.cast需要的是整数类型的内存地址,直接传字符串会导致类型错误,这是程序崩溃的原因之一。就算把x转成整数(比如int(x, 16)),程序还是会崩溃——因为MacOS的进程隔离机制不允许直接访问其他进程的内存地址。
MacOS的核心限制
MacOS采用严格的进程隔离:
- 每个进程拥有独立的虚拟地址空间,你拿到的其他进程的内存地址,在当前Python进程的地址空间里是无效的,直接访问会触发段错误(程序崩溃)。
- 系统默认开启ASLR(地址空间布局随机化),每次程序启动后,内存地址都会随机变化,静态的地址很快会失效。
正确的实现方式
要读取其他进程的内存,必须调用MacOS的内核级API(task_for_pid和vm_read),且需要root权限。以下是可行的代码示例:
import ctypes import ctypes.util # 加载系统库 libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) libmach = ctypes.CDLL(ctypes.util.find_library('mach'), use_errno=True) # 定义Mach内核相关类型 mach_port_t = ctypes.c_uint32 vm_address_t = ctypes.c_uint64 vm_size_t = ctypes.c_uint64 kern_return_t = ctypes.c_int # 声明系统函数的参数和返回值类型 libmach.task_for_pid.argtypes = [mach_port_t, ctypes.c_int, ctypes.POINTER(mach_port_t)] libmach.task_for_pid.restype = kern_return_t libmach.vm_read.argtypes = [mach_port_t, vm_address_t, vm_size_t, ctypes.POINTER(vm_address_t), ctypes.POINTER(vm_size_t)] libmach.vm_read.restype = kern_return_t libmach.vm_deallocate.argtypes = [mach_port_t, vm_address_t, vm_size_t] libmach.vm_deallocate.restype = kern_return_t def read_process_memory(pid, address, size): task = mach_port_t() # 获取目标进程的task端口(需要root权限) ret = libmach.task_for_pid(mach_port_t(0), pid, ctypes.byref(task)) if ret != 0: raise OSError(f"获取进程端口失败,错误码: {ret}") data_ptr = vm_address_t() data_size = vm_size_t() # 读取指定地址的内存 ret = libmach.vm_read(task, vm_address_t(address), vm_size_t(size), ctypes.byref(data_ptr), ctypes.byref(data_size)) if ret != 0: raise OSError(f"读取内存失败,错误码: {ret}") # 将内存数据转为Python字节串 data = ctypes.string_at(data_ptr, data_size) # 释放内核分配的内存缓冲区 libmach.vm_deallocate(task, data_ptr, data_size) return data # 使用示例:替换为你的目标进程PID和内存地址 try: target_pid = 1234 # 目标进程的PID,可通过ps命令获取 target_address = 0x7FA09AAE85A0 # 要读取的内存地址(整数形式) read_size = 16 # 要读取的字节数 memory_content = read_process_memory(target_pid, target_address, read_size) print(f"读取到的内存数据(十六进制): {memory_content.hex()}") except OSError as e: print(f"操作失败: {e}")
注意事项
- 必须以root权限运行:执行命令时加上
sudo,比如sudo python3 your_script.py,否则task_for_pid会权限不足。 - SIP限制:如果系统开启了系统完整性保护(SIP),无法读取系统进程(如Finder、Safari)的内存,需要临时关闭SIP才能操作。
- 地址有效性:确保目标地址是目标进程当前有效的虚拟地址,ASLR会导致地址随机变化,通常需要通过逆向工具找到基地址+偏移来计算有效地址。
- 内存大小:读取的内存大小不能超出目标地址的有效范围,否则
vm_read会失败。
内容的提问来源于stack exchange,提问作者octopuswindow
相关产品推荐
相关产品推荐

