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;