Saturday, November 28, 2015

Adding Keyboard Support to a Crazy Taxi Clone

Note

I've wanted to do a blog/tutorial on how to add keyboard support to arcade games for a while - this game in particular was extremely easy to write a library for which is why it was selected - global names are not stripped, it's modular, runs on a modern OS - we'll focus more on strategy and technique rather than having to wade through obfuscation first. In practice, this is the same method I use for much more difficult games. 

Background

There are a vast assortment of arcade games - some well known, others super obscure. Although security is one component of getting a PC-based arcade game to run natively on a modern PC, what good is it if you can't actually play it?

A number of these games had a limited release, ran on dated hardware, and will eventually be lost deeper into obscurity - let's do something about that!

That said, let's dig up a strange one and give adding keyboard support to it a shot.

Frenzy Express


Ok, now we're in strange territory - this game came out in 2001 as a blatant ripoff of crazy taxi: the player races around town avoiding obstacles; collecting time and power-ups while stopping at pickup points and dropping them off across town. Given that this is a scooter and not a taxi, packages such as flowers, toys, and important documents (whatever those are) are carted around while the player tries to make 15,000$ to go on vacation.


First Time Run

The game itself runs fine without any security-related modifications (even on Windows 10). Of course, no input works besides the common exit keys (ESC or F12 - in this case, it's both).


It starts with a simple calibration screen that errors, but doesn't stop the game from proceeding. Eventually, we'll get this working perfectly as well.


We then hit the attract mode loop and everything seems to be working fine - albeit lacking input.

Ok - let's dig into this!

The Files

The files I have are from a Frenzy Express 2.0 Hard Disk - if you can find someone to get a copy from, follow along :)

There are two disks - G and H:

H has a rather small copy of windows (looks like Windows 95 or some other 9x):


