我正在为我的逆向工程课程寻找一个可以在ntdll.dll个Windows DLL中转换为jmp esp的小工具,但我面临一些技术问题.

我写了以下脚本:

import ctypes
from ctypes import wintypes, WinDLL


def GetModuleHandle(module):
    kernel32 = WinDLL('kernel32', use_last_error=True)
    kernel32.GetModuleHandleW.restype = wintypes.HMODULE
    kernel32.GetModuleHandleW.argtypes = [wintypes.LPCWSTR]
    hMod = kernel32.GetModuleHandleW(module)

    return hMod


def find_bytes_in_module(module_name: str, module_size: int, search_bytes: bytes) -> int:
    # Get the handle of the module
    hModule = GetModuleHandle(module_name)

    # Read the contents of the module into a ctypes array and convert to a bytes array
    ctypes_arr = ctypes.c_ubyte * module_size
    module_data = bytes(ctypes_arr.from_address(hModule))

    # Search for the wanted bytes in the module data
    index = module_data.find(search_bytes)

    return hModule + index


def main():
    module_name = 'ntdll.dll'
    module_size = 2 * 1024 * 1024  # ntdll.dll on my system is under 2 MB
    search_bytes = b'\xff\xe4'
    addr = find_bytes_in_module(module_name, module_size, search_bytes)
    print(f'`jmp esp` gadget found inside {module_name} at the absolute address: {hex(addr)}')

    return 0


if __name__ == '__main__':
    main()

当我使用64位IPython终端运行find_bytes_in_module内的命令时,以下代码可以工作,但由于我的课程限制,我只允许使用32位的Python解释器.

当我try 使用任何其他发行版本的python(我甚至try 了一个普通的64位python解释器)来运行这个脚本时,它在第module_data = bytes(ctypes_arr.from_address(hModule))行崩溃.尤其是在try 将ctype数组转换为字节数组时.

退出代码是-1073741819.我try 使用管理员权限运行终端,但得到了相同的结果.

有谁知道我该怎么解决这个问题吗?也许这甚至不是我应该走的方向(我正在试图找到从DLL开始到小工具的偏移量) 我使用的是64位的Windows10发行版,以防万一(希望它不会有问题).

编辑:我在Google上发现这个错误代码意味着访问冲突异常发生在程序的主线程上下文中,没有被程序的代码捕获,从而导致程序的main()/WinMain()入口点过早退出,终止了进程.然而,我不知道我应该采取什么不同的方式来防止这种情况发生,为什么当我在IPython中交互地做同样的事情时,它没有发生……

推荐答案

不知道为什么,我也try 了当前的模块大小,因为你传递的大小比我在最新的Windows10上获得的模块大小略大,但我也遇到了相同的解释器崩溃……

ReadProcessMemory代替,很容易就解决了这个问题.代码非常简单:

显然,只要将模块加载到进程地址空间中,这就可以正常工作.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import ctypes
import ctypes.wintypes as wt

# Windows Structs


class MODULEINFO(ctypes.Structure):
    _fields_ = (
        ('lpBaseOfDll', ctypes.c_void_p),
        ('SizeOfImage', ctypes.c_uint32),
        ('EntryPoint', ctypes.c_void_p)
    )

# Windows API


kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
GetModuleHandle = kernel32.GetModuleHandleW
GetModuleHandle.restype = wt.HMODULE
GetModuleHandle.argtypes = (wt.LPCWSTR, )

ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.argtypes = (
    ctypes.c_void_p,  # HANDLE hProcess
    ctypes.c_void_p,  # LPCVOID lpBaseAddress
    ctypes.c_void_p,  # LPVOID  lpBuffer
    ctypes.c_size_t,  # SIZE_T  nSize
    ctypes.POINTER(ctypes.c_size_t)  # SIZE_T  *lpNumberOfBytesRead
)
ReadProcessMemory.restype = wt.BOOL

