Nulinspiratie
Nulinspiratie

Reputation: 181

Enforce VirtualAlloc address less than 32-bits on 64-bit machine

I need to allocate a certain space in memory, and I have been using VirtualAlloc for this. However, I have increasingly noticed that VirtualAlloc returns an address that exceeds 32 bits, though always less than 33 bits. The consequence is that when I copy data to this memory address, the computer crashes into a BSOD.

I am using 64-bit windows and a 64-bit Python. I suspect that the program that copies data to the memory is only equipped to handle 32 bits. Is there is a way to enforce VirtualAlloc to provide an address within 32 bits?

I am using Python, specifically the ctypes package to call VirtualAlloc, see code below. Executing this code multiple times changes the address, so repeatedly calling the function below will eventually result in an address below 32 bits. However, I am looking for the cause of and a fail-safe solution to the problem. Any help would be greatly appreciated.

import ctypes
mem_commit = 0x1000
page_readwrite = 0x4
size_bytes = 200000  # Allocation sizes are usually around this value

ctypes.windll.kernel32.VirtualAlloc.argtypes = [
    ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long]
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_int

addr = ctypes.windll.kernel32.VirtualAlloc(
    0, ctypes.c_long(size_bytes), mem_commit, page_readwrite)    

Note that I free up the memory afterwards using VirtualFree.

Upvotes: 1

Views: 1275

Answers (1)

CravateRouge
CravateRouge

Reputation: 140

It is possible to enforce a memory allocation with VirtualAlloc starting on a 32-bits address memory as long as there is enough free space at this range. Looking in the msdoc we have the following function signature:

LPVOID VirtualAlloc(
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

And the following description for lpAddress:

The starting address of the region to allocate [...] If this parameter is NULL, the system determines where to allocate the region.

So you can choose the address with this parameter. In your case, you specified 0 for lpAddress and it is considered as NULL value.

Furthermore, you must consider that if you choose the memory address you have to ensure that the space is free or VirtualAlloc will not give you the space.

Also, you use mem_commit without mem_reserve and the msdoc says:

Attempting to commit a specific address range by specifying MEM_COMMIT without MEM_RESERVE and a non-NULL lpAddress fails unless the entire range has already been reserved.

A better option would be to use 0x3000 (MEM_COMMIT|MEM_RESERVE) for flAllocationType

Finally, you certainly could use a 64-bits address but you set the result type of VirtualAlloc to c_int and on Windows, this is an alias for a signed 32 bits c_long. So a 64-bits address returned by VirtualAlloc would be truncated thus you would use a wrong address to copy your data.

Upvotes: 0

Related Questions