如何读取进程.data段?扫描notepad.exe .data段未找到目标值问题排查
核心错误点说明
- 对PE .data段的存储范围认知错误:PE .data段仅存储程序编译时就确定的全局、静态变量,记事本中用户输入的内容是运行时由编辑控件在进程堆上动态申请内存存储的,根本不在exe文件映射的静态.data段范围内,仅扫描.data段不可能找到用户输入的内容。
- 段大小计算逻辑错误:你代码中用
section_max_addr - section_min_addr计算扫描长度是pefile的错误用法,段的实际映射长度应该取min(data_section.Misc_VirtualSize, data_section.SizeOfRawData),之前的计算方式要么读不全段内容,要么触发越界读失败。 - 字符串编码匹配错误:Windows记事本的编辑控件默认使用UTF-16LE编码存储文本,你搜索的单字节
b'\x68\x65\x6c\x6c\x6f'是ASCII编码的hello,对应UTF-16LE的字节序列是b'\x68\x00\x65\x00\x6c\x00\x6c\x00\x6f\x00',编码不匹配自然搜不到结果。 - 主模块获取逻辑不可靠:直接取
list(process.list_modules())[0]作为notepad主模块的写法有兼容问题,不同Windows版本下模块枚举顺序不固定,第一个返回的模块可能是ntdll.dll等系统模块,会导致后续PE结构解析、地址计算全部错误。 - 额外说明:你用「模块基址 + 段VirtualAddress」计算段在进程内虚拟地址的逻辑是完全正确的,这部分没有问题。
修正后可运行代码
import pymem import pefile process = pymem.Pymem('Notepad.exe') # 准确匹配notepad.exe主模块 process_module = next(m for m in process.list_modules() if m.szModule.lower() == 'notepad.exe') pe = pefile.PE(process_module.filename) # 匹配.data段时去掉段名末尾的填充空字节,避免匹配失败 data_section = next(x for x in pe.sections if x.Name.rstrip(b'\x00') == b'.data') section_address = process_module.lpBaseOfDll + data_section.VirtualAddress # 正确计算可扫描的段长度 section_scan_size = min(data_section.Misc_VirtualSize, data_section.SizeOfRawData) data_section_dump = process.read_bytes(section_address, section_scan_size) ascii_hello = b'hello' utf16_hello = 'hello'.encode('utf-16le') print(f".data段ASCII hello命中结果:{ascii_hello in data_section_dump}") print(f".data段UTF16 hello命中结果:{utf16_hello in data_section_dump}") # 要找用户输入的内容,需要扫描进程所有可读写的已提交内存页 found_address = [] for memory_page in process.list_pages(): # 过滤条件:内存已提交、权限为可读写,跳过不可读的系统保留页 if memory_page.State == 0x1000 and memory_page.Protect in (0x02, 0x04, 0x20, 0x40, 0x80): try: page_data = process.read_bytes(memory_page.BaseAddress, memory_page.RegionSize) if utf16_hello in page_data: found_address.append(hex(memory_page.BaseAddress)) except Exception: # 跳过没有读取权限的页 continue print(f"全内存扫描UTF16 hello命中地址:{found_address}")
补充说明
如果要验证.data段扫描逻辑的正确性,可以自己写一个简单的C测试程序,定义全局字符串变量char test_str[] = "hello";,编译运行后再用上述逻辑扫描exe的.data段,就能正常命中目标字符串。
如果只是要获取记事本的输入内容,不需要做全内存扫描,直接向记事本的编辑控件句柄发送WM_GETTEXT消息就能直接拿到文本,效率和稳定性远高于内存扫描。
内容的提问来源于stack exchange,提问作者moti shaku
相关产品推荐
相关产品推荐

