Yes, it is possible
I'm going to explain you a bit how most games do it (I have never reversed any GTA but I suppose it's something like this anyway).
I'm going to cover static and dynamic allocation of structures.
The static way:
GlobalGameInfo g_info;
// ...
g_info.some_data = 1;
This is what ends up being a static offset in IDA, like so:
lea eax, [g_info + 0xAABB] ; suppose 0xAABB is the offset for 'some_data'
mov [eax], 1;
g_info
is always going to stay at the same offset, so once you find it, you can just use g_info + offset
to get your data.
The dynamic way:
Player* players; // can be defined as Player* players[<count>] or Player** players;
// it's the same
// ...
players = new Player[players_count];
// ...
players[1].alive = false;
Which then results in:
; this is a static location which is actually the "players" variable
; and it contains an address which points to the offset in memory of the
; actual players structure
dword_xxxx dd ?
So to use it in e.g. Cheat Engine, you Add a new address
, check Pointer
, add the xxxx
part of dword_xxxx
, and in offset, put your desired offset.
For example, to get players[1].alive
, with alive
being on offset e.g. 0x100, you'd calculate:
value_stored_in_dword_xxxx + sizeof(Player) * player_id + 0x100
So if dword_xxxx
-> 0xAABBCCDD
, sizeof(Player)
-> 0x204
, player_id
-> 8
, and offset
-> 0x100
, your calculation would be:
0xAABBCCDD + (0x204 * 8) + 0x100
// ^base ^size ^id ^offset
The example
Since you gave us mov [esi + 0x2F], dl
:
esi
is a pointer to the structure. Look above (in the disassembly).
mov esi, dword ptr [dword_xxxx]
(most probably) means it's dereferencing a pointer, which means that the structure is allocated dynamically.
mov esi, offset dword_xxxx
(most probably) means that it's just assigning the address (xxxx
part) to esi
, so this is a static address.
The usage
Cheat Engine
In Cheat Engine, it's easy as inputting the pointer and the offset:
As you can see, 0x5CCB138
is the dword_xxxx
, the value inside dword_xxxx
is 0x09021A00
, and that + 0x142
(my offset) results in the start of the in-game name.
C
In case you want to do it programmatically, you can do it like this in C:
PCHAR my_name = PCHAR (*PDWORD(0x5CCB138) + 0x142);
^save the addr| | ^deref to get | add the offset
| ^cast | 0x09021A00 |
// -> be careful, do not surpass the max length!
// -> also remember that there's 'your name' length + 1 \x00 byte
// at the end!
char new_name[] = "newName";
strncpy(my_name, new_name, sizeof(new_name)); // again: be careful with the length!
The proper way, however, would be reversing the entire struct like this:
struct player_data {
int ID;
char name[15];
int some_data;
...;
};
// make sure the order / size of each item is correct!
// a single error can fuck up the entire struct
// I'm going to assume you understand pointers
player_data* data = *(player_data**) 0x5CCB138;
// do your changes
// again, be careful with the length!
// also note that sizeof() will not work if you use char*
char new_name[] = "new name!";
strncpy(data->name, new_name, sizeof(new_name));