I usually use the usb gecko. But I went ahead and went through the steps to do this with dolphin. It turns out you need the debugfast build, which shuffle was a great help with. The regular build can set execute breakpoints, but not ram read/write ones. Anyways, after building dolphin with the debugfast stuff, heres how I did it.
Open up the save file and change a byte in it to force a corruption.
Start dolphin with the "-d" option for debugging. Go to the "view" menu and enable the memory, breakpoints, ect. Then start the game and let it run up to the point where it says the save is broken
Find some data in you save that is not likely to be in the RAM outside your save. My character's name is Pune, so I used that.
Dig through the RAM in dolphin and eventually you end up with this section. It looks like a section right in the middle of the save file.
Go to the breakpoint tab, and click the "+MC". Then enter the memory range where the save was, select "read", and select "break".
Now restart the game. Let it run till it hits the breakpoint and freezes.
Hop to this instruction in your favorite disassembler. It looks like this is our bitch. r3 is the pointer to memory, r4 is the length. The "mr %r3 %r6" near the end means that r6 will be the return value See all those "lbz"? Those are reading 1 byte at a time, and adding it to r6. So there is their kindergarden checksum.
If youre in IDA, right click the function and chart the xrefs. These are the 6 functions that are calling the checksum. The first 3 here never check the
result, they only compute it. The last 3 of them actually check the result and compare the result.
This is the first one I looked at. There is a magic word or whatever stored right before the checksum that must match a handcoded value. They
load the location of the section of the save they want to check and a length, save the current checksum in r31, and set the one in the save file to 0.
then calculate the thing. And then store the old value back in the save and compare the expected and actual results. It sets r3 to 0 for failure and
1 for success.
the other 2 calls to the checksum function we care about are very similar. they are varying the length and location, as well as some magic word
stored directly ahead of the sum.