mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 17:55:23 +02:00
An updater's DATA.PSAR is a flat sequence of records - each is 0x150 bytes of PRX-style encryption header, a 0x110 byte entry describing one file, and then its compressed contents. So to get the files, you don't actually have to run it and let it self-unpack - we can just do it. Two steps per record. First "demangle": the 0x130 bytes at +0x20 are AES-CBC encrypted on top of everything else and hide the PRX tag at +0xD0, so a KIRK CMD7 pass with keyseed 0x55 comes first. Then the record is an ordinary PRX blob for the decrypter we already have, once it knows the tag - 0x0E000000, which is new here. Its key needs the kirk7 scramble applied, unlike every other key in that table, which are stored already scrambled; hence the flag on TAG_INFO. UnpackPSAR() takes a prefix filter, since the planned main use for this is pulling flash0:/font out of an updater the user supplies (or from an ISO) rather than extracting whole firmwares, although that can also be interesting for running the VSH. Tested on a 6.61 updater: 436 entries, all 418 files decrypt and decompress, nothing fails. The contents are what they should be - 295 ~PSP modules, 61 PRF files, 18 PGF fonts, and the encrypted XMB indices. Two things it doesn't do yet. Every entry in that archive is named with a five-digit token rather than a path; the real names live in tables 00001-00012 inside the archive itself, under their own separate encryption, so files come out under the short name for now and the prefix filter can't match them. And only the zlib compression format is currently supported. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9