Skip to content

Structures

brkzlr edited this page Jun 18, 2026 · 6 revisions

Structures

Structures (or Structure Types) let you define custom data layouts and apply them to memory addresses. If you've ever reverse engineered a game struct or class and wanted to see all its fields laid out nicely with their current values, this is your bread n butter.

It's basically like creating your own mini type system on top of raw memory. You tell PINCE "at this address, there's an int at offset 0, a float at offset 4, a pointer at offset 8" and so on and the Structure view will read and display all those values for you, updating in real time as the game runs.

How can I access it?

  • You need to be attached to a process first.
  • After that, open Memory View.
  • Go to Tools -> Structures.

This opens the Structures window where you can manage your structure definitions.

Creating a Structure

Click New in the Structures window to open the Structure Editor. You'll need to give your structure a name and then add members to it.

Adding Members

Each member represents a field in your structure. Click Add to create a new member and you'll see these options:

  • Name: What you want to call this field (like health, position_x, ptr_to_inventory).
  • Offset (hex): The byte offset from the structure's base address. Enter in hex without the 0x prefix.
  • Kind: What type of member this is:
    • Value: A primitive value (int, float, string, etc.)
    • Pointer: A pointer to another structure (dereferences the pointer at this offset)
    • Inline: Another structure embedded directly at this offset (no pointer dereference)

Value Members

For value members, you pick the data type:

  • Integer types: Int8, Int16, Int32, Int64 -> choose signed, unsigned or hex representation
  • Float types: Float32, Float64
  • String types: ASCII, UTF-8, UTF-16, UTF-32 -> set the length and zero termination
  • Byte array: Raw bytes with a specified length

You can also set the endianness if the game uses a different byte order than your system.

Pointer and Inline Members

These let you nest structures. Say you have a Player structure with a field that points to an Inventory structure:

  1. First create the Inventory structure with its own members.
  2. Then in your Player structure, add a member at the right offset.
  3. Set Kind to Pointer (if the field holds an address) or Inline (if the inventory data is embedded directly).
  4. Select Inventory from the Structure dropdown.

When you view the structure, pointer members will follow the pointer and show the nested structure's fields. Inline members will interpret the bytes at that offset as the nested structure.

Viewing a Structure

Once you've defined a structure, you can view it at any address:

From the Structures Window

  1. Select the structure in the Structures window.
  2. Click View at address….
  3. Enter the base address.

From the Address Table

Right-click on any entry in the address table and hover over View as structure. You'll see a submenu listing all your defined structures. Pick one and the Structure View opens at that entry's address.

This is handy when you've already found an interesting address and want to interpret it as a known structure without having to copy the address over manually.

The Structure View window opens showing all your members with their current values. The view has four columns:

  • Offset: The byte offset from the base address.
  • Name: Your member name.
  • Type: The data type or nested structure name.
  • Value: The current value read from memory.

Live Updates

The Structure View polls memory at the same interval as the address table, so values update automatically as the game runs. You can double-click any value in the Value column to edit it directly.

Expanding Nested Structures

If you have pointer or inline members, you'll see an expand arrow next to them. Click it to drill down into the nested structure and see its fields. This works recursively up to 16 levels deep.

For pointer members, PINCE reads the pointer value at that offset and uses it as the base address for the nested structure. If the pointer is null, the expansion just shows nothing.

Adding to the Address Table

You can push an entire structure's members into the address table as a group:

  1. Select your structure in the Structures window.
  2. Click Add to address table.
  3. Enter the base address.

All the structure's members appear in the address table as a collapsible group, with their offsets shown as relative addresses. Nested structures become sub-groups. This is handy when you want to monitor or freeze multiple related values at once.

You can also do this from the Structure View window with the Add to address table button at the bottom.

Structure Rows in the Address Table

When you add a structure to the address table, the parent row is a special type that only holds an address, it doesn't have an editable value or type like normal entries. The child rows underneath it are the actual members with their values.

You can change the base address of a structure row by double-clicking its address column. This updates all the child rows' addresses automatically since they're calculated as offsets from the base.

Structure rows have some limitations compared to normal entries:

  • No freeze: The freeze checkbox on a structure row just unchecks itself as you can't freeze the parent row. Individual child members can still be frozen though.
  • No "View as structure": Right-clicking a structure row doesn't show the View as structure submenu since it's already a structure.
  • Relative addresses: Child rows show their offset as the address (like +0x10) rather than the resolved absolute address.

Editing and Deleting

  • Edit: Modify an existing structure's name or members. Double-clicking a structure in the list also opens the editor.
  • Delete: Remove a structure definition. This doesn't affect any address table entries you've already created from it.

In the Structure Editor, you can reorder members with the Up and Down buttons or remove them with Remove.

Saving with Sessions

Your structure definitions are saved alongside your address table when you save a session (.pct file). This means when you load a session later, all your structures come back with it.

If you share a .pct file with someone, they'll get your structures too, which is useful for distributing cheat tables that rely on specific structure layouts.

Practical Example

Let's say you've found a player object at 0x7f1234560000 and you know from reverse engineering that it has:

  • Health (int32) at offset 0x10
  • Mana (float32) at offset 0x14
  • Position X (float32) at offset 0x20
  • Position Y (float32) at offset 0x24
  • A pointer to an Inventory struct at offset 0x30

You'd create a Player structure like this:

Player
├── health        0x10    Int32
├── mana          0x14    Float32
├── position_x    0x20    Float32
├── position_y    0x24    Float32
└── inventory     0x30    ptr → Inventory

Then create an Inventory structure with whatever fields you've found there:

Inventory
├── gold          0x08    Int32
├── item_count    0x0C    Int32
└── items_ptr     0x10    ptr → ItemArray

Now when you view the Player structure at 0x7f1234560000, you see all the player's stats and you can expand inventory to see the nested Inventory fields. If you expand items_ptr, it follows that pointer too and shows the item array structure.

Tips and Tricks

Finding Offsets

If you're not sure about the exact offsets, you can use the address table and Memory Viewer to figure them out. Add a variable at a known offset, then use Find out what accesses this address to see what code touches it. The disassembly will show you the offset being used (like [rax+0x14]).

Structure Size

The structure's size field is mostly informational, it doesn't affect how members are read. But it's useful to keep track of how big your structure is, especially if you're dealing with arrays of structures.

Shared Structures

You can reuse the same structure definition across multiple addresses. If you have 5 enemies all using the same Enemy struct layout, just create one Enemy structure and view it at each enemy's base address.

Combining with Mono/IL2CPP Dissector

If you're working with a Mono or IL2CPP game, the Mono/IL2CPP Dissector can automatically generate structure definitions from the game's managed classes:

  • Export as Structure: Right-click on a class to create a structure definition with all the fields already filled in.
  • Dissect as Structure: Right-click on a class with a singleton pattern (like Player.Instance) or on a live instance in the Find Instances window to immediately open the Structure View on that object.

Common Patterns

Games often use common patterns you can recognize:

  • Object headers: Most objects start with a vtable pointer (8 bytes on 64-bit, 4 on 32-bit) followed by a sync block or reference count.
  • Arrays: Managed arrays usually have a length field followed by the elements. Native arrays might just be a pointer and size stored separately.
  • Strings: UTF-16 strings often have a length prefix. C-style strings are just null-terminated byte sequences.

Clone this wiki locally