Skip to content

Latest commit

 

History

History
42 lines (34 loc) · 2.99 KB

File metadata and controls

42 lines (34 loc) · 2.99 KB

Tips for reverse-engineering TR5

Bit-fields

Some structures used in Tomb Raider 5 (whose definitions are available in the TYPES.H and SPECTYPES.H headers for most of them) contain bit-fields, i.e. various different fields that each occupy 1 or 2 bits. Example from COLL_INFO struct (only the bit-field is shown):

struct COLL_INFO
{
	unsigned short slopes_are_walls : 2; // offset=132.0
	unsigned short slopes_are_pits : 1; // offset=132.2
	unsigned short lava_is_pit : 1; // offset=132.3
	unsigned short enable_baddie_push : 1; // offset=132.4
	unsigned short enable_spaz : 1; // offset=132.5
	unsigned short hit_ceiling : 1; // offset=132.6
};

Here, all of the fields above fit in a single short (16-bit signed integer), and the number after the colon represents the number of bits that the field occupies. On a little-endian architecture, the fields above will be stored in the order of their definition (although it is not mandatory by the C standard; the compiler is free to choose any arrangement, but that is the most common case you will stumble open).

The problem is that in IDA Pro, and most other decompilers, bit-fields are not handled correctly, but instead treated as a whole:

  • in IDA Pseudocode, they will be shown as bf_XX (XX is the offset of the field in hex) and handled as a standalone field)
  • in MIPS assembly, the field will be treated the same way as the pseudocode, but will be "referenced" with the offset of the bit-field.

Therefore, operations on bit-fields are mostly bitwise ANDs and ORs (for clearing and setting a field, respectively). Determining which "part" of the bit-field is being cleared or set takes time, it implies converting the instruction value to its binary representation and finding which bits corresponds to which field. Thus, here is a cheatsheet of common bit-fields operations.

StructureOperationValueResult
ITEM_INFO
And assign
0xFFF9
item.status = 0;
0xFFF7
item.gravity_status = 0;
Or assign2
item.status = 1;
lara_info
And check
0x40
lara.CanMonkeySwing
0x20
lara.IsMoving
And assign
0xFFFB
lara.look = 0;
0xDFFF
lara.Busy = 0;
COLL_INFO
And assign
0xFFCF
coll.enable_spaz = 0;
coll.enable_baddie_push = 0;
0xFFDF
coll.enable_spaz = 0;
0xFFEF
coll.enable_baddie_push = 0;
Or assign
0x10
coll.enable_baddie_push = 1;