Search code examples
cpointersmemoryprocesscheat-engine

Write data to a pointer of another program in C?


I am currently learning C, especially how memory works, and how I can write and read data used by programs. For practice, I started coding a little cheat for the game Undertale, that would constantly overwrite the health address with the maximum health value, which would make the character invincible. I searched the address of the health value with Cheat Engine, and now I have this code:

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

int main(void) {
    printf("\n");
    double MAXHEALTH = 20;

    HWND hwnd = FindWindowA(NULL, "UNDERTALE");
    if(hwnd == NULL) {
        printf("ERROR: COULD NOT FIND GAME WINDOW. PLEASE OPEN THE GAME.\n");
        return 1;
    }
    printf("[+] Undertale window found\n");
    DWORD processID;
    GetWindowThreadProcessId(hwnd, &processID);
    HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);

    if (processID == NULL) {
        printf("ERROR: COULD NOT HANDLE PROCESS.\n");
        return 1;
    }
    printf("[+] Obtained handle\n");

    while(1) {
        printf("[*] Writing max health value to health address..\n");
        WriteProcessMemory(handle, (LPVOID)0x049B2F8, &MAXHEALTH, sizeof(MAXHEALTH), 0);
        printf("[+] Done!\n");
    }
    return 0;
}

And it works. The bad thing is, when you close the game and re-open it, all the addresses are different... That's not very efficient. So I wanted to try using Cheat Engine to find the base address of the health value. I did multiple pointer scans, and narrowed the results to approximately 150 addresses, pointing to the health address. I tried selecting one randomly, closed the game, re-opened it, and it worked: I was able to modify the health value by using the pointer I found.

So I thought I'd use it in my code. Under "Base Address" in the pointer scan window, it showed "UNDERTALE.exe"+059E4F8. I tried replacing the address in my code with the address of the pointer (I typed (LPVOID)0x059E4F8), but it didn't work. The output said "[+] Done!" repeatedly but the health value wasn't changing, while it worked in Cheat Engine... I'm new to the whole memory management thing, what did I do wrong? Is what I want to do even possible?

I hope my explanation of everything I did was clear enough, if not, please let me know.

Thank you.


Solution

  • Alright, I found how to do what I wanted to do. I finally got (maybe it was obvious but hey) that this first pointer that I found was just the first of a chain of 5 pointers, that I had to follow to arrive to the health address. So I read the value contained by each pointer to find the next, until eventually reaching to the correct health address. Now my cheat works everytime I run the game :) .

    My code (i know it's not optimized, I could've used a for loop, but it was just for testing purpose.):

    #include <stdio.h>
    #include <Windows.h>
    
    int main(void) {
        printf("\n");
        LPVOID readPointer;
        double health;
        int pointerval = 0x00400000 + 0x0059E470 ;  //UNDERTALE.exe base address + first offset to get to first pointer
    
        HWND hwnd = FindWindowA(NULL, "UNDERTALE");
        if(hwnd == NULL) {
            printf("ERROR: COULD NOT FIND GAME WINDOW. PLEASE OPEN THE GAME.\n");
            return 1;
        }
        printf("[+] Undertale window found\n");
        DWORD procID;
        GetWindowThreadProcessId(hwnd, &procID);
        HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
    
        if (procID == NULL) {
            printf("ERROR: COULD NOT OBTAIN HANDLE FOR PROCESS.\n");
            return 1;
        }
        printf("[+] Obtained handle\n");
    
    
        printf("[*] Following pointer chain...\n");
    
    
        printf("[*] Reading pointer 1 value from memory at address 0x%p...\n", pointerval);
        ReadProcessMemory(handle, (PVOID*)pointerval, &readPointer, sizeof(readPointer), 0);
        pointerval = (int*)readPointer;
        printf("Pointer 1 value: 0x%p\n", pointerval);
        printf("Applying offset 0x98..\n\n");
        pointerval += 0x98;
    
        printf("[*] Reading pointer 2 value from memory at address 0x%p...\n", pointerval);
        ReadProcessMemory(handle, (PVOID*)pointerval, &readPointer, sizeof(readPointer), 0);
        pointerval = (int*)readPointer;
        printf("Pointer 2 value: 0x%p\n", pointerval);
        printf("Applying offset 0xC..\n\n");
        pointerval += 0xC;
    
        printf("[*] Reading pointer 3 value from memory at address 0x%p...\n", pointerval);
        ReadProcessMemory(handle, (PVOID*)pointerval, &readPointer, sizeof(readPointer), 0);
        pointerval = (int*)readPointer;
        printf("Pointer 3 value: 0x%p\n", pointerval);
        printf("Applying offset 0x4..\n\n");
        pointerval += 0x4;
    
        printf("[*] Reading pointer 4 value from memory at address 0x%p...\n", pointerval);
        ReadProcessMemory(handle, (PVOID*)pointerval, &readPointer, sizeof(readPointer), 0);
        pointerval = (int*)readPointer;
        printf("Pointer 4 value: 0x%p\n", pointerval);
        printf("Applying offset 0x1D0..\n\n");
        pointerval += 0x1D0;
    
    
        printf("[+] Pointer chain over: health address is 0x%p.\n\n",pointerval);
    
        printf("[*] Reading actual health value\n");
        ReadProcessMemory(handle, (PVOID*)pointerval, &health, sizeof(health), 0);
        printf("[+] Actual health value: %f\n\n",health);
    
        printf("[*] Writing health value to health address repeatedly..\n");
        printf("[+] God mode activated ;)\n");
        while(1) {
            WriteProcessMemory(handle, (LPVOID)pointerval, &health, sizeof(health), 0);
        }
    
        return 0;
    }