Pointers

This article about pointers targets specificly game hacking.








What is a pointer?

Long story short: A Pointer is a number in memory that equals a certain memory address. Pointers are used whenever the location of a value might change. Locations may change due to the memory management of the game/program. Imagine having a level loaded somewhere in memory and your character is stored behind it. Now if you change the level it might occupy more or less space in memory so your character's properties might be relocated as well to prevent it from being overwritten or having unused gaps of memory. How does the game now where your character is located anyways? Pointers! (Starting) Pointers are statically stored and won't be relocated. These will be used to express a path through memory targeting the desired value.

memory  management

Offsets

Pointers don't always point directly to the target value. Instead, there might be a small offset. This happens because pointers might redirect to some data structure. Imagine your character has many properties like health, size, weight, name, textures, the pointer will always point to the beginning of your character's structure. So adding some offset to the pointer will lead us to the target value (health). Adding another offset instead will lead us to another value again (weight). Offsets can also be negative.

Pointers-to-Pointers

In some cases a pointer redirects to some structure that also contains pointers. This is another memory optimization used by the game. When attempting to create a cheat code it might be required to search for a pointer that redirects to another pointer. In theory there is no limit on pointer depths. 3-level, 4-level pointers are also possible but rare. You might only care about these when hacking PC games. But exeptions might also occur on embedded systems like consoles.

Example in C++

