Process of Arcade ROM Hacking

  • View

  • Download

Embed Size (px)


Process of Arcade ROM HackingBy Stephen Wylie12.04.2016 (5844 2F70)

The Tapper game has plenty of Budweiser branding.

How can we change it?

ToolsEveryone should have these handy!MAME emulatorGame ROMsEditors (Hexplorer, SciTE Hex)GIMP for new graphics creationPre-built tools for the games platformIf not, I hope you can write code!

Hexplorer for Windows is nice for reasons you will see later. (Hint: If you dont get it, its that the Matrix-style color scheme lends well to pattern recognition.)

MAME EmulatorDownload and unzip MAMEPut your ROM in the roms folder in its own directoryMAME/roms/tapper/*.binLaunch MAMEmame64.exe -window -verbose -debug -nomax tapperPress F5 to run in Debug modePress F4 for Tile Viewer- Press Enter for more information

3. Why use the command line? If theres an invalid checksum with your ROM compared to what MAME thinks is right, this will let you get around that. When you load the ROM through the menu with plain Jane MAME, it will stop on its own ROM checksum mismatch, considering it a fatal error, and wont let you run your creation.-window makes MAME windowed rather than full-screen. Otherwise you could not navigate to other applications without exiting the game. However, the window is still usually very large.-verbose spews lots of other information on the command-line window such as CRC checksums of the ROMs, input & sound devices being loaded, status of initializing the ROMs, etc.-debug launches the debugger.-nomax makes the window the native size of the game, rather than the maximum size your monitor can fit.

Around MAME and the ROMsThe Tile Viewer shows the available color palettes, tile artwork, and tile map.Examine the two background files; look for patterns. What matches the Tile Viewer? Discover the encoding and palette scheme.Practice making edits. See if the results are what you expected. Refine and tweak if it did not meet your expectations.Organization of ROM Filestapbg0Background tile palettetapbg1Background tile artworktapfg[0, 7]Foreground spritestappg[0, 3]Game logic, level tile arrangementstapsnda[7, 9], tapsda10SoundGetting Your Bearings

DemoStudying & Testing Background ROMs12.04.2016 (5844 2F70)SDthgkkjkj

In this demo, we were looking at the tapbg0 and tapbg1 files in the hex editor. I showed those in conjunction with the tile map and color palette to describe how I deduced the encoding scheme.

What we learnedtapbg0 (right) encodes the group of 4 colors (minor palette) for each pixeltapbg1 (left) encodes the color within the minor palette for each pixelThese are two-bit encodings per pixelEach tile is 64 pixelsEach tile offset is 0x10

Each tile offset is simply the tile address shifted up 4 bits. Makes it easy to calculate! Just stick a 0 on it in hex and youve got it.

Rearranging Tiles On the Background

Where are the tiles?Carefully study tiles in Tile ViewerMatch these to locations on-screenDraw yourself a gridScroll through program ROM until you find one or more tile addresses

How did you know it was the program ROM? Process of elimination ;)

Where are the tiles?Carefully study tiles in Tile ViewerMatch these to locations on-screenDraw yourself a gridScroll through program ROM until you find one or more tile addressesSometimes you have to eliminate the distractions, such as row wrappingAnd the Tile Viewer might not be on the correct major palette setting

Depending on how wide your hex editor is, you might have one row of tile addresses on more than one line, so that the line is wrapped. In the picture at top right, every other row is actually a continuation of the first row of tiles, thus ignore it.

The 50 parts, while not really part of the tile address, is still important. Well discuss that later.

Now that the extraneous data has been blacked out, take a look at how the tiles line up between the hex code, the snippet of the game background, and the tile file.

And this tile arrangement is easy, because at least the word COMMUNITY is written straight across, even if it is split into the top half and bottom half. The original arrangement of the Budweiser logo made next to no sense at all. Id imagine they were using some sort of Gray code to minimize the number of bits that had to be changed to load each sequential tile, but since MAME doesnt run on hardware from the early 80s, were not concerned with squeezing out every last drop of performance from our graphics engine.

Zilog Z80 machine language features opcodes where any byte value from 0 to 255 seems equally likely. However, background tile regions exhibit a pattern. Can you spot where the tiles begin?

Think about this in terms of probability or from an entropy perspective. The Zilog Z80 instruction set is comprised of a great many opcodes, making big chunks of code look random and uniform (as in a uniform distribution, where all byte values from 0 to 255 seem equally likely) to someone inspecting the machine code in a hex editor. However, the background tiles will seem to take on much less of a uniform distribution, exhibiting tendencies to repeat the same or very similar numbers many times over. You might also start to see some of the tile addresses called out from the tile viewer. In fact, the 96 just a little bit down from the middle of the slide, in the first column of the 5th grouping of four, is the byte before the beginning of the tile map.

DemoSearching For & Editing Background Tiles12.04.2016 (5844 2F70)SDthgkkjkj

In this demo, we opened up tappg1 and navigated to address 0x2211 (relative to the file, not the program space) which is where the background tile order information begins. We changed that byte in the hex editor (any value between 00 and FF will do), then saved it, and watched the ROM blow up because later on in some other program code, the checksum was calculated to be invalid.

Substantial ROM EditsFor the checksum to make,thou must giveth and takeROM checksum is calculated by a loop in tappg3Checksum covers game program ROMs, D6, and D7Two strategies to address this:Balance out your changesNOP the checksum routine

Just alter it:Must calculate after each code changeChanging the programmed checksum value wont helpUse debugger to find the difference in expected vs. actualPick a byte at the end to subtract this offset fromWhat if the byte you picked gets used for something?Remove the checksum code:Simple to overwrite the conditional branch instruction with NOPs so the processor ignores itShouldnt do any harm on modern computers and emulatorsMaybe you would want it back before writing to real EPROMsConsidering the Checksum

Changing programmed checksum value wont help because if you changed something in ROM 1 to alter its checksum, then you have to change its checksum in ROM 3 where the checksum code lives. However, this in turn changes ROM 3s checksum, which ends up creating a chase your tail kind of situation.

Beyond these two solutions, people in class offered additional alternatives:1b. Make a program to alter the checksum for you after you make breaking edits.3. Jim recalled that older versions of MAME for Windows seemed to let you edit the checksum value without having to rewrite the ROM or use the debugger. Then again, this recollection was about 15 or 16 years old.

MAME DebuggerUse -debug at the command lineSet breakpoint to pause upon reaching a piece of code:bpset 0xBEEFSet watchpoint to see when one byte of memory is:Read: wpset 0xBEEF,1,rWritten: wpset 0xBEEF,1,wEither: wpset 0xBEEF,1,rw

0xBEEF is our hypothetical 16-bit memory address. You can watch a whole range of memory addresses for reads/writes by increasing the middle value from 1 to a larger number.

DemoChoking Your Checksum So You Can Really Edit Background Tiles12.04.2016 (5844 2F70)SDthgkkjkj

In this demo, we opened up tappg3 to look for the string ROM ERROR. Luckily it was there encoded in ASCII format. Its in the file at 0xDDF, which translates to 0xCDDF in the program space, thus we set a watchpoint at 0xCDDF because this piece of memory would be copied on-screen to be shown. The first time the watchpoint is hit, we discover its in the midst of a loop where its adding up all the values of the ROM to calculate the checksum. The second time this address is hit, its being used to throw up the message. Instead of letting it get to the second time, let the loops run their course but put a breakpoint at 0xCD86. This statement compares the value of a memory address storing the expected checksum to the accumulator, which will raise the (Z)ero flag if the two numbers are equal. If the Z flag is not raised, it proceeds to continue along running instructions 0xCD89 through 0xCD8F in order to store the ROMs index to a memory address so it can keep a list of which ROMs are bad. Because we dont have physical ROMs going bad, we can simply use the hex editor to replace all the instructions from 0xCD89 through 0xCD8F with 00s (NOPs) so that when it finds invalid checksums, it simply doesnt act on that information.

Tile Codes At a GlanceRange: [0, 0x3FF]Little endian0x6F11 = Tile 16F, Palette 1Aliased; higher-order bits affect various settings as described at rightSpecificsBits 15:14 - No apparent changeBits 13:12 - Major palette4 total groups of 16 colorsBit 11 - Flip horizontalBit 10 - Flip verticalBits 9:0 - Tile addressBackground Tile Codes

Little endian means the least significant byte of the two-byte number comes first when you look at it in the hex editor.

Consider using flips to save on tiles. Tapper doesnt seem to do this very much.

However, despite bits 15:14 werent seen to do anything to the graphics, it should be noted that the vast majority of tile addresses seem to have bit 14 set. The earlier le