Also, this tutorial is not finished. It should however provide you with all of the information necessary to successfully move a file, even if all steps aren't explained in detail yet.
Software used in this tutorial:
- HxD - hex editor to modify binary ROM image (the game data)
- rn64crc - tool to recalculate the CRC checksums of a modified ROM
- Decompressed Majora's Mask N64 ROM of choice (you can use ndec to decompress your N64 Zelda ROMs)
- [+] Example of the process (simpler explanations)
- In this example, we'll be moving Link's file to unused space at offset 0x03D00000. I've imported this sword into the file, so the size of it has increased:
- [+] Spoiler
Thanks to CDi-Fails for providing me with this sword model!
If you compare the two files, you'll see that the modified one is slightly bigger in filesize than the other one. This means that we can't put it back at the original location of Link's object file, since it wouldn't fit.
Go ahead and open up both of these files in HxD, as well as a decompressed NTSC 1.0 MM ROM.
In the modified file, copy all data. This can be done by hitting CTRL+A on the keyboard to select the entire file binary, and then CTRL+C to copy that data.
Now switch over to the ROM. We need to go to the new location where we'll place the modified file. As stated above, we'll place it at offset 0x3D00000 in this tutorial, since data around that location isn't normally used by the game.
To go to a certain offset in HxD, you can etiher click "Search" and then "Goto", or hit CTRL+G on the keyboard. When you do either, a box will pop up where you can enter the specified offset that you want to go to. Enter "3D00000" and then hit "OK".
You will arrive at that offset almost immediately. Before pasting the file though, you should take a look at the offset.
You'll need to remember this offset, since you'll be needing new pointers to tell the game to load Link's file from this new location instead of the original one. Therefore, I recommend you to write it down in notepad or something similar, so that you won't forget it.
Now go ahead and paste write the data of the modified file at that location. It is very important that you "paste write" the data - don't paste it like regular. That would increase the filesize of the ROM, and it would become unplayable.
You can paste write through simply right-clicking and clicking paste write, or hitting CTRL+B on the keyboard. Remember to always and only "paste write" when altering the data of Zelda ROMs using HxD, unless you're very sure of what you're doing.
When this is done, look at the offset you arriven at.
You'll have to remember this offset as well. The previous offset that you documented will tell the game from what location to start reading the file, whereas this one tells the game where to stop reading it. Write it down as well, so that you'll be able to create the new pointer.
Creating a new pointer is actually really simple. Just take your start offset and attach your end offset to it.
Now you've successfully moved the file! The game doesn't magically know this though; you'll need to rewrite the pointers that tells it from where to load Link's object file.
To do this, first you need to go back to offset 0 of the ROM.
Now switch over to the clean, unmodified version of Link's file and copy all of it just like you did with the modified one.
Switch back to the ROM. We're going to search for the entire file, to find the location in ROM where it's originally stored.
To search for specific data in HxD, you can either click "Search" and then "Find", or simply hit CTRL+F on the keyboard. Just like when going to an offset, a box where pop up. Here you can enter the data you want to search for; just paste the data you copied from the unmodified file as this. Since the data you copied was so large, it won't actually display what you entered. This doesn't matter though, as HxD still will search for the the stream of bytes that you entered.
Before you search though, you'll need to change the "Datatype" from "Text-string" to "Hex-values".
Click "OK", and you'll arrive at an offset after some selected bytes. These bytes are the data you searched for, or in other words: Link's object file. Now you can see from what offset the game originally loads Link's object file from, by looking at the offset where the marked bytes start.
Write this one down in notepad as well, as we'll be searching for this offset in ROM to locate the original pointers to the file.
Notice though, that the offset displayed in HxD (like in the picture above) only consists of 7 digits. Data is represented by bytes in HxD, which in hexadecimal consist of 2 digits. Since 7 is an odd number while 2 is even, the offset can't be stored in bytes exactly as displayed above.
To solve this minor issue, simply put a 0 at the start of the displayed offset, to make it consist of 8 digits (an even number) while still keeping its value.
Now it's time to locate the pointers in ROM (there are three of them that we need to replace, to be exact). This isn't very hard, just search for the start offset of the file that we located previously.
You should arrive at an offset displaying the exact same bytes as you searched for.
Here, paste write the entire new pointer that we created earlier, which points to the new location in ROM where we put the modified file.
Now we've replaced one of the three pointers. To find the next one, hit the F3 key to "find again", which will search for the same data again. Now you should arrive at an offset displaying another pointer to the original file.
As you can see, this pointer is actually right next to the first one we replaced.
You can't replace this pointer with the entire new one though. This specific pointer actually only points to the start of a file, so just paste write the start offset of our modified file here.
Now there's only one pointer left to replace
Hit F3 again, to search for the pointer (to the original location of Link's object file) yet another time. Once again, you should arrive at an offset displaying the exact bytes that you searched for.
This pointer is like the first one, so you can go ahead and replace it with the entire new pointer that we created before.
Now we're done with HxD, and the "hard" parts of the tutorial are over. Nice job! Go ahead and save the ROM before closing the program.
We're not done yet though. If you were to load the game in an emulator right now, you'd get an error and be unable to play the game. This is because the CRCs (basically a type of security checks built in to the ROM) of the game have been corrupted, which happens when modifying certain areas in ROMs of N64 games.
To solve this, we'll need to use the program "rn64crc". To run it, open up command prompt and simply drag and drop the program onto the command line,
Now hit space, write "-u" and then hit space again. This tells rn64crc to update the CRCs of the ROM that you'll provide it with soon.
Now drag and drop your modified ROM onto the command line.
Now simply hit enter, and the program should finish the process of recalculating the CRCs in our modified ROM!
Now we're done! Open up your ROM in an emulator, get the Guilded Sword equipped and you'll see the result of your moved file!
- [+] WIP General explanation of the process (overly detailed, but hopefully well-explained)
First of all, why would you even want to move a file in the first place, and when would it be useful?
Well, sometimes while modifying individual files extracted from the game (like the file containing the mesh and texture data for Link's model( his "object file") for example), you might want to add something to it (like importing a new sword model into Link's object file).
This will increase the size of the file though, so you won't be able to "put back" the file at its original location in ROM, since it simply doesn't "fit" there with the increased size of the file. This is a typical situation in which you'll have to move the file.
Finding the pointers:
If you want to move a file, it is vital to know at which offsets in ROM its entries (pointers) in the file tables are stored. This is because these tell the game from what offsets (start to end) to load a specific file, which essentially is what we need to modify when moving a file.
So, in MM there are 3 pointers that you will have to replace when moving a file. Finding these shouldn't really be a big deal, you'll just need a (unmodified) copy of the file you want to move, an MM ROM (version of choice) and a hex editor (preferably HxD).
Fire up your hex editor and open up your ROM and file in it (a clean version of the modified file which you're intending to move).
In the unmodified version of the file you're moving, hit CTRL+A and then CTRL+C to copy the entire file binary.
Switch over to the ROM. Now hit CTRL+F to search in the ROM.
In the "Search for" box, hit CTRL+V to paste the binary of the file you copied.
Set the "Datatype" box to "Hex-values" and hit "OK" (this will make it so that HxD searches for hexadecimal/binary numbers instead of other types of data).
You should arrive at a result almost immediately. From this you can easily see the start- and end-offset of the file, however you'll actually most often just need to know the start-offset of a file to locate its pointers in the file table (a chunk of data that tells the game where all individual files are stored in ROM, through displaying their start- and end-offsets)
Before doing anything else, I should explain the "formatting" of the pointers we're replacing:
- [+] Spoiler
- 1 - xx xx xx xx yy yy yy yy
2 - xx xx xx xx 00 00 00 00
3 - xx xx xx xx yy yy yy yy
xx = Start-offset of file
yy = End-offset of file
A result should pop up - this is the "1" pointer.
Next to this should be the "2" pointer".
To locate the "3" pointer, simply hit F3 to "Find again".
Write down the offsets of these somewhere, so that you won't forget them.
Moving the file and re-pointing:
After you've found the pointers, the only things left to do is to actually move the file and then re-write the pointers according to this new location.
To do this, open up the file you want to move in HxD and hit CTRL+A and then CTRL+C to copy the entire binary.
Switch over to the ROM and decide where you want to move the file to. You'll probably want to move it to space that's not already being used by the game. Everything after around offset 0x3D00000 is free space in most Zelda 64 ROMs - we'll use that in this example.
So hit CTRL+G and write "3D00000" in the "Offset" box to go to this offset. Here, simply paste your file in (CTRL+B).
Now it's time to "create" a new pointer so that the game will load the file from this new location instead of the old one. To do this, simply take the start- and end-offset of your moved file and put them together.
For example, if the start-offset of your moved file is 0x03D00000 and the end-offset is 0x03D1E250, the new pointer will be 0x03D0000003D1E250 (the prefix "0x" just signifies that a value is hexadecimal).
So go to the offsets of the "1" and "3" pointers you located earlier and paste this there. But what about the "2" pointer?
As you might remember, this only points to the start of the file, so you should only write the start-offset of your moved file there (would be 0x03D00000 in this example).
Now you're done with this part of the tutorial, so you can save the ROM and close HxD. If you were to open your ROM in an emulator now though, you'd get an error, even if you did everything completely right.
This is because the N64 has a sort of built in security check to prevent modification of its games, called CRC checksums. I will not delve too deeply into what these actually are (as I'm not completely sure myself), but know that by modifying certain areas of ROM they will become corrupted and the game won't run (which is exactly what happened in our case).
We will have to update the game's CRCs in order to fix this issue.
Recalculating the CRC:
The last step is to recalculate the CRC - explanation will come sometime.