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.
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:
character.ID = [character] = [0x006FFAC4]
character.health = [character] + 0x4 = [0x006FFAC4] + 0x04
character.weight = [character] + 0x8 = [0x006FFAC4] + 0x08
character->name = [[character] + 0xC] = [[0x006FFAC4] + 0x0C]
character->weapon.strength = [[character] + 0x10] = [[0x006FFAC4] + 0x10]
character->weapon.energy = [[character] + 0x10] + 0x04 = [[0x006FFAC4] + 0x10] + 0x04
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
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