Breaking Videogames

For those who can't play a video game without dissecting it


Project maintained by banyaszvonat Hosted on GitHub Pages — Theme by mattgraham

Currently testing out a workflow for identifying PlayStation overlays containing executable code, using reverse engineering tools and a CD image browser.

If you have an overlay loaded in memory, but want to locate it on the disc, this procedure will let you map that overlay in memory to an LBA. Conversely, the PlayStation API relies on timecodes to seek the disc, and it seems developers generally ignore file names entirely, so getting the CdlLOC timecode given to CdControl(CdSeekP, ...) can tell you where to look in the image. Done, right? Not really. For extracting the sectors directly, you’ll need the file’s size, which can be extracted from the TOC. I honestly recommend trying to string search for extensions like “.STR”, “.TIM”, “.BIN” instead of trying to guess where it is. The TOC appears to be in the ISO9660 format. But for once, I didn’t create extra work for myself and used a CD image browser.

Side note, in CDMage, you can verify the difference between the two LBAs. Go to Edit -> Data Track Properties and see the Misc info tab. The difference between the Total disc time and Size (M:S:F) should correspond to the difference, when converted using the (MM * 60 * 75) + (SS * 75) + FF formula.

Limitations: This assumes that the disc is a single-track, single-session disc. If you have multiple tracks, I’m not sure the file offsets and the LBAs will stay lined up. I think the PSX API doesn’t support multiple tracks, so it should be fine for the purpose of locating overlays. Additionally, addresses in the overlays require fixups before they can be actually usable, so ultimately you still want to dump them from memory, but the corresponding file size should give at least some clue how much memory you need to dump.


^[1] Sleight of hand warning: I don’t think it’s guaranteed that the entire file is mapped as an overlay, but once you’ve moved to the file abstraction from raw byte chunks, you can just get away with mapping the entire file into a separate address space in Ghidra. Similarly, the file may contain a header before the actual code, so you’ll need to line the function prologue in the file up with the address it’s supposed to be at.

Back to index