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.

Porting Kindle 3.1: Part 2 – Update encryption

Overview

So, on the topic of Kindle (I swear, it’s becoming an obsession). I am currently in the process of porting the Kindle 3.1 software to Kindle 2 and DX. I will make a series of posts describing my process while describing how various parts of the Kindle operating system works. Now I’ve tested 3.1 on my Kindle 2 and it works perfectly fine. All features work (audio, TTS, book reading), and the new features also work without major slowdowns (new PDF reader, new browser, etc).

Where’s part one you ask? Well, part one was getting the 3.1 OS to work on the Kindle 2, the rest is making an easy installer. That is a long story that involves custom partition tables, manually creating tar files (checksums are a pain), remote debugging, and more. It’s a lot of stuff and most aren’t very useful because nobody should have to repeat the process, which is why I’m creating a easy to use installer. If I have time one day, I may write it down for documentation purposes.

First of all, I will write down the game plan. What I plan to do is create an installer with the least amount of steps for the user. I’m hoping for a two part or three part installer. (Can’t be one part because you need a copy of the OS, and distributing it is most likely frowned upon by Amazon). How the installer should work is:

  1. User copies a image-creator package on a jail-broken Kindle 2. This package will backup the original OS, and generate a new ext3 image with some required files from the Kindle 2 (drivers and such). It will also update the kernel to support recovery packages.
  2. User keeps backup in a safe place and copies the image-creator package and the image generated from the K2 on a jail-broken Kindle 3 and runs the package. The image-creator will scan the filesystem making sure all files exist are are unmodified, then copies the files to the ext3 image. It will then take the ext3 image and generate a Kindle 2 recovery package with the 3.1 OS.
  3. User copies the recovery package generated from the Kindle 3 and copies it to the Kindle 2 and restarts. The Kindle will write the ext3 image to the root partition.

Update Encryption

Now, Igor Skochinsky wrote a nice post a couple of years ago on the Kindle update encryption algorithm. Basically, to encrypt an update, you take each byte of the file and shift the bits four to the left and OR it with the same bits shifted four to the right. Then you AND the result by 0xFF and XOR it by 0x7A. (Sounds like some computer dance move). Well, Igor also wrote a nice Python script that does the encrypting and decrypting, but I didn’t want to port Python to Kindle, so I decided to modify Amazon’s update decryption script “dm” and reverse it to make a encryption script “md”. I opened up IDA Pro and looked for the encryption. Here it is nicely commented by me into psudocode:

BL getchar // get byte to modify

EOR R3, R0, #0x7A // R3 = R0 ^ 0x7A

CMN R0, #1 // if !(R0 == 1), we are at the end of the file …

MOV R0, R3,LSR#4 // R0 = R3 >> 4

AND R0, R0, #0xF // R0 = R0 & 0xF

ORR R0, R0, R3,LSL#4 // R0 = R0 | R3 << 4

BNE loc_8470 // … then jump to end of program

MOV R0, #0 // clear R0 register

ADD SP, SP, #4 // don’t care

LDMFD SP!, {PC} // don’t care

It was a simple matter of reversing the instructions and registers, but like I said before, IDA Pro does not allow changing instructions directly, so I had to mess around with the machine code in the hex editor until I made the instructions I want. Here’s the modified function nicely commented by me in human.

BL getchar // get byte to modify

CMN R0, #1 // if byte is 0×01, then …

MOV R3, R0,LSR#4 // set R0 to R0 right shift 4

AND R3, R3, #0xF // set R4 to R4 logical AND 0xF

ORR R3, R3, R0,LSL#4 // set R3 to R3 logical OR ( R0 left shift 4 )

EOR R0, R3, #0x7A // set R0 to R3 logical exclusive OR 0x7A

BNE loc_8470 // … exit program

MOV R0, #0 // clear register R0

ADD SP, SP, #4 // don’t care

LDMFD SP!, {PC} // don’t care

If you want to try it out, here’s the bspatch from “dm” to “md”. MD5 of dm is 6725ac822654b97355facd138f86d438 and after patching, md should be 3b650bcf4021b41d70796d93e1aad658. You can copy md to your Kindle’s /usr/sbin and test it out:

