6

I found an assembler instruction: mov [esi+2F],dl. I think ESI is a reference to a struct or class. 0x2F is the offset that references a property of the struct/class. Is it possible to find the value of the ESI register? I think this class or struct is initialized when the game is started.

For example, I tried to reverse GTA San Andreas. A lot of memory addresses of the GTA SA here.

I've found such information in this site: 0xB6F5F0 - Player pointer (CPed).

I think it's address that I finding now. But how I can find it with debugger like cheat-engine without pointer scan? I'd like to find addresses in asm code. It's possible?

I tried to set a breakpoint to the instruction. But I think it's useless because ESI address is dynamic. As I understand CPed struct/class uses dynamic memory allocation.

I am sorry for my bad English and thanks in advance.

  • I'm a little confused, "But how I can find it with debugger", do you want to find the value of ESI in a debugger or in a disassembler? Since the address of the struct/class is most likely dynamic you won't be able to find it with a disassembler. – RoraΖ Feb 9 '15 at 14:03
  • @raz however, since the game uses it, there must be a static location which stores the pointer. – rev Feb 9 '15 at 14:10
  • Either you do it the "hard" way, you backtrack instructions until you find what is the last modification on ESI and thus what is its value at that point. Or you just put a breakpoint on your debugger and read the value of ESI at this instruction. Any specific reason you want to do this statically? – Dillinur Feb 9 '15 at 14:20
  • @AcidShout Why? If it's an object it's most likely allocated at runtime and no static location in the binary is necessary. Unless it's a global variable there's not reason for it to have a static location. – RoraΖ Feb 9 '15 at 14:21
  • @raz you still have the variable which stores a pointer to the allocated object, and you can take it from there. and that variable will be static – rev Feb 9 '15 at 14:55
10

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:

Cheat Engine

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));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.