0

Will be using the game Assault Cube as an example. Here are the addresses found with Cheat Engine from searching the health value.

We have 0x0050F4F4 (static local player pointer) which points to 0x00CA9000 (dynamic player object address)

Then 0x00C9A000 + F8 = 0x00C9A0F8 will give us the dynamic address of health

Here is the class:


class CPlayer
{
public:
char __0x0000[0xF7]; //0x0 - 0xF7
    __int32 m_nHealth; //0xF8
};


#define ADDR_Player 0x0050F4F4

CPlayer* pPlayer = *(CPlayer**) ADDR_Player;

pPlayer->m_nHealth;

What I don’t understand is why did they cast ADDR_Player to a pointer to a pointer of type CPlayer? How is it a double pointer?

If you dereference *ADDR_Player:

0x0050F4F4 -> 0x00C9A000 = 13202112 (random value)

If you dereference *ADDR_Player + offset:

0x0050F4F4 -> 0x00C9A00+F8 = 40 (health)

I thought it would be like this: CPlayer* pPlayer = *(CPlayer*) ADDR_Player; but this is incorrect and I don’t understand why the correct one is casted to a double pointer:

CPlayer* pPlayer = *(CPlayer**) ADDR_Player;

localhost
  • 25
  • 3
  • `char __0x0000[0xF7]; //0x0 - 0xF7` This looks weird. The array has `0xF7` elements `0x0 - 0xF6`. There may be another (padding) byte after that because the next member is `__int32`. – MikeCAT Jun 19 '22 at 14:26
  • Are you asking why the programmers of Assault Cube stored a pointer to pointer to player at address 0x0050F4F4? That could have millions of answers that might all be wrong. Maybe they did just to confuse cheaters? – Goswin von Brederlow Jun 19 '22 at 14:59

2 Answers2

1

0x0050F4F4 is a memory address, so the type of a variable holding that value would be a "pointer to something", but a pointer to what?

What resides at address 0x0050F4F4? Another memory address: 0x00C9A000. Since that is a memory address, the type of that data is "pointer to something". That means the type of the original variable holding 0x0050F4F4 is "pointer to pointer to something".

Finally, you can look at what resides at address 0x00C9A000. That's a CPlayer object, so the variable holding 0x00C9A000 is a "pointer to CPlayer" which means the variable holding 0x0050F4F4 is a "pointer to pointer to CPlayer".

That is, you have something like this in memory:

 Memory       ADDR_Player              0x0050F4F4               0x00C9A000
┌─────────────┬──────────┬─────────────┬──────────┬─────────────┬────────────────────────┐
│             │          │             │          │             │                        │
│     ...     │0x0050F4F4│     ...     │0x00C9A000│     ...     │     CPlayer Object     │
│             │     │    │             │     │    │             │                        │
└─────────────┴─────┼────┴─────────────┴─────┼────┴─────────────┴────────────────────────┘
                    │                  ▲     │                  ▲
                    │                  │     │                  │
                    └──────────────────┘     └──────────────────┘

As you can see, ADDR_Player points to a pointer that points to your CPlayer object. That is, it is a CPlayer**.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
  • So… 0x0050F4F4 points to 0x00C9A000. So are you saying 0x00C9A000 is a pointer aswell and not a variable? If that is the case then what memory address does 0x00C9A000 hold in its value? – localhost Jun 22 '22 at 04:05
  • Pointers _are_ variables. At address `0x0050F4F4` is a `CPlayer*` variable with the value `0x00C9A000`. That pointer points to a `CPlayer` object at address `0x00C9A000`. See the diagram in my answer. At the top are the addresses of the variables in memory, inside the boxes are the values held in those variables. – Miles Budnek Jun 22 '22 at 16:12
0

You want a pointer CPlayer*. What will be a pointer when dereferenced is a pointer to pointer CPlayer**. So casting to CPlayer** and dereferencing is a good way to obtain CPlayer* value.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70