Executing assembly code in memory using python modules ctypes and mmap
Asked Answered
W

1

6

This code works on linux and prints 43, how could I code a script with similar functionality to be run on windows without errors?

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()

When I change the line:

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

to

buf = mmap.mmap(-1, mmap.PAGESIZE, tagname=None, access=mmap.ACCESS_DEFAULT)

the python interpreter outputs the error:

OSError: exception: access violation writing 0x00EC0000

Does anyone know how to correct this code so it runs properly? The desired output should be "43".

Warwickshire answered 14/11, 2019 at 7:41 Comment(2)
Being able to execute data in memory is a pretty big security hole, and Window unfortunately have a history of much to many holes, which it have closed over the years. This is probably one such a hole that it closed. You most likely have to use Windows native calls to be able to mark memory pages as executable.Monopode
@Someprogrammerdude, Python's mmap module predates the addition of the FILE_MAP_EXECUTE and PAGE_EXECUTE_* constants in Windows XP SP2. However, Python 3.5+ only supports Vista and later, so someone could submit a patch to extend the access parameter to support execute access. There's nothing preventing this in principle. Note that we already have support for this kind of operation in ctypes in order to allow calling Python callbacks from C, which requires storing a small stub function assembled in executable memory that sets up the call into the interpreter.Vindicate
S
1

You can use VirtualAlloc or VirtualProtect and mark as PAGE_EXECUTE_READWRITE.

import ctypes

asm = """
55                      push   %rbp
48 89 e5                mov    %rsp,%rbp
48 81 ec 00 00 00 00    sub    $0x0,%rsp
48 89 4d 10             mov    %rcx,0x10(%rbp)
8b 45 10                mov    0x10(%rbp),%eax
83 c0 01                add    $0x1,%eax
f3 0f 2a c0             cvtsi2ss %eax,%xmm0
c9                      leave
c3                      ret
""".split('\n')

code = []
for line in asm:
    code.extend(int(x, 16) for x in line[:20].split())

byte_array = bytes(code)

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
PAGE_EXECUTE_READWRITE = 0x40

VirtualAlloc = kernel32.VirtualAlloc
VirtualAlloc.restype = ctypes.c_void_p

buf = VirtualAlloc(
        None,
        len(byte_array),
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE)

ctypes.memmove(buf, byte_array, len(byte_array))

functype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)

increment_by_one = functype(buf)
result = increment_by_one(42)
print(result)


Singletree answered 20/3, 2023 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.