VirtualAlloc failed - virtualalloc

I want to set my own ImageBase to 0x2000000, and then read another EXE program to its ImageBase, of course, usually 0x400000, but when I use VirtualAlloc to apply for space, it always fails, GetLastError is 0x1e7 (487), Of course, I also tried to load only the ntdll.dll program, the same failure, how to solve it?
Part of the code below:
DWORD dwImageBase = pNtHeader->OptionalHeader.ImageBase;
LPVOID lpImageBuff = ::VirtualAlloc((PVOID)(dwImageBase), pNtHeader->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if (NULL == lpImageBuff)
{
::MessageBox(NULL,_T("Application for ImageBase failed!!!"),_T("ERROR"),MB_ICONSTOP | MB_OK);
return;
}

0x1e7 is ERROR_INVALID_ADDRESS
The address where you're trying to reserve memory is already in use - by your own image.
See the SysInternals tool VMmap.
The usual way to use VirtualAlloc for MEM_RESERVE, or MEM_RESERVE | MEM_COMMIT , is to use 0 for its first argument. This allows the API to pick a free region of virtual address space.

Related

ImageBaseAddress in PEB is wrong

I'm currently trying to retrieve the Image Base Address of a suspended 32-bits process.
I successfully retrieved the PEB VA by using (*CTX).Ebx - 0x1000 (where CTX is the CONTEXT structure retrieved with GetThreadContext()), it's in correlation with the data I got from some process analysis tools.
The problem is that the field ImageBaseAddress at offset 0x08 is equal to 0xffffffff.
I verified and all the other fields are okay, if for example I create the process in debug mode the BeingDebugged byte is set to 1 etc...
And if I look with some tools where the Image of the PE is loaded I see that it's at 0x880000, unfortunately that data isn't present in the PEB.
So I basically tried to create a "normal" process that isn't suspended but I have the same problem.
All the fiels of the PEB are fine, the process too, there's just that 32-bits integer at offset 0x08 that is equal to 0xffffffff for some mysterious reasons.
(P.S.: I know that the PEB isn't documented and that it is not a great idea to depend of it as it's fields might change in the future but I really need to get the Image Base Address of a suspended process from it's PEB).
Thanks.
Use NtQueryInformationProcess with the ProcessBasicInformation, the resulting PROCESS_BASIC_INFORMATION structure will contain the correct peb address.
typedef NTSTATUS(__stdcall* tNtQueryInformationProcess)
(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
PEB GetPEBExternal(HANDLE hProc)
{
PROCESS_BASIC_INFORMATION pbi;
PEB peb = { 0 };
tNtQueryInformationProcess NtQueryInformationProcess =
(tNtQueryInformationProcess)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
NTSTATUS status = NtQueryInformationProcess(hProc, ProcessBasicInformation, &pbi, sizeof(pbi), 0);
if (NT_SUCCESS(status))
{
ReadProcessMemory(hProc, pbi.PebBaseAddress, &peb, sizeof(peb), 0);
}
return peb;
}
PEB peb = GetPEBExternal(hProc);
std::cout << "0x" << std::hex << peb.ImageBaseAddress << std::endl;
Use the PEB definition from x64dbg source code, it's the best source for undocumented structures in my experience.

why does VirtualAlloc fail for lpAddress greater than 0x6ffffffffff

I wanted to try seeing the limits on how "far" i can point to in 64 bit C program by trying to map very far addresses, as close to 64 bit as possible into valid memory by using VirtualAlloc.
I managed to get to 0x6ffffffffff which is a 42 bit address, but any number above that results in failure to allocate, with error code 0x57(The parameter is incorrect).
This is my code:
#include <Windows.h>
#include <stdio.h>
int main(int argc, char **argv)
{
LPVOID mem;
WCHAR message[] = L"Hello, World!";
mem = VirtualAlloc (
(LPVOID)0x00006ffffffffff,
4096,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (mem == 0) {
wprintf(L"%x.\n", GetLastError());
system("pause");
exit(-1);
}
memcpy(mem, message, sizeof(message));
wprintf(L"[%llx] -> %ls\n", mem, mem);
system("pause");
return 0;
}
Why can't I VirtualAlloc above 0x6ffffffffff?
The explanation is that the address you request is outside of the available range. Although there is a theoretical 64 bit range of available addresses, in practise not all of that range is available to a user mode application. You can find the allowable range by calling GetSystemInfo and inspecting the values of lpMinimumApplicationAddress and lpMaximumApplicationAddress. If you attempt to reserve an address outside of this range, the call to VirtualAlloc will fail and the error code is set to ERROR_INVALID_PARAMETER.
Note that these minimum and maximum values are not precise. You will start observing ERROR_INVALID_PARAMETER when you get close to the limits.

MapViewOfFile() no longer works after process hits the 2GB limit

MapViewOfFile() works without any problem if our process has not hit the 2GB limit yet. However if the process hits the limit then MapViewOfFile() no longer works even if some or all of the memory is deallocated. GetLastError() returns 8, which means ERROR_NOT_ENOUGH_MEMORY, Not enough storage is available to process this command. Here is a small program showing the problem:
#include <Windows.h>
#include <cstdio>
#include <vector>
const int sizeOfTheFileMappingObject = 20;
const int numberOfBytesToMap = sizeOfTheFileMappingObject;
const char* fileMappingObjectName = "Global\\QWERTY";
void Allocate2GBMemoryWithMalloc(std::vector<void*>* addresses)
{
const size_t sizeOfMemAllocatedAtOnce = 32 * 1024;
for (;;) {
void* address = malloc(sizeOfMemAllocatedAtOnce);
if (address != NULL) {
addresses->push_back(address);
}
else {
printf("The %dth malloc() returned NULL. Allocated memory: %d MB\n",
addresses->size() + 1,
(addresses->size() * sizeOfMemAllocatedAtOnce) / (1024 * 1024));
break;
}
}
}
void DeallocateMemoryWithFree(std::vector<void*>* addresses)
{
std::vector<void*>::iterator current = addresses->begin();
std::vector<void*>::iterator end = addresses->end();
for (; current != end; ++current) {
free(*current);
}
addresses->clear();
printf("Memory is deallocated.\n");
}
void TryToMapViewOfFile()
{
HANDLE fileMapping = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE,
fileMappingObjectName);
if (fileMapping == NULL) {
printf("OpenFileMapping() failed. LastError: %d\n", GetLastError());
return;
}
LPVOID mappedView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0,
numberOfBytesToMap);
if (mappedView == NULL) {
printf("MapViewOfFile() failed. LastError: %d\n", GetLastError());
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return;
}
if (!UnmapViewOfFile(mappedView)) {
printf("UnmapViewOfFile() failed. LastError: %d\n", GetLastError());
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return;
}
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
return;
}
printf("MapViewOfFile() succeeded.\n");
}
int main(int argc, char* argv[])
{
HANDLE fileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeOfTheFileMappingObject, fileMappingObjectName);
if (fileMapping == NULL) {
printf("CreateFileMapping() failed. LastError: %d\n", GetLastError());
return -1;
}
TryToMapViewOfFile();
std::vector<void*> addresses;
Allocate2GBMemoryWithMalloc(&addresses);
TryToMapViewOfFile();
DeallocateMemoryWithFree(&addresses);
TryToMapViewOfFile();
Allocate2GBMemoryWithMalloc(&addresses);
DeallocateMemoryWithFree(&addresses);
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return 0;
}
The output of the program:
MapViewOfFile() succeeded.
The 65126th malloc() returned NULL. Allocated memory: 2035 MB
MapViewOfFile() failed. LastError: 8
Memory is deallocated.
MapViewOfFile() failed. LastError: 8
The 64783th malloc() returned NULL. Allocated memory: 2024 MB
Memory is deallocated.
As you can see MapViewOfFile() fails with 8 even after releasing all memory that was allocated. Even though MapViewOfFile() reports ERROR_NOT_ENOUGH_MEMORY we can call malloc() successfully.
We ran this example program on Windows7,32bit; Windows 8.1,32bit and Windows Server 2008 R2,64bit and the results were the same.
So the question is: Why does MapViewOfFile() fail with ERROR_NOT_ENOUGH_MEMORY after the process hits the 2GB limit?
Why MapViewOfFile fails
As IInspectable's comment explains freeing memory allocated with malloc doesn't make it available for use with MapViewOfFile. A 32-bit processes under Windows has a 4 GB virtual address space and only the first 2 GB of it is available for the application. (An exception would be a large address aware program, which increases this to 3 GB under suitably configured 32-bit kernels and to 4 GB under 64-bit kernels.) Everything in your program's memory must have a location somewhere in this first 2 GB of virtual address space. That includes the executable itself, any DLLs used by the program, any data you have in memory, whether allocated statically, on the stack or dynamically (eg. with malloc), and of course any file you map into memory with MapViewOfFile.
When your program first starts out the Visual C/C++ runtime creates a small heap for dynamic allocations for functions like malloc and operator new. As necessary the runtime increases the size of the heap in memory, and as it does so it uses up more virtual address space. Unfortunately it never shrinks the size of the heap. When you free a large block of memory the runtime only decommits the memory used. This makes the RAM used by the freed memory available for use, but virtual address space taken up by the freed memory remains allocated as part of the heap.
As mentioned previously a file mapped into memory by MapViewOfFile also takes up virtual address space. If the heap (plus your program, DLLs, and everything else) are using up the all virtual address space then there's no room to map files.
A possible solution: don't use malloc
An easy way to avoid the heap from growing to fill all of the virtual address space is to not to use the Visual C/C++ runtime to allocate large (at least 64k) blocks of memory. Instead allocate and free memory from Windows directly using VirtualAlloc(..., MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE) and VirtualFree(..., MEM_RELEASE). The later function releases both the RAM used by the region and virtual address space taken up by it, making it available for use with MapViewOfFile.
But...
You can still run into another problem, where MapViewOfFile can still fail even though the size of view is smaller, sometimes even much smaller, than the total amount free virtual address space. This is because the view needs to be mapped into a contiguous region of virtual address space. If the virtual address space becomes fragmented. the largest contiguous region of unreserved virtual address space can up being relatively small. Even when your program first starts up, before you have had a chance to do any dynamic allocations, the virtual address space can be somewhat fragmented because of DLLs loaded at various addresses. If you have a long lived program that does a lot of allocations and deallocations with VirtualAlloc and VirtualFree, you can end up with a very fragmented virtual address space. If you encounter this problem you'll have to change your pattern of allocations, maybe even implement your own heap allocator.

