Reverse engineering a dynamic library on the Xperia Play

Welcome to part two of my journey to completely reverse the PSX emulator on the Xperia Play. When we last left off, I managed to figure out the image.ps format and the basic order of execution of the emulator. It’s been a week now, and I have more stuff to reveal.

Decrypting the data

One of the main problems was that most of the important files are encrypted. More specifically, these three files: ps1_rom.bin (BIOS), libdefault.so (the emulator), and image_ps_toc (then unknown data). As I mentioned before, Sony used what’s called white box cryptography, which means obfuscating the code to hide the decryption keys. But, we don’t need the keys, we just need the decrypted data. The obvious way of extracting the decrypted data is dumping it from the RAM. However, the Android kernel I’m using doesn’t support reading /dev/kmem and I don’t want to mess with recompiling the kernel. I’ve also tried dumping with GDB, and it did work, but the data isn’t complete and is messy. I used a more unorthodox method of obtaining the decrypted data. After hours of reading and mapping in IDA Pro, I figured out that everything that is decrypted goes through one public function, uncompress(), a part of zlib. This is important, because this means everything that is decrypted is sent to zlib and zlib is open source. That means, I just need to recompile zlib with some extra code in uncompress() that will dump the input and output data. A simple fwrite() will do, as the data is already in a clean, memcpy-able form. (I forgot about LD_PRELOAD at the time, but that might have worked easier). After some trouble getting NDK to compile zlib, I have dumps of both the compressed/decrypted and uncompressed forms of all encrypted content.

Analyzing the dumps

The next thing is to find out the meaning of the data that we worked so hard to get. ps1_rom.bin is easy. Surprisingly, it is NOT a PS1 BIOS file, but actually part of a PS2 BIOS dump (part, being only the PS1 part of the PS2 BIOS). Does this mean a PS2 emulator is coming for the Play? I don’t know. Next, we have libdefault.so. Plugging it into IDA Pro reveals the juicy details of the PS1 emulator. It’s really nothing interesting, but if we ever want multi-disk support or decrypting the manuals, this would be the place to look. Finally, we have image_ps_toc (as it is called in the symbols file). I am actually embarrassed to say it took almost a day for me to figure out that it’s a table of contents file. I did guess so at first, but I couldn’t see a pattern, but after a night’s sleep, I figured out the format of the uncompressed image_ps_toc file. (Offsets are in hex, data are little-endian)

0×4 byte header

0×4 byte uncompressed image size

0×12 byte constant (I’m guessing it may have something to do with number of disks and where to cut off)

0×4 byte number of entries

Each entry:

0×4 byte offset in image.ps, where the compressed image is split

Image.ps format

I actually forgot to mention this in my last post. The “rom” that is loaded by the emulator is a file named image.ps. It is found on the SD card inside the ZPAK. It is unencrypted, and if you delete it, it will be downloaded again from Sony’s servers unencrypted. How it works is that an PSX ISO is taken and split into 0×9300 (about 38kb) sections, and each section is compressed using deflate (zlib again) and placed inside image.ps (with a 0×14 byte header). The offsets of each section is stored in the toc file (and encrypted) because although uncompressed, they’re perfect 38kb sections, compressed, they’re variable sized. I already wrote a tool to convert image.ps to an ISO and back again/

Putting it all back together

Now that we’ve tore apart, analyzed, and understood every element of the PSX emulator on the Xperia Play, what do we do? The ultimate goal is to convert any PSX game to run on the Xperia Play, but how do we do that. There are two main challenges. First of all, libjava-activity.so, which loads everything, expects data to be encrypted. Once again, we need keys. Also, I’m pretty sure it uses a custom encryption technique called “TFIT AES Cipher”, because I was not able to find information on it anywhere else. However, since we have the decrypted files, we can patch the library to load the decrypted files directly from memory, and I was halfway into doing that when I realized two more problems. Secondly, if I were to patch the library to load decrypted data, that means every user needs to decrypt the files themselves (because I won’t distribute copyrighted code). Third, image_ps_toc is variable sized, which means if the image is too big, it’ll break the offsets and refuse to load.