The below code demonstrates everything needed to be known. For simplification, I ignored any good coding practice, but it demonstrates how data is accessed by using offset numbers (it's for a good sake, you will survive the pain, I promise). If you don't understand any of the code the given, don't worry, images might help you anyways.

#include <iostream> #include <string> using namespace std; class Weapon { public: int m_strength; int m_energy; Weapon(int p_strength, int p_energy) { m_strength = p_strength; m_energy = p_energy; } }; class Character { public: int m_id; int m_health; int m_weight; string* m_name; Weapon* m_sword; Character(int p_id, int p_health, int p_weight, string* p_name) { m_id = p_id; m_health = p_health; m_weight = p_weight; m_name = p_name; m_sword = new Weapon(31, 85); } }; int main() { string name = "Videl"; Character* character = new Character(123, 100, 60, &name); char* pointer = (char*)character; cout << "Pointer to character location at: 0x" << &character << "\n" << "Character located at: 0x" << (int*)pointer << "\n" << "ID (at pointer): " << (int)(*pointer) << "\n" << "health (at pointer + 4): " << (int)*(pointer + 4) << "\n" << "weight (at pointer + 8): " << (int)*(pointer + 8) << "\n\n"; string* namePointer = (string*)*(int*)(pointer + 0xC); cout << "namePointer: " << namePointer << "\n" << "value at namePointer: " << *(string*)namePointer << "\n\n"; char* weaponPointer = (char*)*(int*)(pointer + 0x10); cout << "Weapon pointer: 0x" << (int*)weaponPointer << "\n" << "Weapon strenght (at pointer): " << (int)*weaponPointer << "\n" << "Weapon energy (at pointer + 4): " << (int)*(weaponPointer + 4) << "\n"; }

The code contains two classes. One expresses a weapon (Line 5 - 16) with two properties (strength (L 8) and energy (L 9)). Another one expresses a character (L18 - 35) that features an ID (L 21), health (L 22), weight (L 23), name (L 24) and weapon (L 25). The name member is a pointer that directly redirects to the name (L 39). The weapon member is a pointer as well. The character instance is a pointer too (L 40). So we can obtain the character's pointer, and follow it to its properties. Since other properties are referenced by pointers we can extend the pointer path.
First the character pointer is casted to a pointer of the type char* (L 41) so bytewise incementations to the pointer are possible. Now all initialzation is done.
Next we print where the character's pointer is located (L 43).
On line 44 we print the address to the character that is located at the address we print on line 43.
Since we have the pointer we can now dereference it and obtain the character's ID (L 44).
By adding an offset of 4 we can access the next member and obtain the health value.
Same can be done by adding 8 but now we get the weight instead (L 45)!.
This demonstrates how we access a value through a single pointer + offset.
Simplified expression (Brackets show what is being dereferenced): [pointer at character-instance] + 4 = health of 100

Now we go for a pointer-to-pointer path!
Let's access the charcter's name this way. By 0x0C to the pointer we get the name's pointer location (L 49). Printing it reveals the real location (L 50) and dereferencing it gives us the value (L 51). [[pointer at character instance] + 0x0C] = name "Videl"


Last but not least we wanna access the weapon's values via a pointer-to-pointer path, now with an offset given after the encapsulated pointer.

First, we obtain the weapon pointer (L 53) and print it (L 54). By dereferencing it we get the strength and adding an offset of 4 to the pointer we get its energy value (L 55). [[pointer at character instance] + 0x10] + 4 = Weapon's energy of 85

Console output:

console output
visualizing of pointer paths

Searching for Pointers

How do I know I need pointers?

Whenever you notice a cheat code stops working it is good to check its address. If the hacked value has diappeared it might be located somewhere else.

Prepare the Pointer Search

Find it again and jot down its address. Befor you do anything else dump the entire memory.
Once done go to another level (or do whatever caused the address to change) and find the updated address. Write it down once again and perform another memory dump. It is up to you how many memory dumps you collect but you will need at least two.

Performing the Pointer Search

First it requires you to set up the pointer search. For this we load the first dump:
Enter the base address. This is the Address where the game maps the memory at (N64, GCN, Wii: 80000000, Wii U: 0x10000000).
Enter the maximum and minimum (negative) offsets. The bigger they are the more possible results you will get. However, this can increase the search time exponentially. Thedestination address is where you have found your value.
Now start the first search. You will get too many results. ignore them for now and go for the second search. Load the second dump and enter the second target address. You should now have a small selection of possible results. If you are left with too many results go for a 3rd memory dump.

The result: [0x803d1d38] + 0x35bc = 0x80abc010

Prepare initial search Prepare second search Results

Creating Cheat Codes Featuring Pointers

Range Check

When the game is loading another scene or level you might not want to read from or write to some pointer path. The pointers might change or be used by something else or are overwritten with a null-pointer. Dereferencing a null-pointer will inevitably cause the game to crash. Crashes might also occur when writing to som pointer path while it's being used for something else during load times. To prevent this from happening range checks got you covered. If the destination address is never lower than 0x80AB0000 and never bigger than 0x80AB0000 a range check between these two value should be used. So when ever the pointer does not match any value between the cheat won't be executed to prevent any crashes.

MungPlex Lua

ptr = ReadFromRAM(INT32, 0x803d1d38) if (ptr >= 0x80AB0000 and ptr < 0x80AC0000) then ptr = ptr + 0x35BC WriteToRAM(INT32, ptr, 0x43000000) end

Line 1: Load pointer into ptr
Line 2: Check if in range
Line 3: Add offset to ptr
Line 4: Write value to pointer

Pointer-to-Pointer

Shown with the values of character->weapon.energy


ptr = ReadFromRAM(INT32, 0x006FFAC4) if (ptr >= 0x006F0000 and ptr < 0x00720000) then ptr = ptr + 0x10 ptr = ReadFromRAM(INT32, ptr) if (ptr >= 0x00B20000 and ptr < 0x00B40000) then ptr = ptr + 0x04 WriteToRAM(INT32, ptr, 100) end end

Line 1: Load pointer into ptr
Line 2: Check if in range
Line 3: Add offset to ptr
Line 4: Load encapsulated pointer into ptr
Line 5: Check if in range
Line 6: Add offset to ptr
Line 7: Write value to pointer

Wii Gecko

48000000 803d1d38 DE000000 80AB80AC 140035BC 43000000 E0000000 80008000


Line 1: Load pointer into ptr
Line 2: Check if in rangebr
Line 3: Write value to pointer + offset


Pointer-to-Pointer

To Do



Wii U Cafe Code

30000000 403d1d38 40AB0000 40AC0000 001235BC 43000000 D0000000 DEADCAFE


Line 1: Load pointer into ptr Line 2: Check if it is in range Line 3: Write value to pointer + offset



Pointer-to-Pointer

Shown with the values of character->weapon.energy. Base of 0x10000000 added.


30000000 106FFAC4 106F0000 10720000 31000000 00000010 30100000 00000000 10B20000 10B40000 00120004 00000064 D0000000 DEADCAFE


Line 1: Load pointer into ptr
Line 2: Check if in range
Line 3: Add offset to pointer
Line 4: Load encapsulated pointer
Line 5: Check if in range
Line 6: Write value to pointer + offset

©Lawn Meower (Sophie Schmidt) 2015 - 2022