Hacking Games for Fun and Profit

While chilling in a voice chat, one of my friends suggested we play Chained Together. If you haven’t tried it, it’s a game on Steam where all players are literally chained together, and you have to climb up without dragging each other down. Sounds simple, right? Yeah… not so much.
It didn’t take long for the game to get on my nerves. One misstep, and we’d all come crashing down. bad jumps, bad timing, and the constant struggle of coordinating with teammates who seemed determined to make things harder. Instead of suffering through it, I figured… why not take the easy way out?
So, I decided to hack the game 😉 .
The most important thing in this game is height, everything revolves around how far up you can climb. If we could find where the game tracks our height, we could manipulate it to skip the struggle entirely. No more falling, no more frustration

Now that we’re ready to start, we fire up the golden tool—Cheat Engine. Since Chained Together has no anti-cheat, we don’t have to worry about getting kicked or banned, making this process much easier.
Finding the Height Value
Since height is the most important variable in this game, our goal is to locate where it’s stored in memory. However, there’s a small problem: we don’t know the exact value of our height. Unlike things like health or ammo in other games, height isn’t displayed as a clear number.
That’s where searching for unknown values comes in.
Unknown Initial Value
In Cheat Engine, we attach to the game process.
Since we don’t know the exact height value, we select "Unknown Initial Value" as our first scan type. This captures all possible values in memory.
Most of the time, height values or coordinate values in games are represented as float. So, we use the Float data type .

Filtering the Results
We move up to a higher area, then return to Cheat Engine to scan for values that have increased.

Next, we go down and scan for values that have decreased.

It’s also better to use "Values Not Changed" to further reduce the results. Additionally, using hotkeys speeds up the search process, eliminating the need for manual clicking.
By repeating this process, we gradually narrow down the results until we identify the memory address storing our height.
When we get 200 results or fewer, we try freezing 20 at a time. This helps avoid breaking the game’s physics while checking if our height remains the same when moving to a lower area

And voilà! We've found the address responsible for height. Now, if we change it to 6.9, let's see the result!

the issue is that the character jumps very high but then comes back down. This happens because the next instructions are overwriting our change, so we need to find another way.

Now, what we do is left-click the height address we found and select "Find out what accesses this address." This will open a new window that shows all the instructions or code that are modifying or interacting with the height value. By reviewing these instructions, we can better understand how the game handles and changes the height, which can help us find a more permanent solution.

When jumping, we can see that our address is being accessed by several instructions. However, the last two are the ones that access the address only when we move or jump. The other instructions access the address regularly, Let's investigate those last two instructions further.

The height value is stored inside an XMM register, which is used for handling floating-point values in the CPU and are commonly used to store high-precision numbers like floating-point values.
Let's investigate this register further to understand how it’s being manipulated.
XMM registers are different from regular registers. To inspect them, we must click the "More Options" button and then press the F key, which will open a window displaying all the XMM registers and their values. In this window, we can see that XMM0 and XMM1 contain our height value.

So, how do we manipulate them? Well, we can't directly manipulate XMM registers, so we use a code cave. A code cave is a small area of unused memory where we can insert our own code. We replace the original instruction with a jump to our controlled function, where we change the value. Then, the function returns to complete the normal flow of the program.

then we select AOB injection

first we allocate memory for our data values
alloc(our_add,$400,INJECT)
Here we define our custom floating-point values that will replace the game's original values.
our_add:
dd (float)0.10
dd (float)9.41
dd (float)0.00
dd (float)0.00
then we loads our custom values into the xmm0 register and writes them to the same memory location the original instruction was targeting then jumps back to continue normal game execution
newmem:
code:
movaps xmm0, [our_add]
movsd [r10+r11*8+10],xmm0
jmp return

and after enabling it... boom! The height value is now successfully manipulated. and we’re at a height of 9.41, which is heaven or the highest point!

PoC