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

32位Python查找ntdll.dll中jmp esp gadget遇访问冲突求助

解决32位Python访问ntdll.dll内存崩溃及获取Gadget偏移的问题

问题根源

64位Windows系统中,32位进程运行在WoW64(Windows on Windows 64)兼容层下,默认加载的ntdll.dll是64位版本,其内存地址超出32位进程的4GB地址空间范围。直接读取该模块内存会触发访问冲突(退出码-1073741819即0xC0000005,内存访问违规)。


解决内存崩溃的方法

1. 加载32位版本的ntdll.dll

64位Windows的32位系统库存放在C:\Windows\SysWOW64目录下,修改脚本加载该路径下的ntdll.dll,确保模块地址落在32位进程的地址空间内。

2. 仅读取模块的代码段(而非全量内存)

直接读取整个模块内存容易触发权限或范围问题,正确做法是解析PE头,仅读取存放指令的.text段(代码段)内存。


完整修正脚本示例

import ctypes
from ctypes import wintypes

# 定义Windows API函数
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

GetModuleHandleW = kernel32.GetModuleHandleW
GetModuleHandleW.argtypes = [wintypes.LPCWSTR]
GetModuleHandleW.restype = wintypes.HMODULE

ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.argtypes = [wintypes.HANDLE, wintypes.LPCVOID, wintypes.LPVOID, wintypes.SIZE_T, wintypes.PSIZE_T]
ReadProcessMemory.restype = wintypes.BOOL

# 加载32位ntdll.dll
hModule = GetModuleHandleW(r'C:\Windows\SysWOW64\ntdll.dll')
if not hModule:
    raise ctypes.WinError(ctypes.get_last_error())

# 读取DOS头,定位NT头
dos_header = wintypes.IMAGE_DOS_HEADER()
bytes_read = wintypes.SIZE_T()
ReadProcessMemory(wintypes.HANDLE(-1), hModule, ctypes.byref(dos_header), ctypes.sizeof(dos_header), ctypes.byref(bytes_read))

nt_headers_addr = hModule + dos_header.e_lfanew
nt_headers = wintypes.IMAGE_NT_HEADERS()
ReadProcessMemory(wintypes.HANDLE(-1), nt_headers_addr, ctypes.byref(nt_headers), ctypes.sizeof(nt_headers), ctypes.byref(bytes_read))

# 获取代码段(.text)的虚拟地址和大小
text_section = nt_headers.OptionalHeader.DataDirectory[0]
text_virtual_addr = text_section.VirtualAddress
text_size = text_section.Size
text_mem_addr = hModule + text_virtual_addr

# 读取代码段内存
text_data = (ctypes.c_ubyte * text_size)()
ReadProcessMemory(wintypes.HANDLE(-1), text_mem_addr, text_data, text_size, ctypes.byref(bytes_read))

# 查找jmp esp的机器码(0xFF E4)
jmp_esp_opcode = b'\xFF\xE4'
offset_in_text = 0
while offset_in_text <= len(text_data) - 2:
    if bytes(text_data[offset_in_text:offset_in_text+2]) == jmp_esp_opcode:
        # 计算相对于DLL基地址的偏移
        gadget_offset = text_virtual_addr + offset_in_text
        gadget_full_addr = text_mem_addr + offset_in_text
        print(f"找到jmp esp Gadget: 地址 = 0x{gadget_full_addr:X}, 相对于DLL基地址的偏移 = 0x{gadget_offset:X}")
    offset_in_text += 1

获取Gadget偏移的逻辑

Gadget相对于DLL起始位置的偏移计算公式为:

gadget偏移 = (Gadget内存地址 - DLL基地址)

在脚本中,我们通过代码段的虚拟地址加上其内部偏移,直接得到相对于DLL基地址的偏移,无需额外计算。


额外说明

如果需要查找64位ntdll.dll的Gadget(如jmp rsp,机器码同样为0xFF E4),32位Python无法直接访问内存中的64位模块,但可以直接读取磁盘上的C:\Windows\System32\ntdll.dll文件,解析PE文件结构后在文件内容中查找对应机器码,计算虚拟偏移(需考虑PE节的对齐规则)。

内容的提问来源于stack exchange,提问作者Tal Afek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:22:39