1

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.

Nim
  • 158
  • 2
  • 14
  • Now learn about [virtual memory](https://en.wikipedia.org/wiki/Virtual_memory), your computer is not an 8-bit gaming console. – unwind Apr 09 '18 at 20:01
  • @unwind Alright.. Please correct me if I'm wrong: "UNDERTALE.exe" represents the entry point of the program in virtual memory, and "UNDERTALE.exe"+059E4F8 is the actual address of the pointer? There are also 4 offsets, that when added to the pointer address makes the address of the actual value the pointer points to? So for my code to work, I'd need to use the entry point + 059E4F8 + the offsets to find the address of the value I want to write to? I might be completely wrong haha, I'm trying to get it – Nim Apr 09 '18 at 23:04
  • 1
    No. Virtual memory means that each process has its own view of memory. All addresses are virtual, so their numerical values don't matter. Address 0x1000 for process A is not referencing the same physical memory as address 0x1000 for process B. Addresses cannot be transferred across process boundaries, since they are only valid in the original process' virtual memory space. – unwind Apr 10 '18 at 08:19
  • @unwind I see... But how comes modifying the health value the first time worked then? If process A isn't referencing the same memory as process B, why did it work when I took the address from cheat engine, and tried writing to it? – Nim Apr 10 '18 at 08:36
  • I'm not familiar with Cheat Engine (and corporate fw objects to me learning more), perhaps it uses operating system magic to look into another process' address space. You can of course do that too, then, but it's way more complicated than just using a raw pointer initialized to some value. – unwind Apr 10 '18 at 08:47
  • @unwind I don't know exactly how it does its magic but yeah, it allows you to scan for values in another process, like, find all addresses that contains the number 28, then you change the value in the game (if it's health by getting hit or something), and scan again with the new value, and with multiple scans you can find the address of the variable you want to modify. It's really handy, and it allows you to do pointer scans too, to find the base address of the variable, that you can reuse even after closing the game. And that's what I'm trying to do, using the pointer I found in my C code – Nim Apr 10 '18 at 09:08
  • @unwind But I'm not entirely sure how I can do that, but I'll keep searching ^^. Thanks for your help! – Nim Apr 10 '18 at 09:09
  • @unwind Alright, I found how to do what I wanted ! Thank you again :D ! – Nim Apr 10 '18 at 16:46

1 Answers1

0

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;
}
Nim
  • 158
  • 2
  • 14
  • Here's a function that will remove all that redundant code, thought you would benefit from it https://hastebin.com/rewutugipi.cpp cheers – GuidedHacking May 06 '18 at 03:01
  • @GuidedHacking Thank you! I did already improve my code, here: https://pastebin.com/SEpypstw, but your exemple with the function is much better, especially since I have multiple addresses to calculate. I also finished the program, here's the full code: https://pastebin.com/tPnr1n1f, if you have some advices for me... I do know I have to use functions way more, because lots of my code repeats, I'll do that, but any other thing? Thanks again! – Nim May 06 '18 at 18:18