echo ‘hello world’ | md > hello.bin # “md” encrypt ‘hello world’ and output to hello.bin

cat hello.bin | dm # “dm” decrypt hello.bin and it should output ‘hello world’

Now that we can create update packages from the Kindle, I can start working on the Kindle 2 image-creator script.

Recovering a formatted or corrupt Kindle 2

One day, while playing around with a Kindle 2, I accidentally deleted the /lib folder. Oops. Now, no command beyond “ls” and “rm” work. If this was a computer, I could have simply inserted a installation DVD and copied the files over, but this was an eBook reader, and I was in for a world of pain. This was a month ago, and I’ve finally recovered the Kindle. I’m posting what I did online to save anyone else who’s in the same boat a ton of time. This tutorial is only designed for the Kindle 2, but it MAY work for the DX. It will NOT work for the Kindle 3, but directions should be similar.

 

First

If you’ve think you “bricked” your Kindle, don’t panic yet. There could be a easy solution. Chances are, if you can see the startup progress bar loading, the solution should be easier (although I can’t tell you exactly what your problem is). I would follow Amazon’s troubleshooting directions first. Only proceed if you are absolutely sure nothing else can be done.

Overview

Here’s what you’ll need

  1. TTL to RS232 or USB connector. I used this one. For that, use the jumper on pin 1 and 2 on the side (with the three pins, pin 1 is towards the USB port). Connect Kindle Tx -> Tx, Rx -> Rx, GND -> GND, VDD -> VDD
  2. Windows with HyperTerminal (I tried Kermit on Linux, but it couldn’t send files. HyperTerminal is the only program I’ve tested that works sending files to the Kindle)
  3. Linux or Unix-based computer with “dd” and “ssh”
  4. My custom recovery kernel which allows jailbreak signed recovery packages and exporting MMC0 without a password. If you want to know how I’ve made it in technical details, see the appendix.

Here’s what we’ll be doing:

  1. Attaching the recovery port
  2. Flashing the custom patched recovery kernel
  3. Obtaining a backup of Kindle system files
  4. Restoring your Kindle

Attaching the recovery port

First open up the Kindle 2 to reveal the PCB board. You should remove both the metal casing and the white plastic with all the screws. On the top, to the left of the headphone jack, you should see four pads labeled J4. Either solder (recommended) or tape (make sure it isn’t lose!) four wires to these pads. The order of these ports (left to right, where left is towards the volume switch) are: VDD, Rx, Tx, GND. Connect these lines to your TTL adapter and connect the adapter to your computer.

Flashing the custom patched recovery kernel

Open up HyperTerminal, and connect to your adapter. Make sure to click “Configure” and fill in the settings. The settings are: BPS: 115200, Data bits: 8, Parity: none, Stop bits: 1, Flow control: none. Then, restart your Kindle either by removing & reconnecting the battery, holding the sleep switch for 30 seconds, or tapping the reset switch on the PCB. Press Enter when text pops up in HyperTerminal. You only have one second, so be quick. In uBook, type in “run prg_kernel_serial” (make sure to type fast or uBoot will timeout). Then right click on the text, and choose “Send File”. Under protocol, choose Ymodem-G and for the file, select my custom kernel. Wait a few minutes for it to upload and install, then type in “bootm 0xa0060000″ to boot the kernel. The Kindle has two kernels that it alternates on each boot, so if you want to use my recovery kernel, you need to either flash the other kernel also or type in “bootm 0xa0060000″ into uboot on startup. Hold down Enter either on your computer or on the Kindle to enter the recovery menu. The recovery menu times out in 10 seconds, so you need to be quick. First type “I” to recreate all the partitions, then type “3″ to export the MMC. Again, these can be typed from either your keyboard in HyperTerminal, or the Kindle keypad. If you do not have access to HyperTerminal because you are in Linux restoring, you can get back here by holding Enter on the Kindle keypad and pressing 3 on the recovery menu.

Obtaining a backup of Kindle system files

