- Published on
Exploring LLDB: Modifying In-Game Coins in a Mobile Game
- Authors
- Name
- Posa
- @_bellaposa
Introduction
LLDB is a powerful tool used by developers to debug and inspect programs at a low level. It provides the ability to monitor and manipulate registers, memory, and program flow, making it invaluable for identifying bugs and testing specific conditions. In this article, I’ll walk you through how I used LLDB to hack the coin count in a mobile game.
While I won’t disclose the name of the game, I can tell you that it’s a physics-based game where you control a car as it drives through various terrains. The objective is to collect coins in order to power up your car, improving its speed, handling, and other performance attributes. Along the way, you may also encounter gems, though I won’t be covering them in this article.
During my exploration, I used Hopper, a reverse engineering tool, to disassemble and analyze the app. Through this process, I discovered an interesting function, which seemed to be responsible for adding coins to the game.
Once I identified the function, I used LLDB to set a breakpoint, inspect the registers, and modify the coin count, successfully altering it to millions — all with just a few commands.
The Setup: Finding the Right Function
The game’s core mechanic revolves around collecting coins as you race through different levels. These coins allow you to upgrade and power up your car, enabling you to reach further and unlock more challenging areas. By using Hopper, I was able to identify the addCoins(int)
function, which is responsible for adding coins when certain actions are triggered, such as hitting a coin on the track.
By analyzing the assembly code, we can see that the w9
register holds crucial information—specifically, the coin count in the game. The code contains several key instructions, including comparisons and a conditional select operation. These operations caught my attention, and I decided to dive deeper into understanding what’s going on with the w9
register.
Why This Caught My Attention:
The combination of comparing the coin count and selectively adjusting it using conditional logic in the csel
instruction made me realize that the w9
register holds more than just the current coin value—it's the point where the game ensures no illegal values are stored. This made me curious about manipulating the value of w9
directly.
Once I identified it, I used LLDB to set a breakpoint at its address:
(lldb) b 0x1002f8a38
Setting the breakpoint would allow me to halt the program when the function was called, giving me the chance to inspect the registers and understand how the coin count was being handled.
Listing Breakpoints and Continuing Execution
After setting the breakpoint, I used the following command to list all active breakpoints:
(lldb) breakpoint list
This would show me all the breakpoints set in the current session, along with their addresses and hit counts. For example, here’s what the output might look like:
2: address = 0x00000001002f8a38, locations = 1
3: address = 0x00000001002f8a24, locations = 1
4: address = XXXX XXXX XXXXX[0x00000001002f8a38], locations = 1, resolved = 1, hit count = 1
When I hit a coin in the game, the breakpoint triggered, and I could inspect the program’s state.
To continue the execution after halting at the breakpoint, I simply used the (c)ontinue
command:
(lldb) c
Inspecting and Modifying Registers
LLDB allows you to read and write the values of these registers, which is essential for hacking and debugging.
Reading Register Values
To inspect the value stored in a register, you can use the register read
command. For example, to view the value stored in register X8
, you would run:
(lldb) register read X8
LLDB will output the register’s value in hexadecimal format:
X8 = 0x0000000104945000
Next, I read register W9
to check the coin count before hitting the coin in the game:
(lldb) register read W9 --format d
The output was:
W9 = 2881
This value represented the number of coins before interacting with the game.
Modifying a Register
One of the most powerful features of LLDB is the ability to modify register values. In my case, I wanted to change the value of W9
(the coin count) to a much larger number, so I ran the following command:
(lldb) register write W9 2000000
This command updated the value of W9
to 2 million coins.
Verifying the Change
To verify that the change had been applied successfully, I read the value of W9
again:
(lldb) register read W9 --format d
The output now showed:
W9 = 2000000
The coin count had been successfully updated!
Resuming the Game
After modifying the register, I resumed the game’s execution by running the continue
command:
(lldb) c
The game continued running, and I could now enjoy my newly acquired million coins — virtually, of course!
ASLR
Before we start setting watchpoints or breakpoints, there’s one more very important thing we need to address: ASLR (Address Space Layout Randomization) slide. ASLR is a security technique used to randomize memory locations, making it harder for exploits to predict where specific data or code is located in memory, and thus preventing certain types of attacks.
I won’t go into too much detail here, as there are plenty of resources available on Google if you want to learn more. A quick search should be enough to get you up to speed.
Now, the lldbinit
script will be extremely helpful when dealing with ASLR. Without it, we would have to take a more complicated approach, such as performing an image dump of the application sections and manually calculating the delta based on the values returned by the dump.
For example, we could use the following lldb
expressions to adjust for the ASLR slide:
expr int $delta = 0x102c2c000
p/x $delta + 0x1007fad8
This process involves manually adjusting the addresses, but with lldbinit
in place, we can automate this step, making it much easier to handle ASLR and continue our hacking process smoothly.
Conclusion
LLDB is an incredibly powerful tool for debugging and reverse engineering, providing developers with deep insight into the inner workings of a program. By setting breakpoints, reading and writing registers, and controlling program execution, you can manipulate the behavior of an app in ways that might otherwise seem impossible.
In this case, I used LLDB to hack the coin count in a mobile game, turning a simple gameplay mechanic into a source of unlimited wealth.
Whether you’re a developer looking to debug your own code or an enthusiast exploring the world of reverse engineering, LLDB offers the tools to understand and modify program behavior at a very granular level.
Sources