Skip to content

[Memhack] Finding New Data

DasKeifer edited this page Mar 3, 2026 · 6 revisions

Finding New Data

The process for finding new data is largely manual. At a high level, it involves finding memory while running the game and tracing it back to a known object or analyzing the memory of a known object. There are two major approaches discussed here. Each are approaches I have found useful. There may be easier options I am unaware of.

Useful Tools

  • Cheat Engine for viewing, searching and tracing binary data while running the game
  • Memhack Memory Analyzer for more context aware comparison of data if you do not know the specific data you are looking for or trying to see what changes in memory when you do certain actions
  • Ghirda for decompiling the exe for heavy duty tracing through the code. Generally more a last resort or confirmation

Presteps

Step 1: Consider Your Data

The first step may seem self evident but is important none the less. First identify what you are trying to find and consider how you can find it, what you expect the data to be, and where you expect it to live. Consider if there are easier or more unique things you can search for and how you can best modify the values you are trying to find in as much isolation as possible. For many cases this is straight forward enough. Some cases like pilots, its easiest to select a field we can control easily in game such as the pilots name as a key to find them.

For example, reputation I would expect to be an int and live somewhere in or down the line from the main GameMap object. We can control this fairly easily by winning missions with the win command or by selling/buying in the shops

Step 2: Find you Basis

Where is the data likely stored? Make sure you can find the base address for it easily and that it is actually a C++ userdata object and not a Lua object. You can check the object type by just LOG(var) and it will print <userdata> if it is. Then you can use the LOG(itbin.debug.intToHex(itbin.dll.memory.getUserDataAddr(var))) to print the hex address of the data. This will come in handy later

Step 3: Choose Your Approach

Choose to either use Cheat Engine Scanning or Memhack Memory Analyzer. You can always try the other if one is dead ending.

If you suspect the data is in Game, definitely use cheat engine. If its in a Game object such as Pawn, and you know what the data should look like then either approach may work. If its a highly dynamic object or you are not entirely sure what you are searching for in an object, memory analyzer is the best choice.

Cheat Engine Searching

Cheat engine is a great tool and method for exploring the game data and tracing through nested levels of pointers. It will work best for objects in GameMap but can be used for other more stable data structures like pawn and pilots.

Step 1: Scan For Your Data

Now that you know what you are looking for and generally how you will do it, its time to actually search for the data. Open up Into the Breach and Cheat Engine. Attach cheat engine (via the magnifying glass icon) to Into the Breach. Based on the current value for your data, click "New Scan". Most likely this will have a large number of hits. Add more reputation, update the value being searched for then click "Next Scan" to narrow down further. Repeat until you have only one or a small number of changes.