Let’s put your broken Kindle aside. You need a working copy of Kindle’s system files. I cannot provide this for legal reasons, but if you obtain another Kindle 2 (preferably the same model and version as your broken one, but others MAY work [not Kindle 3 though... yet]), jailbreak it and install the usbNetwork hack for SSH access. Make sure that Kindle has at least 500MB of free space on the FAT partition to store the backup image. Once you SSH’d into the working Kindle (there are tons of tutorials around on this), issue the following command:

dd if=/dev/mmcblk0p1 of=/mnt/us/rootfs.img bs=1024

Note that this will only make a copy of the OS files. All personal information, passwords, books, etc are not copied. You can tell your friend that. This may take five to fifteen minutes to run, but when the command returns with the blocks written, you can disable usbNetwork and enable USB storage again. Copy the rootfs.img file over to your recovery computer and prepare to restore.

Restoring your Kindle

Back to your broken Kindle. You need to reformat the root and copy over the backup files. I moved the Kindle over to a Linux computer because it is easier. You can also use OSX or maybe even cygwin, but I haven’t tested. In shell, type in the following commands:

sudo su # Become root, so you don’t need to sudo everything

fdisk -l # Look for your Kindle’s identifier, it should be something like /dev/sdc, it should be a 2GB drive with 4 partitions. I will use /dev/sdX to represent this drive

mkfs.ext3 /dev/sdX2 # Make a ext3 partition for /var/local

dd if=/path/to/rootfs.img of=/dev/sdX1 bs=1MiB # This will take a long time to finish

Note that an alternative method is to gzip rootfs.img and place it into a recovery package created using kindle_update_tool.py, but I’ll leave that as an exercise for the reader.

Appendix

So, what is in the magical Kindle recovery kernel? It’s actually just a regular Kindle kernel recompiled with a modified initramfs with a patched recovery script. Using the regular kernel, you’ll run into two difficulties when trying to recover. First, if you press 3 to export MMC0, you’ll get a password prompt. Good luck brute forcing it. Second, if you build a custom recovery package using kindle_update_tool.py m –k2 –sign –fb, it will not work because of signature checks. What I did was patch the two checks.

First, I extracted the recovery-utils file by gunzipping uImage (with the extra stuff stripped out), and gunzipped initramfs.cpio from that. Then I extracted initramfs.cpio and found recovery-utils under /bin.

Next, the easy part is patching the updater package signature checks. What I did is extract the updater RSA public key file from the Kindle, found under /etc/uks and used OpenSSL to extract the public key from it (n and e). Then I opened recovery-utils with a hex editor, searched for the public key, and replaced it with the jailbreak key (found in kindle_update_tool.py).

Finally, the challenging part was to patch the password check from export MMC0. First I opened recovery-utils with IDA Pro. Then I located the check_pass function. I worked backwards from that and saw it was called from loc_94A8. Here’s a snippet of the check along with my interpretation of what it does:

BL check_pass # Call the check_pass function

CMP R0, #0 # check_pass sets register R0 with the return value, we will check if R0 equals 0×0

BEQ loc_9604 # If the previous instruction is true, then password check has failed

LDR R0, =aDevMmcblk0 ; “/dev/mmcblk0″ # We did not jump out, so CMP R0, #0 is false

BL storage_export # Call this function

It’s always easy to patch the least amount of instructions with the least amount of changes, so this is what I did. (Note that IDA Pro doesn’t allow editing instructions directly, so I have to find the machine code in hex to know what to replace. Luckily, I have tons to instructions to look at and see what their corresponding machine codes are).

NOP # Instead of calling check_pass, I did MOV R0, R0 which is the same as NOP

CMN R0, R0 # Negative compare R0 with itself. Basically, always return false.

… rest is the same

Now, I saved the file and luckily, it was the same size. So I didn’t have to recreate the initramfs.cpio, I just replaced the file inside with my hex editor (note that cpio files do not have checksum checks unlike tar files). I copied this to the kernel source folder and compiled the kernel. Lucky for you, I have already done all of this so you don’t have to.