G has two items in its root - a directory named 'FRENZY' (where we'll be spending all of our time) and WIN386.SWP (a swap file). The FRENZY directory can be taken out of this structure and placed anywhere - all paths are relative to the game.


The Frenzy directory contains a gl folder with textures, models, etc. The 'show' directory contains MP3s for music (I wonder if they have a real MP3 license...), The history folder has two files which are replay data for the attract mode and how to play, the sound folder contains all the effects, speech, etc., and the rest of the files are either dlls for various components of the game (sound, video, IO), the game executable itself (xwin.exe), or an x.cfg file which is probably game data. I'm guessing that boot.exe does something system-related, although I never looked into it.


Well... next step!

IDA

First, we should dive into the xwin.exe file - after all, this is the entry point for the game. However, a file named xio.dll might be interesting as well - perhaps the developers made the input modular. Jumping to the import table, it looks to be that way:


We have an XIO object that contains various functions for interacting with the IO (getting and setting along with some reset and initialization logic), it looks like we also have some globals as well (wow, could they have made this any easier?!).

Jumping into the XIO dll, we see that methods names are left intact (could we be any luckier).

Putting setVibration into hexrays, we see a few common elements:

A number of functions are simply void returned calls to do something to the internal state of XIO and/or talk to the hardware (we'll jump into this in a second).


This looks like it's checking some value and if it's 0, it sets the value back to a default of 3. After all of this , it calls that sub at the bottom with a 6XX number and the value we're passing.

This looks like some kind of write function - we have the 9x direct hardware access __outbyte here on a conditional. It looks like if the dword at the top is set, it will run another function but if not, it will push the value to hardware directly. At this point, we can assume that the dword at the top is a flag if the OS supports direct hardware access (any Windows before NT).


A quick look at  that upper sub confirms - this route uses DeviceIoControl to make the hardware call indirectly (think ioctl for Windows). Just to be sure - let's xref that dword in the previous function to see where it's set:

Makes sense - the GetVersion() line where it checks >= 0x80000000  is an old trick to determine if a Windows version is NT or later - they don't support direct IO access due to a number of issues unless it's from a driver.

Ok, so we have the general idea of how it writes - xref'ing DeviceIoControl again we find the read function:


Given that we have the general idea - we can now determine that the IO setup of this game works in a pretty straightforward fashion (game <---> xio.dll <---> hardware).

For clarity, we may want to build a struct in IDA to list the properties that we see (using the logic that a function like setSteeringBar will talk to the struct members that have to do with steering data, lamps with lamp data, etc).

We get something like this:


And when we run in hex-rays, things look a lot cleaner:


From this point, we should start first by trying to get to the operator menu or inserting a coin - any of the basic non movement-oriented inputs... just to get a feel for what we'll be doing the rest of the time.

Coin and Operator Menu

The game makes several calls to xio::update() - several due to the fact that it's responsible for updating all the states:


Right off the cuff - we notice that g_bKeyExec & 8 (or the 4th bit of that value) is a conditional to update the coin counter - looks like we found our coin button.

Looking deeper into the update input state, we can see that various bits are set to control buttons:


Looks like this byte controls buttons (more than likely the operator menu, coin drop, start, and the arrow keys on the machine).

To test this theory, let's use CheatEngine to mess with the values and see what we can have happen. First, however, let's force this thing to Windowed mode so we can more easily change values and debug on a single screen.

Hacking in Windowed Mode

First of all, the game contains a call to ChangeDisplaySettingsA to force 640x480:

We can easily nop out this function with no real issues (although the screen test on startup might show that it failed - whatever, doesn't matter).

The REAL meat and potatoes comes from CreateWindowExA: 


This is where it pulls the current screen resolution (1920x1080 for me) out and sets the window to that size. Unfortunately for us, the game at this point will render a big black window with the game sitting in the lower corner - not exactly what we want. Let's force this to statically render a window at 640x480!

The trick here is we need some bytes to play with - push eax for height and width are only one byte - the function call won't give us enough bytes to push a two byte value like 640 into it like that as those are at least 4 bytes:

However, we don't need GetSystemMetrics for width or its parameter index - so we have 5 bytes extra... still not enough.

Provided registers are not reused, we can use the GetSystemMetrics call above the other set values (the one for height) and keep it in the proper buffer with a bit of rewriting and move everything up the few extra bytes we'll have - provided the stack stays in good shape, we should be fine doing this:

The result:



There we go - it should be in windowed mode now; although the top will be cut off a bit because I changed the windows style to have a border so we could move it - no matter.


Fuzzing with CheatEngine

I love this thing - hats off to the team that made it. It's more than just for trainers, it can scan for codecaves, nop out variables being set, scan memory and update in realtime. It's a very useful tool for Windows debugging and fuzzing.

The first thing we'll want to do is find out where in the game the g_KeyExc variable is stored.

From this point, we can fire up CheatEngine and add it as a variable to watch:

While adding an address manually, we tick the pointer checkbox, set the value to byte, and put the address in below:


We fire up the game and attach it to cheatEngine and we see that the value is just sitting there - makes sense.
Now, we could try to modify the value, but remember that this is an IO set value - it's gonna be firing like every X milliseconds so it will quickly get overwritten - we need to first shut the IO library up so we can set it ourselves.

If we right click on the value, we can select 'Find out what writes to this address'.


The top one looks like it writes a lot - we can select Add to the Codelist to keep track of it and give it a fun name. In addition, if we right click on the line in the Code List, we can select 'Replace with Code that Does Nothing' and it will NOP this value being set for us - it can be restored later as well.

Now, if we set the value to 8, a coin should be dropped:



Success!

If we wanted to get even more fancy with testing, we could hook up some rudimentary input support via CheatEngine's LUA scripts, add keyboard handling to set the bits, etc, but I'll leave that up to the reader (I actually did this but I lost the lua script file, haha).

Writing the DLL

Ok, now that we know the base layout of all the dll calls the game makes, we can construct a dll based on a similar XIO object and replace the calls to hardware with scanning the keyboard. However, doing this would be (and was) an unnecessary task

*** IMPORTANT LESSON ***

One of the biggest challenges a lot of reversers face in the beginning is going too granular - sometimes it's necessary, yes, but in this case, replacing all the DeviceIoControl calls in unnecessary given the context of the game - the game itself reads from the globals mostly and sends some information back to the hardware, but we don't really need that - we just need to tell the game which values we want which is why CheatEngine fuzzing is a valuable step - it will let us see what values per the globals affect the game. In fact, I added all the globals to a CheatEngine table:


With that said, I did originally map out the device calls in the original dll (found on my github page: https://github.com/batteryshark/feXIOEmulator), but due to the convoluted way values are passed around - weird stuff happened: the steering wasn't working properly, the brake made the handlebars jam to the right when you let go, and acceleration was unplayable as the scooter went careening at warp speed toward the nearest objects.



Looking at the whole thing again, and making some modifications, the game really only needs a few exports:

It needs the various globals such as brake velocity, button state, acceleration, etc.
It needs to be able to open and close the interface (basically left blank for us because there's no hardware to make a device file for), it needs to update all the values, and get / set certain values... That's pretty much it.

The current I/O library as of this writing can be found here: https://github.com/batteryshark/feXIOEmulator

The dllmain is a simple dll entry point - nothing special.

The real meat is in the XIO.cpp and XIO.h files - the header like usual lays out the groundwork for the XIO object, and the  cpp file contains most of the logic (including the keyboard logic):



It's always important (especially if you're putting something up on github) to comment the living shit out of a library, especially when reversing. This way, you can catch logic errors or even data type errors.

If we were to, say, give lampState an unsigned char value (even though it shouldn't be an int ever) in XIO::selectLamp:

The game would refuse to link with the mangled name because it would be:
?selectLamp@XIO@@QAEXE@Z
instead of
?selectLamp@XIO@@QAEXH@Z

It's important to check the mangled names the game wants for hints as to the data types that go into a function if the names aren't stripped - in this case, they weren't. It's also important to name the functions the same unless you're using IAT_Patcher or something of the like to change the name in the binary itself. In this case, we don't need to.

Keyboard Input

All this time and no talk about Keyboard stuff yet - what am I doing? That's because the keyboard part itself is easy (besides maybe some hardware-side logic like analog stuff that we'd have to emulate in code) - figuring out what to hook it all up to is the challenge most of the time:



For this game, I used GetAsyncKeyState, I made a couple of defines myself, and set the bits I needed to set for each member function to do its thing. Remember, the original hardware could only send 1 byte back at a time and it only called once - so values are very small (some between 0-64 or 0-255).

This is where iterations upon iterations of tests come in. Set a value, launch the game, go into the operator menu / gameplay and see if it acts how you want it to act - rinse and repeat.

After a while, you'll get something like this:



Conclusion

Input writing for arcade games can be a fun battle back-and-forth with granularity, original intent, and other factors when you don't have the original hardware or have never even seen the machine itself, but the steps to figuring out what a game does from an unknown data source are all pretty much the same. If all else fails - debug, fuzz, fuck around with shit - see what happens. In the end, you might just get it working :)

Cheers!


Friday, October 3, 2014

Hacking 'I Wanna Be The Boshy' Game Saves


Background

It seems that the world missed the "good ol' days" of ridiculously hard platform games. Games that were made difficult mostly due to the fact that they had to be short to fit on a cartridge. Years ago, a guy known as Kayin created a game called "I Wanna Be The Guy" - a masochistic game to show us just how insanely difficult developers could make platform games.

The game is known for being legendarily difficult; sporting difficulty options for no saves, longer boss battles, and countless "gotcha" moments. Essentially, a compilation of ripped assets from roms to create something ridiculously difficult, but insanely fun:

Anyone who played IWBTG remembers the goddamned spike corridor at the bottom, lol.


Eventually, this went on to inspire a more polished indie game called:


Who dialed back the difficulty a bit and brought it more mainstream.



Eventually, this wave of super hard "throwback platformers" even reached Capcom when they developed 

and


... further proving that, not only can they still make nail ripping-ly difficult platformers, but are still pretty damn good at it.



During this time period, a guy who goes by the name of Solgryn developed a game much like "I Wanna Be The Guy", but added multiple characters:



And online play as well:


It's also much longer and calls itself "I Wanna Be The Boshy"


The game runs on Multimedia Fusion 2's engine - a staple for a lot of platformer indie games.

During a playthrough, I wondered what the game save format was like and if values could be modified to fully unlock the game and set options passed their normal limitations. 





The Save Format

By default, data is passed around in MMF2 in ini files - IWBTB is no different:



Unlike normal ini files, however, these are encrypted...

After running procmon to take a look at this massive 130MB executable, we can see that it unpacks itself and operates out of a directory...



In the directory, we see a whole bunch of mfx modules which are basically renamed .dll files. The most interesting of which is INI++... what could this be???


oh...
ooohhh....

OH!



Ok, so we have a custom module that basically acts like a read/write wrapper for the normally plaintext ini files, takes a password, and encrypts the data. It also supports MD5 hashing without changing the size of the output file (from the site).

Well... if  that's not information bleed...

So we have this crypto that is the same size as plaintext (meaning no key or salt attached to the encrypted data) and theres a password that somehow encrypts or decrypts it. Yay stored secrets!!!

Throwing their dll in IDA will get you something like this with IDAScope (I used it to see what crypto modules they're using):

Ok... just the MD5 inits - well, they already said they had the ability to store hashes of the strings instead, but MD5 is one way so thats no way to encrypt something (doesn't do ya much good if you can't recover it, haha).

So no fingerprints of a common crypto interface - looks like someone wanted to hand-roll their own crypto... the only thing someone should roll about that is their eyes (lel).

Well , guess it's time to start digging for "crypto" functions in the binary (Hint: just look for a bunch of bitwise operations and stupid array shaking).


....aaaaaand pwnt.


Alternatively, you could also just find that an open source python impl of MMF2 is online called anaconda. They happen to have this extension module already converted.


With this, I could make a python tool to encrypt/decrypt the data:




So now we know the algorithm... but we still don't know the damn password! Fortunately, MMFS2 is publicly available and so is this plugin.

Getting The Password


After making a small test project that simply starts and writes an ini file with some data into an encrypted file, I find that the password allows no special characters and one line.



I compiled my project and set out in its running memory to find my password in plaintext because... #YOLO I guess...




Doing the same thing on IWBTB will net you a lot more text, but looking near the areas in memory where I found my password, theirs stuck out as well






The result:

The src below will decrypt/encrypt any of Boshy's INI files - the algorithm is reversible... just run again to re-encrypt. Decrypt a fully unlocked save available online if you want :)

Fin