Playstation Vita’s USB MTP Connection Analyzed

This is the first of (hopefully) many posts on the PS Vita. Before I attempt anything drastic with the device, such as getting unsigned code to run, I hope I can try something easy (well, easier) to get used to the device. Ultimately, I want to make a content manager for the PS Vita for Linux. Unlike the PSP, the Vita does not export the memory card as a USB storage device, but instead relies on their custom application to copy content to and from the device. This post will give just a peek into how the communication between the Vita and the PC works.

There are two ways of approaching this. One is to sniff the USB packets to figure out what data gets sent to and from the device, and second is to disassemble the content manager application to find out how it communicates with the device. I tried both methods.

Reverse engineering the Content Manager

The biggest problem here is that the PC version of Sony’s content manager has its symbols removed. This makes everything a hundred times harder as you would have a harder time guessing what each function does. Luckily, the OSX version of the content manager does have the symbols intact. The problem here is that IDA does not work perfectly with Objective-C (it works, but you get a C++ish interpretation of Objective-C). I have a good idea of how the application is laid out, but there isn’t much point giving all the details (not useful). I will give some important points:

  • The Vita uses the Media Transfer Protocol, however I am not sure if it adheres completely to standards or if it uses a custom implementation
  • USB endpoint 0×2 is for input, while 0×81 is for data output, and 0×83 is for MTP event output
  • There is support for passing PSN account information to and from the Vita (password would be in plain text!), but it is unimplemented
  • CMA uses a SQLite database to index media information and licenses
Also, I’ve compiled a list of MTP operation codes for the Vita that are referenced in CMA (and therefore implemented in the Vita). Note that some of the codes are not in the standards while others are. For events, the second number is for reference with regards to the jump-table inside CMA only.


Events:
0xC104 0: RequestSendNumOfObject
0xC105 1: RequestSendObjectMetadata
0xC107 3: RequestSendObject
0xC108 4: RequestCancelTask
0xC10B 7: RequestSendHttpObjectFromURL
0xC10F 11: RequestSendObjectStatus
0xC110 12: RequestSendObjectThumb
0xC111 13: RequestDeleteObject
0xC112 14: RequestGetSettingInfo
0xC113 15: RequestSendHttpObjectPropFromURL
0xC115 17: RequestSendPartOfObject
0xC117 19: RequestOperateObject
0xC118 20: RequestGetPartOfObject
0xC119 21: RequestSendStorageSize
0xC120 28: RequestCheckExistance
0xC122 30: RequestGetTreatObject
0xC123 31: RequestSendCopyConfirmationInfo
0xC124 32: RequestSendObjectMetadataItems
0xC125 33: RequestSendNPAccountInfo
0xC801 1789: Unimplemented (seen when getting object from Vita)

Commands:
0x1001: GetDeviceInfo
0x1002: OpenSession
0x1007: GetObjectHandles
0x1008: GetObjectInfo
0x1009: GetObject
0x100C: SendObjectInfo
0x100D: SendObject
0x101B: GetPartialObject
0x9511: GetVitaInfo
0x9513: SendNumOfObject
0x9514: GetBrowseInfo
0x9515: SendObjectMetadata
0x9516: SendObjectThumb
0x9518: ReportResult
0x951C: SendInitiatorInfo
0x951F: GetUrl
0x9520: SendHttpObjectFromURL
0x9523: SendNPAccountInfo
0x9524: GetSettingInfo
0x9528: SendObjectStatus
0x9529: SendHttpObjectPropFromUR
0x952A: SendHostStatus
0x952B: SendPartOfObject (?)
0x952C: SendPartOfObject (?)
0x952E: OperateObject
0x952F: GetPartOfObject
0x9533: SendStorageSize
0x9534: GetTreatObject
0x9535: SendCopyConfirmationInfo (?)
0x9536: SendObjectMetadataItems
0x9537: SendCopyConfirmationInfo (?)
0x9538: KeepAlive
0x9802: ?
0x9803: GetObjectPropValue
0x9805: GetObjectPropList

Response:
0x2001: OK
0x2002: GeneralError
0x2006: ParameterNotSupported
0x2007: IncompleteTransfer
0x200C: StoreFull
0x200D: ObjectWriteProtected
0x2013: StoreNotAvailable
0x201D: InvalidParameter
0xA002: ?
0xA003: ?
0xA004: ?
0xA00A: ?
0xA00D: ?
0xA008: ?
0xA010: ?
0xA012: ?
0xA017: ?
0xA018: ?
0xA01B: ?
0xA01C: ?
0xA01F: ?
0xA020: ?
0xA027: ?

Data Types:
0xDC01: StorageID
0xDC02: ObjectFormat
0xDC03: ProtectionStatus
0xDC04: ObjectSize
0xDC05: AssociationType
0xDC07: ObjectFileName
0xDC08: DateCreated
0xDC09: DateModified
0xDC0A: Keywords
0xDC0B: ParentObject
0xDC0C: AllowedFolderContents
0xDC0D: Hidden
0xDC0E: SystemObject
0xDC41: PersistentUniqueObjectIdentifier
0xDC42: SyncID
0xDC43: PropertyBag
0xDC44: Name
0xDC45: CreatedBy
0xDC46: Artist

Object Formats:
0x3000: Undefined
0x3001: Association
0x3008: WAV
0x3009: MP3
0x3801: EXIF/JPEG
0x3804: BMP
0x3806: UndefinedReserved
0x380A: PICT
0x380B: PNG
0xB007: PSPGame
0xB00A: PSPSave
0xB014: VitaGame
0xB400: ?
0xB411: MNV
0xB984: MNV2
0xB982: MP4/MGV/M4V/MNV3

USB packets

I’ve also captured the USB packets for initializing the device (from device plug-in to Vita displaying the content menu) and gave my best interpretation of it. First line is PC to Vita packet or Vita to PC packet

, followed by packets captured by VMWare running Windows 7, followed by the same action on OSX (dumped from memory using GDB on CMA, not from capturing USB packets), followed by my interpretation of what the packet does (question mark means not sure). EDIT: Some of my comments in the log I know are wrong now.

Next time

I’m hoping to decode these packets and implement them using libusb. I hope Sony is using the MTP standard so I can also make use of libmtp. I also need to be more familiar with how the USB protocol works so I can understand the packet layout better.

EDIT: I’ve begun work on a new project to create an open source content manager for the Vita. As of this post, it can init the device and tell it to show the main menu.

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.