Currently, I’m trying to find the easiest and most legal way of allowing custom image_ps_toc files to work. (Bonus points if I can also load custom BIOS files). What I hope for is to write a wrapper library, libjava-activity-wrapper.so, which loads libjava-activity.so and patches GetImageTOC and GetImageTOCLength to load from a file instead of memory. This means I have to deal with Java and JNI again (ugh), and also do some weird stuff with pointers and memcpy (double ugh). The JNI methods in the library do not have their symbols exported, so I have to find a way of manually load them.

Bonus: blind patching a binary

When trying to patch a method for an ARM processor, it’s a bit of a pain and I’m too lazy to read about proper GDB debugging techniques. In additions, Sony wasn’t kind enough to compile everything with debugging symbols. However, I came up with a hacky-slashy way of changing instructions and seeing what happens. First, open up IDA Pro and find the function you want to modify. For example, I want decrypt_executable() to bypass decryption and just copy data plain. Find the instruction to change, and the opcode to change it to. For example, I want to change a BL instruction to NOP and CMP to CMN (don’t jump to decryption process and negate the “return == 0″). I have ARM’s NOP memorized by now 00 00 A0 E1. I don’t know what CMN’s opcode is, but if I look around I can find CMN somewhere and I see it’s just a change from a 7 to a 5. After everything’s done, copy it over to the phone and run it. If it crashes (and it should), look at the dump. The only important part is the beginning:

I/DEBUG   (  105): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000054
I/DEBUG   (  105):  r0 002d9508  r1 413c103c  r2 2afcc8d0  r3 002d93d8
I/DEBUG   (  105):  r4 00000004  r5 002d93e0  r6 6ca9dd68  r7 00000000
I/DEBUG   (  105):  r8 7e9dd478  r9 2cbffc70  10 0000aca0  fp 6caa4d48
I/DEBUG   (  105):  ip 002d93e8  sp 7e9dd0c0  lr 00000001  pc 4112d01c  cpsr 40000010

The error message doesn’t help at all “SIGSEGV,” but we have a dump of all the registers in the CPU. The important one is the PC (program counter), which shows what offset the last instruction was at offset 0x4112d01c in the memory. To get the program offset, just cat /proc/{pid}/maps to find where libjava-activity.so is loaded in memory. Subtract the offsets, and pop it into IDA pro. Now figure out why it crashed and try again. I need to learn proper debugging techniques one day.

Analyzing the PSX emulator on the Xperia Play

I’ve been playing around with the new Xperia Play (well, with the speed of these Android phone releases, it’s already old). I’ve decided it would be a challenge to try to figure out how the PSOne emulator works and eventually be able to inject any ISO and play it with Sony superior PS1 emulator. Just to be clear, nothing is done yet, and this is just a technical post to aid whoever else is trying to do the same thing. Also, because information should be free.

Decompiling and disassembling

Before we can do any analyzing, we need to break everything open. I found a couple of useful tools to aid with reverse engineering Android applications. First up is apktool, which is like an all-in-one Android app decompression and decompilation tool. It uses various other tools to do stuff like decompress resources, convert the meta files to be readable, and use baksmali to disassemble Dalvik bytecode to assembly code. Another useful tool is dex2jar, which converts Dalvik bytecode to regular Java bytecode and generates a jar that can be decompiled to Java code using a decompiler like, my favorite, JD-GUI. Last, but not least, we have the big guns: IDA Pro, which I’ve used religiously for many projects. If you don’t know, it can disassemble almost any binary, including native ARM libraries.

Stepping through

