如何在 Windows 上使用 Python 调用汇编代码

how to call assembler code with Python on Windows

this link 给出了在 Linux 平台上使用 Python 执行 asm 的一个很好的例子,但我不知道如何在 return 上调用具有 return 值的 asm func =17=],你能告诉我怎么做或者给我一个例子吗?

import ctypes
import mmap

buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)

ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
fpointer = ctypes.c_void_p.from_buffer(buf)

f = ftype(ctypes.addressof(fpointer))

buf.write(
    b'\x8b\xc7'  # mov eax, edi
    b'\x83\xc0\x01'  # add eax, 1
    b'\xc3'  # ret
)

r = f(42)
print(r)

del fpointer
buf.close()

好吧,Unix 和 Windows OS 之间有很多差异,所以这样的 low-level 东西通常附加到平台上。

让我们从汇编列表开始。

mov eax, <b>edi</b>
add eax, 1
ret

这段代码是专门为 Unix 编写的OS。为什么?因为假设第一个参数使用 edi 寄存器传递。在 Windows 系统中,第一个参数使用 ecx 传递,因此 Windows 系统的正确汇编是:

mov eax, <b>ecx</b>
add eax, 1
ret

因此,修补“已编译”程序集:

asm_function = (
    b'\x8b\xc1'  # mov eax, ecx
    b'\x83\xc0\x01'  # add eax, 1
    b'\xc3'  # ret
)

关于 mmap. I have tried to make it work, but any attempt ended up with Access Violation message. I even tried to set PAGE_EXECUTE_READWRITE protection to allocated (using mmap()) memory using VirtualProtect() but WinAPI function failed with ERROR_INVALID_PARAMETER(0x57) 错误代码。

因为我不能让它与 nmap 一起工作,为什么不向下一层并使用 WinAPI 分配内存?很简单,我们只需要调用 VirtualAlloc() to allocate memory and RtlMoveMemory() 将“预编译”程序集复制到分配的内存中即可。

我们需要修补默认 argtypes and restype of ctypes.windll.kernel32.VirtualAlloc and ctypes.windll.kernel32.RtlMoveMemory to match signatures from MSDN. We have to do this, because on x64 systems pointers is 64 bit, but default return value is 32 bit, so address returned by VirtualAlloc() won't be processed correctly. Special thanks to lifemaker, he/she pointed it out in his answer

最终代码:

import ctypes

asm_function = (
    b'\x8b\xc1'      # mov eax, ecx
    b'\x83\xc0\x01'  # add eax, 1
    b'\xc3'          # ret
)

# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc#MEM_COMMIT
MEM_COMMIT = 0x00001000
# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc#MEM_RESERVE
MEM_RESERVE = 0x00002000
# https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants#PAGE_EXECUTE_READWRITE
PAGE_EXECUTE_READWRITE = 0x40
# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
ctypes.windll.kernel32.VirtualAlloc.argtypes = (
    ctypes.c_void_p,  # LPVOID
    ctypes.c_size_t,  # SIZE_T
    ctypes.c_long,    # DWORD
    ctypes.c_long,    # DWORD
)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p  # LPVOID

memory_buffer = ctypes.windll.kernel32.VirtualAlloc(
    0,                         # lpAddress - NULL
    len(asm_function),         # dwSize
    MEM_COMMIT | MEM_RESERVE,  # flAllocationType
    PAGE_EXECUTE_READWRITE     # flProtect
)

if not memory_buffer:  # VirtualAlloc returned NULL
    print("VirtualAlloc call failed. Error code:", ctypes.GetLastError())
    exit(-1)

c_buffer = ctypes.c_char_p(asm_function)

# https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlmovememory
ctypes.windll.kernel32.RtlMoveMemory.argtypes = (
    ctypes.c_void_p,  # VOID*
    ctypes.c_void_p,  # VOID*
    ctypes.c_size_t   # SIZE_T
)

ctypes.windll.kernel32.RtlMoveMemory(
    memory_buffer,     # Destination
    c_buffer,          # Source
    len(asm_function)  # Length
)

f = ctypes.cast(
    memory_buffer,
    ctypes.CFUNCTYPE(
        ctypes.c_int,  # return type
        ctypes.c_int   # argument type
    )
)

r = f(42)
print(r)

P.S. 如果有人能回答如何使用 mmap.

我将不胜感激

你可以帮助我的国家,检查my profile info