Faster Than Light - Finding objects and Structures
Reversing object structures with Cheat Engine. First part of the FTL post series.
Let me preface this post by acknowledging that I haven’t posted a single thing in over a year. Whoops. I’m back now.
Introduction
The intent of this and the next couple posts are to form a coherent series that anyone can follow along to create their very own FTL cheat.
The end goal here is to go from cheat engine addresses to cheat table to standalone trainer. Hopefully following the trainer development process as closely as possible.
Before starting, you should have CE installed and ready to go and a copy of Faster Than Light (FTL). Basic programming knowledge and understanding of hexadecimal numbers (base 16) is recommended.
First glance
Start by loading up to the main menu and starting a new game. Immediately you can see multiple stats of interest.
These are all easily retrieved via a quick memory scan.
(I’ll get to the ship’s power and characters shortly)
Notice how closely the addresses are to each other. From that it’s reasonable to assume they are part of the same structure or parent structure. To confirm this, find out what accesses the Fuel address (F5) and inspect any of the opcodes. We’re presented with this.
cmp [eax+0x494], 03
If you are blissfully unaware of assembly, let me break down the relevant bit. Our fuel address (in my case 0x1BFB33B4) is being accessed by the pointer EAX + 0x494. as you can see at the bottom of the screenshot EAX is equal to 0x1BFB2F20. 0x1BFB2F20 + 0x494 indeed matches our address. What this entails is that the game does not directly access the fuel address but instead reads a ‘containter’ object with an offset to the fuel. EAX is that object’s address.
It’s also fair to assume our money address is part of this same object. Find out what accesses it again.. yep. offset of 0x4D4
We can tell cheat engine to read our values through this pointer as the game does.
Pointers
By now you may be wondering why even bother with pointers at all when you can just use the direct memory address.
Using pointers provides us with a few advantages down the road. First of all it cuts down our work exponentially. Instead of having a bunch of hardcoded addresses we have a couple pointers with their own offsets. Let me try to illustrate this with some pseudocode.
// Each variable has their own reference address
// All these addresses change each time the executable is ran.
int someVar; // 0x0040000
int someVar; // 0x0040030
int someVar; // 0x0040060
int someVar; // 0x0040100
int someVar; // 0x0042050
// Only the structure's address changes. the relative offsets remain
struct aStructure {
int someVar; // 0x0040010 + 0x00
int someVar; // 0x0040010 + 0x04
int someVar; // 0x0040010 + 0x08
int someVar; // 0x0040010 + 0x0C
int someVar; // 0x0040010 + 0x10
};
aStructure someStruct; // 0x0040010 // This address changes each time the executable is ran
Multi-level Pointers
Refinding each address every time you launch your game would be extremely annoying to say the least. This leads us to the other major reason we use pointers. A lot of the time you can easily find static pointers to your pointers. A static pointer is set once the executable is compiled and does not change after that. This lets us reuse the same address until a game update is released.
Okay, how do you find a static pointer to our object? Think about it. If a pointer points to our object, then the pointer’s value must be equal to that object’s address. It’s as easy as doing a mmemory scan for it!
In cheat engine, a green address represents a static address. So for me (and you if you’re running the same version of FTL!) the static pointer is 0x8C548C (or FTLGame.exe+4C548C if ASLR is enabled on your PC)
Common syntax you will see is an address surrounded by brackets. This designates that we are reading the value of that address.
For example:
Knowing that the fuel is at an offset of 0x494. To read our fuel value with the static pointer we found we would use this notation:
FTLGame.exe+4C548C is our static address
[FTLGame.exe+4C548C] is our object pointer address
[FTLGame.exe+4C548C] + 0x494 is our fuel address
[[FTLGame.exe+4C548C] + 0x494] is the amount of fuel we have
Digging deeper into our object
Let me introduce you to the structure dissector (CTRL+D from memory view)
This handy tool makes reversing structures insanely straightforward. If you have yet to use it, a brief summary would be: you give it a pointer -> define a new structure (ctrl+n) -> explore the data and figure out what does what. The standalone equivalent is ReClass. Solid tool from my limited experience, however I prefer CE’s dissector.
Identifying the juicy parts of any structure is practically the same methodology you would apply to a normal memory scan. Search. Change. Search Again. Unfortunately you will be doing the searching manually.
Scrolling down until we reach 0x494 you should notice a couple things.
-
It’s realllly far down. Yes. structures can be massive in size. and unfortunately the dissector doesn’t always guess the data types correctly. So be wary of odd looking types that could potentially be something entirely different. Don’t be afraid to play around with it.
-
You can see your money right below it. This isn’t a conincidence. Pertient data is commonly grouped closely. That makes our eyes valuable in identifying useful variables.
Some other tips for dissecting structures
-
The first couple addresses of an object are often virtual tables. I won’t go into detail here but a quick google search will provide you with more than enough information. These vtables can be quite useful.
-
Doubles are usually 2 seperate Floats Most games tend to use floats rather than doubles so you can quickly eliminate any data types you see marked as such.
-
Get familiar with how certain data looks in the dissector Compile some applications in C with debug symbols enabled and toss them into cheat engine. This is hands down the best way to learn how to reverse structures. Find out what an array looks like in memory. An array of pointers.. etc.
Bringing it all together
By now I have played around with the structure a bit and put all the compelling data into some pseudo structures.
#define OFFSET_BY(X) private: char _filler_ __LINE__[X]; public:
class BaseSensor;
class ShieldSensor;
class PilotSensor;
class WeaponSensor;
class CharArray;
class CharPtr;
class Char;
class FTLObjectPtr {
FTLObject* ftlObject; // 0x00
OFFSET_BY(4);
CharArray* charArray; // 0x08
};
class FTLObject {
void* VTable1; // + 0x00
OFFSET_BY(4);
void* VTable2; // + 0x08
OFFSET_BY(0x0C);
BaseSensor** SensorArray; // + 0x18
BaseSensor* oxygen // + 0x24
BaseSensor* teleporter; // + 0x28
BaseSensor* ???; // + 0x2C
BaseSensor* battery; // + 0x30
BaseSensor* ???; // + 0x34
BaseSensor* clonebay; // + 0x38
BaseSensor* hacking; // + 0x3C
BaseSensor* ???; // + 0x40
ShieldSensor* shields; // + 0x44
WeaponSensor* weapons; // + 0x48
BaseSensor* drones; // + 0x4C
BaseSensor* engines; // + 0x50
BaseSensor* medbay; // + 0x54
OFFSET_BY(0x43C);
int Fuel; // + 0x494
OFFSET_BY(0x3C);
int Money; // + 0x4D4
};
class BaseSensor {
OFFSET_BY(0x28);
char[0x28] name; // + 0x28
unsigned int assignedPower; // + 0x50
unsigned int maxPower; // + 0x54
};
class ShieldSensor : public BaseSensor {
OFFSET_BY(0x1EC - sizeof(BaseSensor));
unsigned int shields; // + 0x1EC
unsigned int maxShields; // + 0x1F0
};
class WeaponSensor : public BaseSensor {
OFFSET_BY(0x1E8 - sizeof(BaseSensor));
unsigned int missiles; // + 0x1E8
};
class CharArray {
OFFSET_BY(0x3C);
CharPtr** charArray; // + 0x3C
};
class CharPtr {
OFFSET_BY(0x20);
Char* character; // + 0x20
};
class Char {
int x; // + 0x18
int y; // + 0x1C
OFFSET_BY(0x08);
int health; // + 0x28
int maxHealth; // + 0x2C
OFFSET_BY(0x2A4);
char name[0x1]; // + 0x2D4
};
The char Y[X];
’s are absoluetly necessary for this kind of class definition. It’s how we offset memory in our structure. A character array of size X will offset us by X amount of bytes. A long integer will offset by 4. If you are unsure how much memory any data type uses, sizeof(type) will tell you.
Iterating the object’s arrays
blah blah talk about sensor arr + power manipulation
More fun stuff
blah blah create lua scripts show character struct pos tping + setting abilities
Saving our cheat table
blahblah