psapi = ctypes.WinDLL("psapi", use_last_error=True)
GetModuleInformation = psapi.GetModuleInformation
GetModuleInformation.restype = wt.BOOL
GetModuleInformation.argtypes = (
    ctypes.c_void_p,  # HANDLE hProcess
    ctypes.c_void_p,  # HMODULE hModule
    ctypes.POINTER(MODULEINFO),  # LPMODULEINFO lpModinfo
    ctypes.c_uint32,  # cb
)


def get_module_info(h_module) -> MODULEINFO:
    """Get Module information for a module loaded into the python interpreter address space.

    Args:
        h_module: The HMODULE (module base address) to the module for which to get the information.

    Returns:
        An instance of the MODULEINFO structure.
    """
    h_current_proc = ctypes.c_void_p(-1)  # pseudo handle to current process.
    module_info = MODULEINFO()
    ret_val = GetModuleInformation(h_current_proc, h_module, ctypes.byref(module_info), ctypes.sizeof(module_info))
    if ret_val == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    return module_info


def read_module(base_addr: int, size: int) -> bytes:
    """Read the entirety of a module loaded in the Python interpreter.

    Args:
        base_addr: base address of the module to read.
        size: Size of the module.

    Returns:
        A bytes instance containing the bytes read from the module.
    """
    h_current_proc = ctypes.c_void_p(-1)  # pseudo handle to current process.

    buffer = ctypes.create_string_buffer(b'', size)
    nobr = ctypes.c_size_t(0)
    ret_val = ReadProcessMemory(h_current_proc, base_addr, buffer, size, ctypes.byref(nobr))
    if not ret_val and ctypes.get_last_error() != 299:  # ERROR_PARTIAL_COPY
        raise ctypes.WinError()
    return buffer.raw[:nobr.value]


def find_bytes_in_module(module_name: str, search_bytes: bytes) -> int:
    # Get the handle of the module
    h_module = GetModuleHandle(module_name)
    if h_module == 0:
        raise ctypes.WinError(ctypes.get_last_error())
    module_info = get_module_info(h_module)
    print(f"{module_name}: Base: {module_info.lpBaseOfDll:#016x}; Image Size: {module_info.SizeOfImage:#016x}")

    # Read the contents of the module into a ctypes array and convert to a bytes array
    module_data = read_module(h_module, module_info.SizeOfImage)

    # Search for the wanted bytes in the module data
    index = module_data.find(search_bytes)
    if index == -1:
        # oops, pattern not found...
        return -1

    return h_module + index


def main():
    module_name = 'ntdll.dll'
    search_bytes = b'\xff\xe4'

    # no need to load ntdll, it's already in the process address space.
    addr = find_bytes_in_module(module_name, search_bytes)
    if addr < 0:
        print("Could not find the pattern in the module.")
        return 0

    print(f'`jmp esp` gadget found inside {module_name} at the absolute address: {addr:#016x}')

    return 0


if __name__ == '__main__':
    main()

Python相关问答推荐

在Pandas 日历中插入一行

如何在Python中并行化以下搜索?

使用groupby Pandas的一些操作

如何获取numpy数组的特定索引值?

如何获得每个组的时间戳差异?

python中字符串的条件替换

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

Plotly Dash Creating Interactive Graph下拉列表

为什么\b在这个正则表达式中不解释为反斜杠

使用Python查找、替换和调整PDF中的图像'

基于行条件计算(pandas)

如何排除prefecture_related中查询集为空的实例?

为什么常规操作不以其就地对应操作为基础?

如何获取Python synsets列表的第一个内容?

根据客户端是否正在传输响应来更改基于Flask的API的行为

504未连接IB API TWS错误—即使API连接显示已接受''

Regex用于匹配Python中逗号分隔的AWS区域

python3中np. divide(x,y)和x/y有什么区别?'

PYTHON中的pd.wide_to_long比较慢

try 在单个WITH_COLUMNS_SEQ操作中链接表达式时,使用Polars数据帧时出现ComputeError