Skip to main content
Pointer chains (also called deep pointers or pointer paths) are essential for accessing dynamic game data that moves in memory. They follow a series of offsets from a base address to reach the final value.

Understanding Pointer Chains

In games, data structures like player health are often allocated dynamically and move around in memory. However, you can reach them by following a chain of pointers from a static base address.

Anatomy of a Pointer Chain

Base Address (static)
  |
  +--[offset 0xA0]--> Pointer 1
                       |
                       +--[offset 0x04]--> Pointer 2
                                            |
                                            +--[offset 0x10]--> Pointer 3
                                                                 |
                                                                 +--[offset 0xF0]--> Player Health

Deep Pointer Example

This real-world example from the README demonstrates using a pointer chain from Cheat Engine to access player health:
from libmem import *
import time

process = find_process("game.exe")
game_mod = find_module_ex(process, process.name)

# Resolve a Cheat Engine pointer scan
health_pointer = deep_pointer_ex(process, game_mod.base + 0xdeadbeef, [0xA0, 0x04, 0x10, 0xF0, 0x0])

# Set player health to 1337 forever
while True:
    write_memory_ex(process, health_pointer, bytearray(int(1337).to_bytes(4)))
    time.sleep(0.2)

How It Works

1

Find the Base Address

Start with a static address - typically a module base plus an offset. This base address never changes between game restarts.
2

Define the Offset Chain

Create an array of offsets that describe the path through memory. These offsets are found using tools like Cheat Engine.
3

Resolve the Chain

Call deep_pointer_ex to follow each pointer in the chain, dereferencing and adding offsets until reaching the final address.
4

Access the Data

Use the resolved address to read or write the actual data value.

Internal Process Pointer Chains

For the current process, use the non-Ex variant:
#include <libmem/libmem.h>

int main()
{
    lm_module_t my_module;
    lm_address_t offsets[] = {0x20, 0x10, 0x08};
    lm_address_t final_ptr;

    LM_GetModule(&my_module);
    
    final_ptr = LM_DeepPointer(
        my_module.base + 0x12345,
        offsets,
        LM_ARRLEN(offsets)
    );

    if (final_ptr != LM_ADDRESS_BAD) {
        int value;
        LM_ReadMemory(final_ptr, (lm_byte_t*)&value, sizeof(value));
        printf("Value: %d\n", value);
    }

    return 0;
}

Finding Pointer Chains

Pointer chains are typically discovered using memory scanning tools:

Using Cheat Engine

1

Find the Value

Use Cheat Engine’s value scanning to locate the address of your target data (e.g., player health).
2

Perform Pointer Scan

Right-click the address and select “Pointer scan for this address”. This searches for pointer chains that lead to it.
3

Filter Results

Restart the game and rescan to filter out invalid pointer paths. Valid paths will still point to the same data.
4

Extract the Chain

The shortest, most reliable pointer path becomes your offset chain. The first address is typically module.base + offset.

Common Patterns

Single-Level Pointer

// Base -> Value
lm_address_t offsets[] = {0x0};
lm_address_t value_ptr = LM_DeepPointerEx(&process, base_addr, offsets, 1);

Two-Level Pointer

// Base -> Pointer -> Value
lm_address_t offsets[] = {0x10, 0x0};
lm_address_t value_ptr = LM_DeepPointerEx(&process, base_addr, offsets, 2);

Multi-Level Pointer Chain

// Base -> P1 -> P2 -> P3 -> Value
lm_address_t offsets[] = {0xA0, 0x04, 0x10, 0x0};
lm_address_t value_ptr = LM_DeepPointerEx(&process, base_addr, offsets, 4);

Error Handling

Always check if pointer resolution succeeded:
lm_address_t result = LM_DeepPointerEx(&process, base, offsets, noffsets);

if (result == LM_ADDRESS_BAD) {
    printf("Failed to resolve pointer chain\n");
    // Handle error - pointer chain may be invalid or game state changed
    return 1;
}

Best Practices

Always check if deep_pointer_ex returns a valid address. Invalid chains return LM_ADDRESS_BAD or None.
Shorter pointer chains are more reliable and less likely to break when the game updates.
Module base addresses don’t change during runtime, so cache them instead of looking them up repeatedly.
Game updates may change offsets. Be prepared to re-scan pointer chains after patches.
Some data may be NULL or invalid depending on game state (e.g., no player loaded). Add validation.

Common Use Cases

  • Player Stats: Health, mana, stamina, experience points
  • Inventory Items: Item counts, equipment stats
  • Game State: Level ID, checkpoint data, quest flags
  • Entity Data: Enemy health, positions, AI states
  • Resource Pools: Ammunition, currency, crafting materials

Troubleshooting

  • Verify the base address is correct (module.base + offset)
  • Check if the game state has changed (e.g., not in a level yet)
  • Ensure offsets are in the correct order
  • Re-scan pointer chain with Cheat Engine
  • Pointer chain may be stale after a game update
  • Game might be using a different instance of the data
  • Try refreshing the pointer scan
  • Pointer chain may be invalid, leading to bad memory access
  • Add validation before reading/writing
  • Ensure offsets are correct size for the target architecture

Next Steps

Memory Operations

Learn basic read/write operations

Memory API

Explore all memory functions

Build docs developers (and LLMs) love