python / cpython

The Python programming language
https://www.python.org
Other
63.16k stars 30.24k forks source link

Virtualalloc wrong return type #88217

Closed c3496bb9-406f-49ed-9880-bebb16aa71fb closed 3 years ago

c3496bb9-406f-49ed-9880-bebb16aa71fb commented 3 years ago
BPO 44051
Nosy @pfmoore, @tjguk, @zware, @eryksun, @zooba

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields: ```python assignee = None closed_at = created_at = labels = ['ctypes', 'type-bug', 'invalid', '3.9', 'OS-windows'] title = 'Virtualalloc wrong return type' updated_at = user = 'https://bugs.python.org/baptistecrepin' ``` bugs.python.org fields: ```python activity = actor = 'baptistecrepin' assignee = 'none' closed = True closed_date = closer = 'eryksun' components = ['Windows', 'ctypes'] creation = creator = 'baptistecrepin' dependencies = [] files = [] hgrepos = [] issue_num = 44051 keywords = [] message_count = 4.0 messages = ['393019', '393042', '393045', '393071'] nosy_count = 6.0 nosy_names = ['paul.moore', 'tim.golden', 'zach.ware', 'eryksun', 'steve.dower', 'baptistecrepin'] pr_nums = [] priority = 'normal' resolution = 'not a bug' stage = 'resolved' status = 'closed' superseder = None type = 'behavior' url = 'https://bugs.python.org/issue44051' versions = ['Python 3.9'] ```

c3496bb9-406f-49ed-9880-bebb16aa71fb commented 3 years ago

The ctypes.windll.kernel32.VirtuAlloc function return by default a ctypes.c_long but on 64bits systems memory addresses can be higher so it should be a ctypes.c_uint64 or ctypes.c_void_p.

zooba commented 3 years ago

The return type of a ctypes function is set by whoever is accessing it. If that is you, then you should do:

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

If it's not you, can you point out which code is getting this wrong? ctypes defaults to 32-bit int by default because that's what C does, and it has no knowledge of the function you're calling to do anything different.

eryksun commented 3 years ago

ctypes.windll.kernel32.VirtuAlloc function return by default a ctypes.c_long

In Windows, ctypes.c_int is an alias for ctypes.c_long, which is a signed 32-bit integer. This is the default conversion type for the integer parameters of an FFI (foreign function interface) call, as well as the result. It's up to the author of a library wrapper to define the correct function prototypes, pointer types, and aggregate struct/union types. Some common Windows types are defined/aliased in the ctypes.wintypes module, but none of the API is prototyped.

ctypes.windll.kernel32.VirtuAlloc

I suggest avoiding the global ctypes.windll loader. IMO, it's not a great idea to use a global library loader since it caches WinDLL instances, which cache function pointer instances. This make it possible for unrelated projects to interfere with each other and the main script by defining incompatible function prototypes -- particularly for common Windows API functions. It also doesn't allow passing use_last_error=True to enable the safe capturing of the thread's last error value as ctypes.get_last_error().

I recommend creating individual CDLL / WinDLL instances. For example:

    import ctypes

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

    kernel32.VirtualAlloc.restype = ctypes.c_void_p
    kernel32.VirtualAlloc.argtypes = (
        ctypes.c_void_p, # lpAddress
        ctypes.c_size_t, # dwSize
        ctypes.c_ulong,  # flAllocationType
        ctypes.c_ulong)  # flProtect

If the call fails, you can raise an OSError as follows:

    base_addr = kernel32.VirtualAlloc(None, size, alloc_type, protect)
    if base_addr is None:
        raise ctypes.WinError(ctypes.get_last_error())
c3496bb9-406f-49ed-9880-bebb16aa71fb commented 3 years ago

Thank you, I didn't know that ctypes wasn't prototyped.

I only use VirtualAlloc in combination with RtlMoveMemory and CreateThread in order to execute shellcodes for research purposes.