Search code examples
windowsreadprocessmemorycheat-engine

how do i use a memory address from cheat engine with ReadProcessMemory?


im trying to make an application that monitors the speed of the character in GTAV, iv found the address of the variable with cheat engine: https://i.sstatic.net/klyYV.png

and i made a function to open a handle to the game process:

/*returns INVALID_HANDLE_VALUE on failure*/ 
HANDLE openProcessByName(const char* name, DWORD access){
    PROCESSENTRY32 process;
    process.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if(Process32First(snapshot, &process) == FALSE){//failure
        CloseHandle(snapshot);
        return INVALID_HANDLE_VALUE;
    }

    while(Process32Next(snapshot, &process) == TRUE){//skips first but thats system anyway
        if(_stricmp(process.szExeFile, name) == 0){//found it
            HANDLE processHandle = OpenProcess(access, FALSE, process.th32ProcessID);
            CloseHandle(snapshot);
            return processHandle;
        }
    }

    CloseHandle(snapshot);
    return INVALID_HANDLE_VALUE;//reached if the process is not found and its handle not returned above
}

in main i get the handle and try to read the memory location like so:

#include <tlhelp32.h>
#include <iostream>

HANDLE openProcessByName(const char* name, DWORD access);

int main(){
    HANDLE processHandle = openProcessByName("GTA5.exe", PROCESS_VM_READ);
    if (processHandle == INVALID_HANDLE_VALUE){
        std::cout << "invalid handle value" << std::endl;
        return 0;
    }

    float speed = 0.00;
    if (ReadProcessMemory(processHandle, (LPCVOID)0x7FF65EEA3940, &speed, (DWORD)sizeof(speed), NULL) == 0){
        std::cout << "failed to read value" << std::endl;
        std::cout << GetLastError() << std::endl;//return 299
    }else{
        std::cout << speed << std::endl;
    }

    CloseHandle(processHandle);
    return 0;
}

but it fails and prints "failed to read value". im assuming this has something to do with an address offset, iv been looking it up but i don't really get what people are talking about. btw the memory location is not static and changes when the game is restarted but i wanted to at least get it working with the actual memory address before i tried to find a way to get it dynamically.

so how do i find the actual memory address to use with the ReadProcessMemory function based on the address displayed in cheat engine.


Solution

  • This is how I ended up doing it (code has been simplified and not tested). The address needed to be offset by the base address of the main module of the game process.

    void read() {
        MODULEENTRY32 mainModule = {0};
        HANDLE process = openProcessByName(PROCESS_NAME, PROCESS_VM_READ, &mainModule);
    
        float rawSpeed = 0.00f;
        ReadProcessMemory(process, (LPCVOID)(mainModule.modBaseAddr + MEMORY_ADDRESS), &rawSpeed, sizeof(rawSpeed), NULL);
    }
    
    //returns INVALID_HANDLE_VALUE on failure
    HANDLE openProcessByName(const char* name, DWORD access, MODULEENTRY32* mainModule) {
        PROCESSENTRY32 process;
        process.dwSize = sizeof(PROCESSENTRY32);
    
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    
        if (Process32First(snapshot, &process) == FALSE) {//failure
            CloseHandle(snapshot);
            return INVALID_HANDLE_VALUE;
        }
    
        while (Process32Next(snapshot, &process) == TRUE) {//skips first but thats system anyway
            if (_stricmp(process.szExeFile, name) == 0) {//found it
    
                HANDLE modSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process.th32ProcessID);
                mainModule->dwSize = sizeof(MODULEENTRY32);
                Module32First(modSnapshot, mainModule);
    
                HANDLE processHandle = OpenProcess(access, FALSE, process.th32ProcessID);
    
                CloseHandle(modSnapshot);
                CloseHandle(snapshot);
                return processHandle;
            }
        }
    
        CloseHandle(snapshot);
        return INVALID_HANDLE_VALUE;//reached if the process is not found and its handle not returned above
    }