Search code examples
chandlereadprocessmemoryopenprocess

Invalid Handle when using a single HANDLE with two calls of ReadProcessMemory


I'm just starting to learn about Windows API and I want to make a simple program which read values in a given process.

Here is my code

#include <stdio.h>
#include <Windows.h> 

void printError();

int main()
{
    int *buffer;

    // process input
    unsigned int pid = 0;
    printf("process ID : ");
    scanf("%d", &pid);
    getchar();
    HANDLE authorisation = OpenProcess(PROCESS_VM_READ, FALSE, pid);
    if(authorisation == NULL)
    {
        printf("OpenProcess Failed. GetLastError = %d", GetLastError());
        getchar();
        return EXIT_FAILURE;
    }   

    // adress memory input
    int *memoryAddress = 0x0;
    printf("memory address to read (in hexadecimal) : ");
    scanf("%p", &memoryAddress);
    getchar();
    printf("Reading from address : %p", memoryAddress);
    if(ReadProcessMemory(authorisation, (LPCVOID)memoryAddress, &buffer, 8, 
    NULL))
    {
        printf("\nptr2int = %p\n", buffer);
    }
    else
    {
        printError();    
    }

    int varInt = 0;
    // HERE IS THE PROBLEM
    // GetLastError return 6 : Invalid Handle 
    if(ReadProcessMemory(authorisation, (LPCVOID)buffer, &varInt, 
    sizeof(int), NULL))
    {
        printf("varInt = %d\n", varInt);
    }
    else
    {
        printError();
    }

    printf("Press ENTER to quit");
    getchar();

    return 0; 
}

void printError()
{
    printf("ReadProcessMemory Failed. GetLastError = %d", GetLastError());
    getchar();
    return EXIT_FAILURE;
}

However, if I create a new Handle for the second call of RPM, it's working perfectly.

I read this on MSDN:

The handle returned by the OpenProcess function can be used in any function that requires a handle to a process"

What am I doing wrong ?


Solution

  • Your issue is this:

    int *buffer;
    unsigned int pid = 0;
    
    ReadProcessMemory(authorisation, (LPCVOID)memoryAddress, &buffer, 8, NULL);
    

    Let us say, the address of buffer is 0x0 and the address of pid is 0x4 because you're compiling a 32bit application and a pointer is 4 bytes. When you call RPM you hard coded 8 bytes of size, which is overwriting pid making it invalid. You basically Buffer Overflowed yourself.

    Whenever you use ReadProcessMemory() you should always use sizeof(originalVariable) as the number of bytes argument so you never have any issue.

    If you're planning to access other process's memory often you should follow this practice:

    Use uintptr_t to store addresses and then compile your application to match the architecture of the target process. When compiling for x64 it'll be 8 bytes and on x86 it'll be 4 bytes. You could also make your own typedef if you like.

    Compiling for the same architecture of the target process is helpful in many ways, which you will find out in your journey, there are several WINAPI things that are easier to work with this way. You don't have to do this, but I highly recommend.