For those who can't play a video game without dissecting it
Currently testing out a workflow for identifying PlayStation overlays containing executable code, using reverse engineering tools and a CD image browser.
00 FF FF FF FF FF FF FF FF FF FF 00.MM SS FF XX, where MM is the minutes, SS is the seconds, FF is the frames and XX is the code of the sector mode. You can convert this to LBA using the formula (MM * 60 * 75) + (SS * 75) + FF. Again, be sure to convert from BCD before doing the math.2352.(LBA_timecode - LBA_diff) * 2352 = file_offsetIf 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.
bchunk, get the TOC with isoinfo -l -i image.iso, then extract with iso-read.^[1]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.