Pointer Search

Pointers are what games use to keep track of the locations of chunks of memory that have been dynamically allocated. If you need a detailed explanation on what pointers are and how to work around them, see About Pointers. Pointer Searches allow you to find pointers to dynamic game objects, or objects that move in memory. This is often called dynamic memory allocation, or DMA.

For the remainder of this page, for the sake of explanation, we will assume we are hacking a 3-D first-person shooter game that stores its lists of players dynamically. Typically in this type of a game, a person will have found his or her character’s health as an int from 0 to 100, but the person will notice that when he or she dies, the address for the health is no longer valid; the player’s health has moved to a new location and must be located again.

What has actually happened is that the chunk of RAM that contained the player’s character data was deallocated by the game and then reallocated when the player respawned. It has not just moved the health, but the ammo, position, energy, and everything else related to the character.

There is, however, one thing that did not move. No matter how complicated a game is, it still needs a way to find the data for each character, no matter when or where the data moves. All games, without exception (as guaranteed by the x86 architecture), have static (non-moving) data. Static pointers (pointers that do not move) are there specifically to tell the game where these sets of moving data are going when they move.

Be careful to note that static data is often defined as data that does not move, however on the Windows® platform there is no such thing as data that does not move. All static data is stored in relation to the module that contains it, and Windows® guarantees that all modules in a process can be loaded to another address if system memory is running low. For simplification, we will assume the game is always loaded at 0x00400000.

 

Properties of Pointers

Pointers have several properties that allow us to locate them. The most important property is that they always point to the base of any given data set (called a structure). Consider the following example.

The red rectangles outline a player structure containing our health, ammo, and some other values we don’t understand. The actual addresses of these values is irrelevant at this point; they are always referenced as an offset from the structure base, however we don’t yet know where the base is. We do, however, know that the game has a pointer to this structure somewhere, and that pointer will point to the base of it. We also know that structures are never large. That means if we have a value inside a structure (health and ammo here), then the base of the structure is never far away. In the picture above, the first value in the structure that we understand is the health. This means the base of the structure is before the address of the health, but not far before the address of the health.

It is usually safe to assume that no structure in your game will be larger than 0x10000 bytes. That means if we have the health of our player, the base of the structure will never be lower than [Address of Health] - 0x10000.

 

Using What We Know

Now we have enough information to perform a Pointer Search. The full search options are explained below, but for now we will only discuss the options used in this example.

Let’s assume the address of Health in the picture above is 0x02BE2C04. Given what we know about structures, the base of the structure must then be between 0x02BD2C04 and 0x02BE2C04. For the sake of simplicity, let’s round 0x02BD2C04 down to 0x02BD0000. In the Pointer Search dialog, we would select Range in the Search Type, then enter 2BD0000 and 2BE2C04 into the Points Between and And edit boxes.

This means we are searching for all pointers that point to locations between 2BD0000 and 2BE2C04, inclusively. The base of our structure is around there somewhere and there is a pointer somewhere that points to it.

We only want to find pointers that won’t move, so we select Only Find Static Pointers. The search will automatically save the offset from 2BE2C04. This will be explained later.

After performing the search, we may get several returns. As stated before, the structures are usually small, so the base of our structure should be near Health. Using the Found Addresses dialog (Search/View Results), we will see a column entitled Distance from 02BE2C04. This is how we can tell how far away pointers are from our Health (address 0x02BE2C04). Negative numbers indicate that the pointer is pointing to a location lower than 2BE2C04. A distance of 0 indicates that the pointer is pointing directly at 2BE2C04. Positive numbers should never be in the list, because pointers to our structure will never point higher than the address of Health (2BE2C04).

The dockable Found Addresses list shows this offset.

For our example, we will assume there is a pointer at address 0x0045EFC0 whose distance is -0xC from 2BE2C04 (our Health). This happens to be very close, though the average distance can be around -0x200 to -0x500, and in some cases farther. If you find a pointer that has a distance between -0x500 and 0x0, there is a very high chance it is the correct pointer to your structure.

Double-click the pointer in the Found Addresses list to add it to the main list. This is the result:

The base of our player structure can always be found by following the pointer at address 0x0045EFC0. If we add 0xC to that location, we have our player health. If we add 0x1C to the base address, we have our player ammo.

 

The Options at Our Disposal

The following chart explains each option in the Pointer Search dialog.

Option

Description

Target

Targets Other Than

Target From

Find Targets Greater Than

Find Targets Lower Than

Let Me Handle This

The meaning of this depends on the Search Type.

Evaluation Type Meaning
Exact Value Find pointers that point to this exact location.
Not Equal To Finds pointers that do not point to the value specified.
Range Find pointers that point between this location and the location specified in the And box, inclusively.
Lower Than Find pointers that point to locations below this location, exclusively.
Greater Than Find pointers that point to locations above this location, exclusively.

It must be in hexadecimal form. Other restrictions apply as outlined in Additional Notes.

To In a Range Search Type, this is the top of the range where pointers can point, inclusively. It must be in hexadecimal form.
Evaluation Type

Specifies the type of search to perform.

Evaluation Type Meaning
Exact Value Find pointers that point to the exact location specified in Target.
Not Equal To Find all pointers that do not point to the location specified in Targets Other Than.
Range Find all pointers that point to locations between Target From and To, inclusively.
Lower Than Find all pointers that point to locations below the location specified in Find Targets Greater Than.
Greater Than Find all pointers that point to locations above the location specified in Find Targets Lower Than.
Unknown Find all pointers.
Only Find Static Pointers Only static pointers (pointers that do not move when the game is restarted) will be found. Static pointers may move only if the module in which they are located moves. For example, the gamex86.dll module in Doom® 3 moves each time the game is restarted. Static means the pointers move with the module, and are always the same distance from the base of the module.
Enable “Same as Original” Sub Search Using the Same as Original sub search requires extra resources since the initial search must be stored to disk. If you do not need the Same as Original sub search, it is best to uncheck this.
From Specifies the starting address from which to search.
To Specifies the ending address at which to stop searching (exclusive).

 

Additional Notes

All fields must be entered in hexadecimal form.

The Points To field must follow the rules of a valid pointer, which means it must be divisible by 4 and must be a readable address in the target process.

Range searches always go from the lower number to the higher number, regardless of the order in which you enter them.

The search itself always starts at the lower address and goes to the higher address, regardless of the order in which they are entered.

All search data entered into the dialog is saved if you click OK and perform a search, which allows you to repeat searches without having to fill out every box again.

Only if you perform a search will the previous results be lost.

 

Tips

  • The most common options are to use a Range Search Type with Only Find Static Pointers and Save Offset From checked.
  • The And value in a Range search should always be the lowest known address in the structure to which you are trying to find a pointer.
  • The Save Offset From value should always be the same as the And value in a Range search.
Copyright © 2006 Shawn (L. Spiro) Wilcoxen