Unable to write to process memory

I am trying to fix a problem in code I am not familiar with. I have traced it down to call to WriteProcessMemory always failing with ERROR_INVALID_ADDRESS. I have no idea why it fails.I tried to check if my process has the required access to write to its child process using VirtualQUery and it does. Can anyone shed some light on this? The code path is extremely convoluted so I have skipped a lot of it. Please let me know if left out any info.
CreateProcessAsUserW(hToken, exe, cmd_line,
NULL, // No security attribute.
NULL, // No thread attribute.
false, // do not inherit handles
CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | EXTENDED_STARTUPINFO_PRESENT | CREATE_BREAKAWAY_FROM_JOB, // start suspended, extended startup info, break out of job
NULL, // Use the environment of the caller
NULL, // Use current directory of the caller.
&si,
&pi);
/*
....lots of work here
*/
void* address = {...};
void* var = address; // note this line
SIZE_T written;
if(!WriteProcessMemory( pi.handle,
var, address, // not completely sure what it is doing here - writing contents of address to address of var?
size, &written))
{
DWORD error = GetLastError(); // ERROR_INVALID_ADDRESS
MEMORY_BASIC_INFORMATION buffer;
SIZE_T num = VirtualQuery(address,&buffer,sizeof(MEMORY_BASIC_INFORMATION));
if(num > 0)
{
DWORD access = buffer.AllocationProtect; // PAGE_EXECUTE_WRITECOPY
DWORD state = buffer.State; // MEM_COMMIT
DWORD type = buffer.Type;
}
}
This is a 32-bit process running on 64-bit Win7.
You're performing a local VirtualQuery before trying to write into another process, whose address space may be wildly different.
If you want to be sure to have a valid pointer in that process's adress space, either you find where that process puts what interests you (good luck with ASLR), or you allocate some memory for you within that process (with, say VirtualAllocEx()).
Note: If you actually want shared memory, you should use CreateFileMapping(INVALID_HANDLE_VALUE) instead.

When using Windows threads, can I specify a buffer to use for a thread's stack, similar to pthread_attr_setstack()?

pthreads allows the user to provide a chunk of memory to use for a thread stack:
size_t stack_size = 1024*1024*4;
void *stack = malloc( stack_size );
pthread_attr_t attributes;
pthread_attr_init( &attributes );
pthread_attr_setstack( &attributes, stack, stack_size );
pthread_t thread_id;
pthread_create( &thread_id, &attributes, worker_function, NULL
Do Windows threads provide similar functionality? The second parameter to CreateThread allows one to specify the minimum size of the stack, but I can't see a way to specify the address of a buffer to use.
You can not specify memory for stack as Jerry Coffin mention in comment, all you can specify is size of stack as second parameter to CreateThread call.
More info here.

Resources