For example, for reputation, I started a game. Open the console and type money 5 in the console. Now my rep is at 5. I searched for 5 in cheat engine (I avoided 0 just because it's so common) and got a very large number of hits. I repeated and had 3 rep. Searched again and narrowed it down to a smaller set but still had a number of them. Repeated one last time and narrowed it down to a single address.

Step 2: Confirm Your Search

Great! Now we have the address... or do we? Let's check! Double click the address in the "Found" window to add it to the address list at the bottom of the window. Double click the value and change it to something else and see if it's updated in the game. If it is, great we found it for sure. If not, then try searching again.

Some values may not be amenable for this. For example, pointers or other values may cause issues if you try to change them. Worst case though the game crashes and you re-search for them.

Continuing our example, reputation is very easy to change. Just set to any other value and it will appear in the game.

Step 3: Trace your Data (to GameMap)

If your data is suspected directly in your object, check the offset of the found data compared to your base object's address. Is it smallish and seem reasonable? If so, note it and continue to step 6. If not, it might not be in the object you thought. Try again or try tracing to a different object like GameMap as described below

If your data is suspected to be in GameMap, we need to trace it back likely through several pointers. This sounds like a gargantuan task, but this is where Cheat Engine really shines. In the addresslist window at the bottom right click the address and select "pointer scan for this address". A new menu with a whole bunch of options will appear. Generally, I will set the "Max different offsets per node" to 50 and the "Max Level" to 4. If you set these large, it can take a long time to run. Run the scan saving to a new folder (it generates a ton of files) and it will show all the pointer chains it found to get to your data. Keep this handy and identify the most likely culprits. Generally, a shorter chain with smaller offsets is more likely to be the one you are looking for. Only consider chains that start in "breach".exe and not other binaries.

It gets a bit trickier when you are tracing relative to an object (e.g. GameMap) instead of the exe offset. How I found to do this is to first find the exe offset of the basis object so you can quickly narrow down the chains based on that or so you can set a filter with the "pointer path can only be in this region" field of the pointer scan. GameMap is stored in the exe at a fixed offset (dependent on version). If you get the GameMap address (LOG(memhack.debug.intToHex(memhack.dll.memory.getUserdataAddr(Game)))), add it to Cheat Engine addresslist ("Add Address Manually" button), and do a depth 2 search, you will see it show up and can see the exe base offset.

A lot of this part comes down to intuition and brute forcing. How big do you expect the data to be? What offsets are reasonable? The GameMap object is quite large and the pawns are surprising large as well

In the instance of Reputation where I wasn't sure, I first checked the memory address compared to GameMap's. It was within the expected size for GameMap meaning it was part of GameMap directly. Nice and easy. No pointer tracing needed.

Step 4: Confirm Your Trace

Repeat scanning several times and keep doing so until you find a consistent chain from your basis. At this point we are nearly done!

Step 5: Quick and Dirty Testing

Close and open a new game. Find and start with your base object and open it in Cheat Engine. Follow your pointer chain you found to the end and confirm the data looks right. Cross your fingers and change the data to make sure it all works. If it does, you got your stable chain! If not, retry from step 3. Keep trying - it can be easy to make a minor mistake that messes things up

Continue onto the Formalize the changes

Memhack Memory Analyzer

The memory analyzer implemented in memhack is specifically made to capture and compare data that is potentially very short lived and, by consequence, hard to reverse engineer in Cheat Engine. It works by taking snapshots of the data then analyzing the snapshots later. It does this based off of offsets so it can be used to compare different objects easily as well which is something not as easily done in cheat engine

Step 1:

Create an Analyzer with a conservative guess for the structure size. Depending on what you are doing, you can do this via the console or in lua code.

memhack.debug.MemoryAnalyzer.new("pilotScanner", 4096)

You can later retrieve it (for using with console) with

memhack.debug.MemoryAnalyzer.get("pilotScanner")

Step 2:

Take snapshots of the memory. Again this can be via the console or in lua code.

memhack.debug.MemoryAnalyzer.get("pilotScanner"):capture(Game:GetPawn(0):GetPilot():getAddress())

Step 3:

Compare the snapshots and look for your data, get the values, and log them

memhack.debug.MemoryAnalyzer.get("pilotScanner"):getChangedEvery(nil, "xpChanges") memhack.debug.MemoryAnalyzer.get("pilotScanner"):addUniqueCapturesValues("xpChanges") memhack.debug.MemoryAnalyzer.get("pilotScanner"):log("xpChanges")

You can later retrieve it (for using with console) with

memhack.debug.MemoryAnalyzer.get("pilotScanner"):getResults("xpChanges")

Step 4:

Quick test you changes by hardcoding your found offsets or by running memhack.dll.memory.writeInt(...)

Continue onto the Formalize the changes

Formalize the changes

Now we have what should be a stable pointer chain. Time to (hopefully) bring it to the finish line

Now you have your chain, its time to formalize it. Add or modify the memhack structs to follow your new chain and add function wrappers for your newly accessible object from you base object. Confirm its all still working and submit a PR!

Clone this wiki locally