5

I'm reverse-engineering an old game, using CE. I found the code that modifies the unit's HP, but I can't find the base address, since the offset is negative.

OPCODE: "mov [esi-282],ax"[1]

The thing is I don't even know how this works, it sounds silly to me, why would the compiler/dev do that anyways ? Is it a kind of a stack temporary pointer ? Is there any way to find it ? (I'm pretty sure there is a way) It's frustrating because I have found offsets for like the ID, the HP and stuff, but the base... I don't have problems with that normally, the offsets are positive.

I thought that the base would be something along [esi-STRUCTURE_SIZE] and the last item would be [esi]

Or maybe I'm completely wrong.

Thanks :)

Riptide
  • 385
  • 7
  • 17
  • 1
    It would help to see how esi is set. A potential why, is sometimes the compiler will offset a base address to the start of a contained array or other sub-object. The original register may then be reused for another purpose. In terms of field access, it's all just an offset from a known point, whether it be the base address, or the address of a sub-object, so if a register already contains such a fixed point it may be used rather than reloading the original base address. – Daniel Stevens Feb 12 '16 at 08:12
  • I _kinda_ get it, seems twisted. I already checked how is esi set, I searched through many calls/returns, the register is moving between esi and ecx among the different calls, I can't get to it. It seems that it never ends – Riptide Feb 12 '16 at 08:54
  • I'm a bit confused, you are looking for the base address of... what? – Margaret Bloom Feb 12 '16 at 13:25
  • I'm actually looking for the "base" address of an object. Here the esi-282 thingy accesses an unit's HP, I want however access to the first item (start of structure) in order to analyze the unit structure. Normally classic instructions looks like `mov [ecx+F5],ebx` and the base address would be ecx, and the first field/item/attribute [eax]. By the way I'm doing this on an old game because I find that games are a great way to learn and analyze. – Riptide Feb 12 '16 at 17:10
  • It's common to copy ecx in the function prolog to a non-trashable register, such as esi, edi, ebx, or ebp. This will preserve its value across other function calls, which are expected to trash the contents of ecx (and eax, and edx). For class member functions, ecx would contain the `this` pointer. I would expect any offsetting to happen between that point and the code you posted. Tracing back to caller functions would be unexpected. The other thought I'm having now, is multiple inheritance. Casting an object to its different types can offset the base address. – Daniel Stevens Feb 12 '16 at 17:25
  • Interesting to know, so it seems harder than I thought, I'm not sure if I can handle this with my current level of knowledge. I could try in an other code segment, analyze the strcture from there come back and adjust. I kept that as a resort solution. Any suggestion is welcome though, I'm curious about it if I can learn other useful things :) – Riptide Feb 12 '16 at 17:42
  • Your shown function could operate on a sub-class instance using multiple inheritance like Daniel mentioned. To access members of base classes it has to use a negative offset from the this pointer. Have you tried doing a "find out what accesses this address" on the ID for example? That one should be handled generically via base-class pointers by the game. – typ1232 Feb 13 '16 at 14:33
  • @typ1232 Brilliant, I didn't thought about using that ID, and that worked, which is great. I previously found the base address using an other segment that was using "fleet" IDs, and your approach confirms that it's correct. – Riptide Feb 19 '16 at 15:35

1 Answers1

3

Negative offsets are typically used for accessing base class members from a sub-class pointer when multiple inheritance is used. The compiler will know the full layout and instead of upcasting the pointer first, directly access members from base classes.

From the generated code it is not possible to know where the class instance starts in memory. However it should generally be possible to find the base pointer by tracking accesses to negativly addressed members. After all the programmer probably created the hierarchy to access the base members independently of what exact derived type they are.

typ1232
  • 5,535
  • 6
  • 35
  • 51