Back to my late teenage years I began developing an app to modify, enhance, and cheat Mac games. After struggling to come up with a good name, my friend Dylan named it Bit Slicer (nobody liked my “XZCheat” prototype name 😅). Fast forward 10 years to now, Bit Slicer has become one of my most beloved applications that I have poured a lot of my soul into. To celebrate its decade long anniversary, let me start with how it began.
Back in the Mac OS X Leopard era (2008) when many of us were still on PowerPC machines, several of us spent an obsessive amount of time modifying and adding content to a video game. We had a thriving community of tinkerers and programmers alike. We made great achievements by altering game data files on disk, but some of us also desired the possibilities of modifying the game while it was running.
A small number of us at the time experimented with using the “Legendary Game Trainer for Mac OS X” – The Cheat:
Inspired by Pandora’s Box for Mac OS (1996), The Cheat enables searching and narrowing down variables that can later be altered. A basic scenario of how this works: if a player has 1378 coins in a side-scrolling game and searches for this value in the game’s memory, they may get 1,000 potential results. When the player gains two more coins and narrows down which of the previous results are now 1380, they reduce or narrow down the set of potential results. By repeating this process, they may find the single variable address that represents their coins and then alter the value to give themselves 9999 coins.
We loved using this utility. We discovered and applied new hacks that were not possible via other methods. It was sophisticated by providing a variety of data types and operators. It enabled us to save and share modifications to others. It also behaved like a native Mac application.
Unfortunately main development on The Cheat halted and newer issues crept up in newer released operating systems. I dug into the codebase and made patches to resolve the issues I encountered for a while, but eventually ran into feature limitations that warranted me to ditch the beloved utility and present alternatives like iHaxGamez.
In a couple weeks, I developed a prototype which lead to an eventual shipping version of Bit Slicer. It had a user interface that on the surface looked similar to The Cheat above and covered most of its functionality.
In its initial release, Bit Slicer also allowed users to add variables at specified memory addresses manually without first searching for them, and allowed searches to be preserved across different or re-spawned processes. Without going into elaborate detail, these two enhancements assisted me in enabling a hidden option in a trial version of a game.
Bit Slicer was thus produced to fulfill my desire of enhancing games in new ways with a long journey ahead of it.
A few months after Bit Slicer’s initial release in September 2010, a new user began the following email exchange with me:
loco: Hey there, I saw your bit slicer project today, finally someone is making an effort in making a better memory editor for mac. I saw your sources and binaries are only for 10.6. Is there any way for me to compile it so it runs on my 10.5
Zorg: Hey. Sorry, but Bit Slicer will not run or compile on a OS lower than 10.6 because it uses features and API’s that became available in 10.6
loco: That’s too bad… Thanks for the speedy reply anyway! Great work on the release though! I have a suggestion if you haven’t included it yet. Allow it to start a search for an unknown variable, and then look for changes as you normally would. There is no program for mac by the looks of it that lets you do this.
A couple months later, I added a feature to search and compare values based on a previously taken snapshot of a process, and loco upgraded to macOS 10.6. Loco tried out the application to his delight and then invited me to have a dedicated section on PortingTeam (a Mac porting focussed gaming forum). I gained more feedback from users, shared my progress, and released beta versions there. I made some great connections and friends including loco. This was the start of Bit Slicer’s life-cycle.
I took a tangential break after adding features such as pointer references, byte arrays, and a memory viewer. I became obsessed with playing a short side-scrolling game called Doukutsu Monogatari, or better known as Cave Story (it’s a really good game by the way). Shortly later, I was introduced to assembly languages in one of my courses. Some peers thought the material wasn’t very practical, but it intrigued my unawareness of how code is executed on a lower level.
Out of curiosity, I used a tool bundled as part of Xcode to disassemble Cave Story. Lucky for me, all the debug symbols were available. So I found a procedure with a corresponding symbol named like “DamageMe” and peeked at the assembly instructions that were decrementing a value and writing its result to an address in memory. I thought, what if I can make these instructions do nothing instead? With a hex editor, I went to the location of where these instructions resided in the binary and overwrote these instruction bytes with 0x90’s (a no-operation opcode on x86).
To my amazement, my experiment of changing the code worked and my player could no longer be hurt. I also found a more practical way to find the instruction without using symbols (which are not always available). After searching for the player’s health using Bit Slicer, I set a watchpoint using gdb on the memory address to find what instruction was writing to the value when it had changed.
I soon began to debug other games like this by setting watchpoints and breakpoints, but gdb wasn’t very fun to use and lldb wasn’t very mature at the time (late 2012). These debuggers are also not very approachable to many game tinkerers. So I went on a long journey of adding debugging capabilities to Bit Slicer.
I spent a few weeks researching how to achieve this. I found a x86 disassembler library to disassemble instructions I read in from a process’ virtual memory. I scrambled throughout the internet finding scarce references on implementing an exception handler that attaches to another process. I found private system APIs to set and get register states from a specified thread. I made sure to understand how to manipulate debug registers for setting watchpoints and breakpoints. I read how to implement backtraces and instruction breakpoints from the web and through gdb and lldb’s source code. I learned about debugger edge cases such as stepping out from a recursive function and heuristics such as deciding where to start disassembling instructions efficiently. I learned how to identify code and data segments, identify which variables are static across runs, and how to relativize variables based on address space layout randomization.
After a long amount of dedication, I ended up writing debugger level features as part of Bit Slicer version 1.6 and later enhanced by 1.7. Users could now find the instructions that accessed a variable, overwrite existing instructions, view the disassembled code around them, or set breakpoints to debug their games. Version 1.7 also later enabled injecting new assembly code into a process and writing scripts to automate searching and debugging tasks.
To reflect on my dedication involved, I estimate these two major versions combined took around 12 months of hard work to reach their point zero releases. Some weeks I was working for many hours daily even when I held a full time position. I recall having two distinct 40-60 day coding streaks on GitHub. This wasn’t always a daily endeavor, but I may have lost a little sleep for some of the time 😅.
User interfaces are very crucial but often neglected. Many applications act the way they do because its developers are influenced by prior experiences. Imagining new ways that simplify interfaces and maintain power is no simple task. If the majority of users are asked what they think of an existing application’s user interface, they may exclaim it’s great. But the same users will also change their minds once they experience a simpler and more powerful design. And after a new design comes out, it becomes ingrained again and suddenly becomes the obvious way such applications should function.
I am not immune to this problem. Initial versions of Bit Slicer looked and behaved similarly to The Cheat, which was influenced from an application before it. Other game cheating software on other platforms have similar influences from a long tail of software before it. From Bit Slicer’s initial release, however, I made one significant design decision contrary to popular trends.
For a little background, The Cheat and other popular alternatives actually have two tables or views that users use. One table populates the memory addresses and values when memory scans are performed. The other table is purposed for variables that the user chooses to apply cheats to. So with The Cheat for example, users search for their desired variable in one table and then add that variable to another table where they can alter it.
The biggest distinction I made from the beginning was choosing not to have two different tables. Bit Slicer is the first to unify searching and altering values while still providing a great amount of flexibility. Users can search for variables and then edit variables at any stage in the search. They can add and remove variables at any point. They can change a variable’s data type. They can mark variables to be preserved and excluded from newly performed searches. Two tables were simplified and purposed into one while retaining the power a user may expect:
While developing version 1.7, I gained inspiration from an experienced Mac developer to re-invent the user interface. The user interface in version 1.6 above had a number of issues that went long ignored. Controls did not extend well when the window grew big or became fullscreen. Some spots in the window had awkward dead space. The window was becoming cluttered with controls and adding any additional options would complicate it further. The searching progress bar was always visible taking up space and looked unnatural. After considering all of these issues, I have thus ended up with the following interface:
The table became the primary focus and changed to stretch the entire window. All the primary options became placed in the very top toolbar along with a natural behaving search field. Search and cancel/clear buttons are no longer separate and are now part of the search field. Additional but rarely used options are accessible from the advanced gears option in the bottom left instead of cluttering the search window. The search status including the numbers of variables displayed is now updated in the center bottom status bar. Descriptions became auto-populated with useful metadata.
The searching progress became de-emphasized. Instead of a big progress bar, a small circular progress indicator now appears in the bottom right of the status bar while a search is occurring. Because searching became more efficient in 1.7, the progress indicator also does not usually appear for a very long amount of time and otherwise stays out of the way. Furthermore, the progress of searching feels more responsive and pleasing because 1.7 shows variable results as the search is progressing instead of only when the search has completed.
The new user interface was a breath of fresh air. While Bit Slicer still has questionable design concerns, nobody desired to go back to the way older versions acted.
While Bit Slicer has an uncertain future due to various reasons including my time spent to maintain it, I am thrilled it has been serving users well for a decade.
As a side project, I gained better expertise in reverse engineering and producing user end applications, which has helped me immensely. Similarly, the project has aided many others, including friends of mine, into learning how to debug software on a lower level.
Bit Slicer has been referenced in YouTube videos, blog posts, and security talks. It has been used heavily by a younger audience to just apply their favorite cheat mods, and by a more technical audience for analyzing a program’s memory structure in depth. Its source code has been used to help others understand how it functions; its code has helped others make their own programs, even including commercial ones.
To this day, curious tinkerers still utilize the application and ask questions regarding it use.
A developer once asked me how I motivated myself into spending a couple thousand commits worth on developing this application.
I do not know the all encompassing way to respond to that question. But I do know I had fun modifying video games and I wanted to make that task more feasible.