The first thing to do once we reversed all the code is to read it. A good way to start is to follow an application from start to finish through the code. Looking in the Android manifest file, we find the main activity that is started is com.sony.android.psone.BootActivity. We open that up, look at onCreate() and read what it does, follow whatever methods it calls and read through all those too. It may get a bit complicated, so I suggest thinking like a stack. From what I can understand, the first thing the app does is check if the data is downloaded. “Crash Bandicoot” is a 500MB game, so it would use up all the system space, so what Sony did is pack the binaries into the APK installed on the system, and the game data (textures, images, etc) is a ZPAK (renamed PKZIP) file that is downloaded from their servers if deleted. Once the data is verified to exist or downloaded from Sony’s servers, the baton is passed to a native JNI library to do the actual work.

Native code

Sony sees the Xperia Play not as just an Android phone, but a game platform. They call it “zplatform”, or as I guess: Zeus Platform (Zeus was the codename for the Xperia Play). The platform APIs is found on libzplatform.so, which is linked by all platform compliant (read: only on Play) games. It contains functions for extracting/creating ZPAK files as well as a lot of encryption/decryption commands and other stuff like networking. Another library is libjava-activity.so, which contains the actual emulator. Well, sort of. libjava-activity.so contains almost 2MB worth of crypto-security functions. It’s sole purpose is to decrypt and load into memory, three files (two of which are stored encrypted inside libjava-activity.so). They are: image_ps_toc (I can only guess it relates to the ROM file, image.ps), ps1_rom.bin (the PS1 BIOS, found in the data ZPAK), and libdefault.so (the main executable, aka: the emulator).

ZPAK files

The ZPAK file is basically a ZIP file that stores the game data. I only looked through “Bruce Lee” and “Crash Bandicoot”, but from what I can see there, all ZPAK files contain a metadata XML and one or more encrypted data files. For example, Crash Bandicoot’s ZPAK data contains image.ps, which I can guess from the size, is the ROM file for the game. I do not know if it’s an ISO or if it’s compressed, but that’s not important right now. There’s also ps1_rom.bin, which I can say for certain after reading the code to decrypt it, is the PS1 BIOS file, compressed using zlib. There’s also pages from the manual named for their page number and have no extensions. I can assume that they’re encrypted too because they contain no image header and the first two bytes are not the same throughout. The main thing I need to figure out is if the encryption key is common or not.

The white box

The main executable, libdefault.so, is completely encrypted and obfuscated by libjava-activity.so, which implements a white box security. If you read anything about white box cryptography (Google), you’ll see that it’s sole purpose in existence is to prevent itself from being reverse engineered. It hides the decryption key in a giant table or an even bigger finite-sized key. Nevertheless, it would take someone, a group of people smarter than me (not that that’s hard to find) to crack this file.

What’s next

Unfortunately, that’s all I know for now. Why? Because the CDMA version of the Xperia Play has not been rooted yet, and any farther analysis would require client access. I’m in the process to locating a R800i model of the Play to test with, but for now, I hope that someone who knows what they’re doing reads this and continue where I left off.

There are two giant problems that’s preventing us from injecting any PS1 image into the emulator. First of all, everything is encrypted. My hope is that it’s a single key used in zplatform (seeing that there’s functions such as zpCryptDecrypt and zpCryptEncrypt in the platform APIs) is used by Sony to encrypt image.ps and the manuals. Second of all, we need libdefault.so, the emulator. This may be easier then imagined. White box cryptography is used to hide the decryption key, not the decrypted content. My hope is that libdefault.so is loaded into RAM after libjava-activity.so decrypts it. There is a high chance of that because it would be hard to hide an executable and run it at the same time. If that is the case, disassembling the emulator will produce more results. If you have a rooted Xperia Play, set up USB debugging, and open up Crash Bandicoot. Connect the Play, and call “adb shell dd if=/dev/mem > memdump.bin” and then “adb shell dd if=/dev/kmem >> memdump.bin” (I don’t know which one would work, so try both). That will (hopefully) produce a memory dump that will contain the emulator executable. Once we have this, even if we cannot decrypt image.ps, it may be possible to write an alternative wrapper application that will load ISOs or something.