_glook
Got a Passion for Smashin'
So some of you may have seen my proof of concept of SD Remix characters loading off of the memory card exploit. You basically have to hack each of the types of files separately, but once you've done one, you'll at least know where to start with it.
Current known injection points
These are the places know where you can both alter the file data safely and where you have a pointer to the file's data loaded in memory.
How to find new injection points
If this isn't enough for you and you want to patch other files, such as music or whatnot, here is how I usually find new injection points:
How files are stored and handled in RAM
There are a couple of things to keep in mind about character files in RAM that may trip you up if you're not aware of them.
First off, the file data in memory are not bit by bit the same as the file data in storage (DVD). A lot of words in the file actually are RAM offsets, at when the game reads the game data and puts them into RAM, it translates those offsets into actual RAM addresses. So something that looks like 00 00 AD 08 or something in the .dat file will look something like 81 12 86 A0. I usually search for the first 0x20 bytes of the file for this reason, as those bytes usually don't contain any RAM offsets.
Also, character files actually start loading as soon as you select them on the CSS, which presumably cuts down on loading times while selecting a stage. Stage files seem to only be loaded once you select the stage, though.
Remember
You only have about 55,000 extra bytes of space to work with in the memory card, assuming you clobber ALL of the name tags. This means you won't be able to patch everything you want, especially if those patches involve stage files.
SDR Lite's Patching Method
You should have enough to get you started with your own memory card character patching, but if you're curious about how I've patched stuff up in SDR Lite, read on.
General approach
So the first question is what form is the patch data going to be in? The SD Remix files take up megabytes of space, so storing them in full is completely out of the question, since I only have kilobytes to work with (about 55 kilobytes). This means I've got to create some sort of patch file to store the character data.
I'm not going to sit here and re-implement xdelta or anything crazy like that. Granted, I haven't taken a look at the xdelta code, but I imagine it's far more than just 100 lines of assembly code, and when you're working at such a low level of code, there's only so much you want to deal with. As a result, I've run with my own very simple diff algorithm, which is actually good because in Melee hacking, you're typically not dealing with chunks of data being moved around, but simply everything staying in place but changing values, which means we don't need most of xdelta or whatever anyway. I'm actually using a couple of different methods because I was learning while making SDR Lite, so I'll go over each thing individually.
PlCo.dat (address 80067AF0)
This was actually the third file I patched, but it's the easiest, so we'll just go over it first. Shout-outs to Achilles for giving me the original memory location of PlCo.dat to get me started.
At this point in memory, we know we're going to be reading data from PlCo.dat, and we have the address of it (offset by 0x9fe0), stored in r0. As a result, you should not use r0 except for reading. You should also not change the value of r3, because it is used for other things later.
From here you can make simple memory overrides. SDR doesn't change too many values, so I simply did this:
Kirby Cap patches (address 800180F4)
This was actually the second thing I patched, after character patches. This particular instruction is actually run once per active character slot and loads at least two character files, depending your character. There's the main PlXx.dat file loaded, then there's another file that's loaded (I don't know which one, but it might be the character costume file). Certain characters will also load other files. This is where I decided to patch Kirby's Cap files (PlKbCpXx.dat).
r30 points to a struct containing information about the file we're currently trying to read. It is at least 0x18 bytes big. At 0x04, it contains the first byte saying which type of file it is (from what I can tell, 02 is a main character file, like PlFe.dat, while 01 means it's an auxillary file, like costume files or Kirby's Cap files). The half word that ends this word is a file id, which, as far as I can tell, is unique for every file in the game. Some examples of what this is for various files:
What I do is I simply check that the first byte is a 1, then I have an array in memory card that holds a file id => patch data location, so it's a simply array look-up to get the patch data.
The actual patch data I'm using for Kirby Cap files is pretty easy because I can take advantage of the fact that none of the changes that SDR does to the Kirby cap files change any of the RAM offsets in the files. As a result, I can simply write over the bytes that are different. As a result, the patch file format I ended up using was of the following format:
The algorithm as a result is pretty simple. 0x10(r30) contains a pointer to a struct specifically about the file's data storage in memory. The word at 0x4 in that struct is the pointer to where the actual file data starts in memory. I basically take this address and run it through an algorithm, which is basically:
Character patches (80068F24)
This is the first one I did, and if I could do it again, I'd probably just use the same method I used with the Kirby patches, because the memory location here is offset, much like PlCo.dat, but the offset is different for every character. You have to manually find what each offset is. Fortunately, this offset seems to be RIGHT after the hex sequence "FE000000 00000000 18000000" for every character, and this sequence only occurs once in every character file. I ended up manually adjusting all of my patch data, but it worked out okay in the end.
There's a couple of gotchas using this data, though. This is one of those times where the RAM offsets are going to be an issue, so I can't do simple byte overwrites like could with Kirby Caps. I won't know exactly what addresses the game is going to use, since the RAM offsets are based off of the file data's location in memory. You might be thinking well why don't you just add the offset yourself, since you know where the file is stored in memory? That would be great, but I don't know which words to apply that logic to, and it would increase the size of the patch files to put that data in to begin with.
The solution I came up with is instead of a basic overwrite, I created a patch for each character based off of ADDs on each WORD. What this mean is that I search for words that are different (instead of bytes) and if I find one, I take the difference between the two words and store them in the patch file. I can then take this difference, take the word in the character file data, and add the difference onto the word and store it back, making it effectively the patch. Here's the data format I'm using for the patch file:
The algorithm is similar to Kirby file patching. It takes the two half words and sees if they're both 0; if they are we're done. Otherwise, multiply the number of words by 4 to get the number of bytes and increase the file data pointer by that amount. Take the next "number of words different" words of the patch file and add it to the next "number of words different" words from the original file data and store it back into the original file data. Repeat.
There is, however, a problem with this method and that is you can't apply the same patch file twice, and the problem with this particular instruction injection point is that it is called FOR EACH player slot, and a character's data is store only ONCE in memory, so if you willy-nilly apply this without any checks, you'll apply the patch twice (or thrice, or even.. fourice) on the same character's data file and you'll be in a world of hurt. IN ADDITION, when you go back to the character select screen, if you don't change the character, the data IS NOT RELOADED from the disk, so it's still in the patched state.
My solution to fix this is to have a sanity check. I manually figure out the first byte in the modified file which has a changed byte that is exactly the same in the file as it is in memory, so that it is always the same (meaning it's not part of a RAM offset value). Once you've figured that out, you do a "sanity check" which is to see if the character's data file in memory at that location is the same as your sanity check. If it is the same, that means it's already been patched and you should not patch it again. If it isn't the same, that means it is a freshly loaded character file, so you should patch it. This would run before the character patcher.
Stage patches (80018130)
So this location that I found is very similar to the character one I found that I use for Kirby Cap patches. However, I also use my Omega toggle to see if I even want to load the altered version of the file or not. The way I do this is at the point where the game checks the stage's ID, I run some code to set another variable somewhere to the location of the stage patch data or 00000000 if I shouldn't patch the file. At the stage file reading injection point, I then check to see if that variable has been set and if it has, I use the patch data at the pointed location.
The logic here is pretty similar to the Kirby Patches, but the stage patches in SDR Lite use the RAM offsets stuff to, so you'll need to use the same patch method as the character patches. Doing "lwz r4, 0x10(r30)" then doing "lwz r4, 0x4(r4)" will get you the location of the stage file data in memory. The nice thing about this location is that the game reloads every stage every time you select it on the stage select screen, even if you've already selected it before (presumably to make space for game data). This means you don't have to do any sanity checks to make sure the patch hasn't already been applied. Also, the pointer to the stage file data starts at the beginning of the file, so you don't have to manage any offsets like you did with the character patches.
And thats it!
That's the basic methodology that I used to get SD Remix characters and hacked stages loading off of a memory card. This has been on my mind almost since I both knew about SD Remix and the memory card exploit, and I'm glad it's finally a reality.
I want to point out that the patching method listed here is not totally optimal. It is good enough for my purposes, but you can get the patch data sizes smaller if you wanted to. It's just more complicated, and doing all of this while learning all this stuff in the process was a big enough task in itself. Maybe you'll come up with a better algorithm and maybe you can get some of the more prohibitively expensive stage patches on the memory card, like Skyrule and Improved Fourside.
Or you can hack snapshots to get yourself some more space to store those stage patches.
Good luck, and happy hacking!
(For completion's sake, I've included my raw notes from making SDR Lite in a zip file for your perusal.)
Current known injection points
These are the places know where you can both alter the file data safely and where you have a pointer to the file's data loaded in memory.
Code:
PlCo.dat (offset by 0x9fe0): 80067AF0
Some character files (this loads the main character files AND other character files, like Kirby's Caps): 800180F4
Only Main character files (PlXx.dat), offset by a variable amount: 80068F24
Stage dats (Gr[X]Xx.dat): 80018130
If this isn't enough for you and you want to patch other files, such as music or whatnot, here is how I usually find new injection points:
- Search for the file name in memory as a string. Every file I've attempted to find has been in the DOL somewhere.
- If you found it in the DOL, convert that to the corresponding RAM address. Every file name string stored in the DOL that I've searched for has had a corresponding pointer to that string somewhere in memory.
- Do a read breakpoint on that spot in memory, and play through the game (you'll probably want interpreter core on) at the spot where you think that the file is being loaded (for all gameplay files, this is usually sometime after you select a stage on the SSS).
- You should have a list of instruction addresses now. In my experience, there's usually two times the file name is accessed, the first time is to tell the game "hey, here's the file, check that it's valid and start loading it if you haven't already". The second time is usually where it actually reads the data from the file and creates useful game data structures from it.
- You should try and hit the second breakpoint again. Once you hit the breakpoint, take the first 0x20 bytes of the file you're searching for and do a Dolphin memory search for it. I find that searching for the first 0x20 bytes is enough to find one one instance of the file, and by the time you hit this second breakpoint, the file should have already loaded in Dolphin (or at least the first part anyway). If there are no hits, step through the code and research until you find it.
- Now that you know that the file is stored somewhere in RAM, do read breakpoints on the first 0x20 bytes on memory. You should have a list of addresses where it has tried to access the file data. At these instructions, the game has somewhere in its registers the address to the file data in RAM. If you analyze the code, you'll probably be able to figure out which ones it has.
- Hopefully somewhere here is an indication of which character/stage/cap/music/sound/menu file you're loading. There's usually at least a file ID or something that can help you identify what exactly you're looking at. I've found that the different file types typically have separate code paths, but within each file type, you could be running into any number distinct files, so you can't just patch haphazardly.
- ????
- Profit!
How files are stored and handled in RAM
There are a couple of things to keep in mind about character files in RAM that may trip you up if you're not aware of them.
First off, the file data in memory are not bit by bit the same as the file data in storage (DVD). A lot of words in the file actually are RAM offsets, at when the game reads the game data and puts them into RAM, it translates those offsets into actual RAM addresses. So something that looks like 00 00 AD 08 or something in the .dat file will look something like 81 12 86 A0. I usually search for the first 0x20 bytes of the file for this reason, as those bytes usually don't contain any RAM offsets.
Also, character files actually start loading as soon as you select them on the CSS, which presumably cuts down on loading times while selecting a stage. Stage files seem to only be loaded once you select the stage, though.
Remember
You only have about 55,000 extra bytes of space to work with in the memory card, assuming you clobber ALL of the name tags. This means you won't be able to patch everything you want, especially if those patches involve stage files.
SDR Lite's Patching Method
You should have enough to get you started with your own memory card character patching, but if you're curious about how I've patched stuff up in SDR Lite, read on.
General approach
So the first question is what form is the patch data going to be in? The SD Remix files take up megabytes of space, so storing them in full is completely out of the question, since I only have kilobytes to work with (about 55 kilobytes). This means I've got to create some sort of patch file to store the character data.
I'm not going to sit here and re-implement xdelta or anything crazy like that. Granted, I haven't taken a look at the xdelta code, but I imagine it's far more than just 100 lines of assembly code, and when you're working at such a low level of code, there's only so much you want to deal with. As a result, I've run with my own very simple diff algorithm, which is actually good because in Melee hacking, you're typically not dealing with chunks of data being moved around, but simply everything staying in place but changing values, which means we don't need most of xdelta or whatever anyway. I'm actually using a couple of different methods because I was learning while making SDR Lite, so I'll go over each thing individually.
PlCo.dat (address 80067AF0)
This was actually the third file I patched, but it's the easiest, so we'll just go over it first. Shout-outs to Achilles for giving me the original memory location of PlCo.dat to get me started.
At this point in memory, we know we're going to be reading data from PlCo.dat, and we have the address of it (offset by 0x9fe0), stored in r0. As a result, you should not use r0 except for reading. You should also not change the value of r3, because it is used for other things later.
From here you can make simple memory overrides. SDR doesn't change too many values, so I simply did this:
Code:
lis r12, 0x[first half-word]
ori r12, r12, 0x[second half-word]
stw r12, 0x[offset](r0)
This was actually the second thing I patched, after character patches. This particular instruction is actually run once per active character slot and loads at least two character files, depending your character. There's the main PlXx.dat file loaded, then there's another file that's loaded (I don't know which one, but it might be the character costume file). Certain characters will also load other files. This is where I decided to patch Kirby's Cap files (PlKbCpXx.dat).
r30 points to a struct containing information about the file we're currently trying to read. It is at least 0x18 bytes big. At 0x04, it contains the first byte saying which type of file it is (from what I can tell, 02 is a main character file, like PlFe.dat, while 01 means it's an auxillary file, like costume files or Kirby's Cap files). The half word that ends this word is a file id, which, as far as I can tell, is unique for every file in the game. Some examples of what this is for various files:
Code:
For LinkCap (PlKbCpLk.dat): 0100027e
For Ness (PlKbCpNs.dat): 01000282
For Samus (PlKbCpSs.dat): 01000289oo
For Child Link (PlKbCpCl.dat): 01000274
For Pichu (PlKbCpPc.dat): 01000283
The actual patch data I'm using for Kirby Cap files is pretty easy because I can take advantage of the fact that none of the changes that SDR does to the Kirby cap files change any of the RAM offsets in the files. As a result, I can simply write over the bytes that are different. As a result, the patch file format I ended up using was of the following format:
Code:
half word of number of bytes that are the same
byte of number of bytes that are different
the bytes that are different
... repeat until done ...
00000000
- Add the bytes that are the same to the file data pointer
- Loop for every byte that is different:
- Write the current byte that is different to the current byte of the file data pointer
- Increment both the patch data pointer and the file data pointer
- Decrement the number of bytes that are different
- If we're at 0 bytes different, go back to reading bytes that are the same
- If you hit a combined value of bytes different and bytes same as 0 (USING AND, NOT ADD, otherwise FFFFFF01 + FF will read 0!), you know you're done patching.
Character patches (80068F24)
This is the first one I did, and if I could do it again, I'd probably just use the same method I used with the Kirby patches, because the memory location here is offset, much like PlCo.dat, but the offset is different for every character. You have to manually find what each offset is. Fortunately, this offset seems to be RIGHT after the hex sequence "FE000000 00000000 18000000" for every character, and this sequence only occurs once in every character file. I ended up manually adjusting all of my patch data, but it worked out okay in the end.
There's a couple of gotchas using this data, though. This is one of those times where the RAM offsets are going to be an issue, so I can't do simple byte overwrites like could with Kirby Caps. I won't know exactly what addresses the game is going to use, since the RAM offsets are based off of the file data's location in memory. You might be thinking well why don't you just add the offset yourself, since you know where the file is stored in memory? That would be great, but I don't know which words to apply that logic to, and it would increase the size of the patch files to put that data in to begin with.
The solution I came up with is instead of a basic overwrite, I created a patch for each character based off of ADDs on each WORD. What this mean is that I search for words that are different (instead of bytes) and if I find one, I take the difference between the two words and store them in the patch file. I can then take this difference, take the word in the character file data, and add the difference onto the word and store it back, making it effectively the patch. Here's the data format I'm using for the patch file:
Code:
half-word of number of words that are the same
half word of number of words different
a series of words taking the word from the modified file and subtracting the word from the original
... repeat ...
00000000
There is, however, a problem with this method and that is you can't apply the same patch file twice, and the problem with this particular instruction injection point is that it is called FOR EACH player slot, and a character's data is store only ONCE in memory, so if you willy-nilly apply this without any checks, you'll apply the patch twice (or thrice, or even.. fourice) on the same character's data file and you'll be in a world of hurt. IN ADDITION, when you go back to the character select screen, if you don't change the character, the data IS NOT RELOADED from the disk, so it's still in the patched state.
My solution to fix this is to have a sanity check. I manually figure out the first byte in the modified file which has a changed byte that is exactly the same in the file as it is in memory, so that it is always the same (meaning it's not part of a RAM offset value). Once you've figured that out, you do a "sanity check" which is to see if the character's data file in memory at that location is the same as your sanity check. If it is the same, that means it's already been patched and you should not patch it again. If it isn't the same, that means it is a freshly loaded character file, so you should patch it. This would run before the character patcher.
Stage patches (80018130)
So this location that I found is very similar to the character one I found that I use for Kirby Cap patches. However, I also use my Omega toggle to see if I even want to load the altered version of the file or not. The way I do this is at the point where the game checks the stage's ID, I run some code to set another variable somewhere to the location of the stage patch data or 00000000 if I shouldn't patch the file. At the stage file reading injection point, I then check to see if that variable has been set and if it has, I use the patch data at the pointed location.
The logic here is pretty similar to the Kirby Patches, but the stage patches in SDR Lite use the RAM offsets stuff to, so you'll need to use the same patch method as the character patches. Doing "lwz r4, 0x10(r30)" then doing "lwz r4, 0x4(r4)" will get you the location of the stage file data in memory. The nice thing about this location is that the game reloads every stage every time you select it on the stage select screen, even if you've already selected it before (presumably to make space for game data). This means you don't have to do any sanity checks to make sure the patch hasn't already been applied. Also, the pointer to the stage file data starts at the beginning of the file, so you don't have to manage any offsets like you did with the character patches.
And thats it!
That's the basic methodology that I used to get SD Remix characters and hacked stages loading off of a memory card. This has been on my mind almost since I both knew about SD Remix and the memory card exploit, and I'm glad it's finally a reality.
I want to point out that the patching method listed here is not totally optimal. It is good enough for my purposes, but you can get the patch data sizes smaller if you wanted to. It's just more complicated, and doing all of this while learning all this stuff in the process was a big enough task in itself. Maybe you'll come up with a better algorithm and maybe you can get some of the more prohibitively expensive stage patches on the memory card, like Skyrule and Improved Fourside.
Or you can hack snapshots to get yourself some more space to store those stage patches.
Good luck, and happy hacking!
(For completion's sake, I've included my raw notes from making SDR Lite in a zip file for your perusal.)
Attachments
-
17.6 KB Views: 73
Last edited: