Screenshot from Paradox Klassix – Soul Reaver (ITA) cracktro
A user in the Nectarine Discord brought an interesting question recently: they had some Youtube videos of cracktros from Playstation games, and wanted to know if anyone could identify their soundtracks. For those unaware, a “cracktro” is a combination of a “crack” (piracy) and an “intro” (demoscene) – it’s a little movie or menu that plays at the start of a hacked / pirated game, usually with credits and simple visual effects. It’s a calling card from the group who helped pirate the game, often with “greetz” to the supplier of the disc image, the coder who cracked it, the BBS or site who re-hosted the result, etc.
Cracktro soundtracks are usually an oldschool chiptune or lo-fi soundtrack in “module” format. Originally created on the Amiga computer, .mod audio files are very small, similar to a MIDI with bundled sound samples. They are well-suited to cramming into a tiny executable, which must fit on the CD along with the pirated game. Sometimes the musician gets credited, but other times it’s a mystery. MOD files don’t have a place to write the artist or other info, only the title and instrument names. Because of the unknown provenance of the files, ripped from games or BBS posts or musicdisks full of sounds, sometimes the original credits are lost or incorrect.
Back to the Playstation games. There was a short list of videos that needed help to track them down, but eventually we got them all figured out. Every one of these was from the group “Paradox”, a console cracking and piracy group who released a number of titles in the early 2000s. Here’s how we figured them all out:
Discord Minesweeper is a Perl script I wrote that builds on one of my previous projects, WebService::Discord::Webhook. It generates Minesweeper boards and posts them to a Discord channel. Each square contains a bomb, number, or blank space, made using the Emoji images. Using Discord’s “spoiler” tag (wrapping text in double pipes, ||like this||), the squares can be individually uncovered, thus making a playable game without even leaving chat.
I ran this script for a few months, posting one board a night, but users eventually got sick of it and deleted the webhook… well, perhaps there are other games that could be done this way? I think a Blackjack simulation would work: you are dealt some face-up cards, optionally some more (covered) to flip, and once you’re finished you can reveal the dealer’s hand to see who won.
It only barely qualifies as a “novel”, as it’s more of a generative art piece. The text is created through custom templating using some selections from dariusk “corpora” project, and the images are rendered using POV-Ray 3.7.
Source code for the project is available here: https://github.com/greg-kennedy/StarAndDriver I highly recommend visiting the Github link, even if you aren’t interested in the code itself. The README has a full write-up on how it all works, and the challenges encountered in creating project.
Magazine, page 20
I’d like to do a print of this and get a physical copy, but I have not priced it out to see if that’s at all affordable. It would be cool on a coffee table though.
An exchange on Twitter led me into a trap that consumed a week of my time – the Sega Genesis / Mega Drive version of Back to the Future: Part III shipped with a bug that caused completely wrong colors to display. Evidently the programmer(s) were confused about the proper format of color data on the Genesis. While color values should be stored in two bytes as 0000bbb0 ggg0rrr0, this game instead uses the incorrect format 00000bbb 0ggg0rrr – all values shifted right by one bit. The end result is that the game displays at half brightness, and lower contrast.
I naively assumed this would be a simple fix: in fact, some prior discussion pointed out that color tables are stored plainly in the file, and even provided addresses to fix some of them. Of course, things are never as easy as they seem. Using a hex editor I changed some color palettes, then used the BlastEm emulator (its debugger is okay) to test, and made two discoveries:
the list in the forum post is incomplete, and I needed to do further digging to uncover the rest of the palettes, and
even with the palettes fixed, colors still didn’t display correctly. Any code that sets the palette (e.g. when fading to/from black) still used the old, wrong format. So while the data was correct, it still displayed wrong.
At this point I decided to see how Ghidra would fare on 68000 code. With the help from some scripts from zznop (to parse Genesis ROM headers, and to generate a new checksum after modification), I spent a couple days working at a disassembly of the ROM. Ghidra works well for this, but it has some quirks: it does not properly handle 24-bit addresses, it sometimes needs a kick with the “disassemble” key to force it to parse a block of obvious code, and the “address table” checkbox on Auto-Analysis causes far more pain than benefit – don’t use that!
Despite the nice color improvements, this stage is still way too hard!
In the end I produced a disassembly that was quite revealing. The game doesn’t have a lot of code re-use, it was apparently written in isolated stages and then combined together at the end. Functions for palette fades and “cutscene” display are duplicated in each segment. Finding palette setting code wasn’t too difficult once a palette were found, and usually looked something like this (taken from a “Fade To Palette” routine):
A bit hard to see maybe, but the important parts are that it’s processing the values in B, G, R order, by using “(component) and 0111“, and incrementing if less than the desired value. This is the wrong bitmask. Changing to 1111 (i.e. 0x7 to 0xf) allows fading through the full gamut, and everything now displays as intended. I was also able to reference the SEGA logo (at game boot), which DOES have proper colors, to double-check that I had this implemented correctly.
Finding the other places in the code where this happens is pretty trivial. A search for 0x0777 or andi.w 0x07 reveals the rest. With that fixed, I regenerated the checksum and wrote a new ROM, then used LunarIPS to make an IPS patch for distributing the fix.
The last step was to port the changes to the EU version of the game. Fortunately, the data is the same, and a Perl script with find-replace made locating the offsets easy. A new IPS patch, a README file, and we’re ready to ship.
All told, this was actually a fun rabbit hole to get lost in, and I did pick up a lot about Ghidra and 68000 assembly that I had been wanting to learn anyway. If only it didn’t come right in the middle of NaNoGenMo… 🙂
Webhooks are basically a “write-only” way to put a message into the chat from your external service. Use them to provide notifications in chat, where a full-blown “bot” client is not needed (e.g. no need to interact with users).