Romhacking.net

Romhacking => Programming => Topic started by: MeganGrass on October 05, 2013, 10:46:48 pm

Title: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 05, 2013, 10:46:48 pm
I'm sorry if this is the wrong section for such a topic.

I'm currently developing a SRAM modifier/creator (c/c++ with GUI) for various Metroid titles.

So far, I have completely mapped and documented all of Super Metroid and Metroid Zero Mission's SRAM, and I eventually plan to add support for Metroid Fusion, as well. Support for Super Metroid is 100% complete (with proper checksum calculation and placement).

...but...

I've ran into a problem with Zero Mission.

Without a proper algorithm to calculate a new checksum for Zero Mission's SRAM, completing support for it will be useless. Same deal for Fusion. Furthermore, my ARM7TDMI dis/assembly skills aren't too excellent, yet.

Can someone help with this matter, please?

EDIT:

SRAM is stored at 0x02038000 and loaded+checked at boot.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 17, 2013, 03:02:03 pm
I can probably poke at it, can you be more specific about what you want? My understanding is that you want to create saves from scratch and MZM uses a checksum to determine if the save is valid, so you want to know how the game makes the checksum?
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 17, 2013, 03:47:18 pm
I can probably poke at it, can you be more specific about what you want? My understanding is that you want to create saves from scratch and MZM uses a checksum to determine if the save is valid, so you want to know how the game makes the checksum?

Yep. :)

I need to know exactly how the game creates the checksum, so that I can do the same for my app.

Any help would most definitely be appreciated.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: snarfblam on October 17, 2013, 04:52:00 pm
You might also want to ask at the forums at metroidconstruction.com. There are a couple of MZM hackers there.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 17, 2013, 10:37:21 pm
This is what I've got so far:

The checksum function is located at 08074624, it takes input r0 = 0 when it's checking the save data. The format of the data at 02038000 is as follows:

02038000 + saveID*0x1220 + 80 is the start of a save slot's data, and saveID = 0,1 or 2. I'll refer to this offset as the SaveOffset. The game does 3 things to check if the save is valid.

1. The game adds all the words in the 0x1220 area and compares that to the value stored at [SaveOffset, 0x10]. These values should be equal in a valid save.
2. The game compares the words stored at [SaveOffset, 0x10] and [SaveOffset,0x14]. It checks if the words are bitflips of each other (i.e. [SaveOffset, 0x10] + [SaveOffset,0x14] = 0xFFFFFFFF)
3. There are 3 strings the game expects to find:
3a. The first string is at [SaveOffset,0], the game expects this string to be "ZERO_MISSION_010" (The exact byte sequence is the 16 bytes starting at 08411410.)
3b. The second string is at [SaveOffset,0x4F], the game expects this string to be "Planet Zebes" followed by the 4 bytes 0x2e, 0x2e, 0x2e, 0x20 (The exact sequence is at 08411420.)
3c. The third string is at [SaveOffset, 0x250], the game expects this string to be " - Samus Aran - "  (The exact sequence is at 08411430.)

If none of the strings match, the game will ignore the save data. If there is a partial match, the game will report the save data as corrupt. If the strings match, but 1 or 2 fail, the game also reports the data as corrupt. Otherwise the game thinks the save data is valid.

I haven't checked how the game actually creates the checksum, but looking at the procedure, this should work:
1. Add all the words in the save slot except the words at [SaveOffset,0x10], [SaveOffset,0x14] and subtract 1 (Call this X.) Store X in [SaveOffset,0x10] and -1-X in [SaveOffset,0x14].
1. Store the strings in their locations.

Here's a partial disassembly of the routine: http://pastebin.com/6vEhYbrm

If anything's vague feel free to ask for clarification :p
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 18, 2013, 07:15:46 pm
@snarfblam - Thanks for the link! I was previously unaware of that Metroid community.

Wow, many thanks, x0_000! :o

I'll try the method you describe, asap.

I'm just confused on a few things:

Quote
1. Add all the words in the save slot except the words at [SaveOffset,0x10], [SaveOffset,0x14] and subtract 1 (Call this X.) Store X in [SaveOffset,0x10] and -1-X in [SaveOffset,0x14].

Do I start at [SaveOffset,0x18] or [SaveOffset,0x00]?

Also, words for my compiler are 2bytes, is it the same size for GBA? Endian-swapping isn't an issue for me, but should I take it into account?
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 18, 2013, 07:39:45 pm
You start at SaveOffset, 0x0. When I say "word" I mean a sequence of 4 bytes, which are reversed in the ROM, so the sequence 0x0 0x1 0x2 0x3 in the ROM should be read 0x03020100. Also it might not be clear, but you save X and -1-X as a word as well.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 18, 2013, 08:13:04 pm
You start at SaveOffset, 0x0. When I say "word" I mean a sequence of 4 bytes, which are reversed in the ROM, so the sequence 0x0 0x1 0x2 0x3 in the ROM should be read 0x03020100. Also it might not be clear, but you save X and -1-X as a word as well.

Ah, okay. Seems simple enough.

I just needed clarity, because a WORD in my compiler is only 2bytes, as I stated, where a DWORD is 4bytes. I had a feeling there'd be something different about GBA architecture.

Again, many thanks for your help!
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 18, 2013, 10:02:06 pm
Cool, if what I suggested doesn't work then upload a test save somewhere and I'll debug whatever's happening.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 24, 2013, 10:32:45 pm
Hmm... that didn't seem to work.

download (http://www1.datafilehost.com/d/633f0d53)

I've provided a working SRAM file, in entirety - it won't be difficult to isolate the individual (0x1220 byte) save data.

If you figure a solution, please provide the mathematical algorithm in c/c++ format. :D
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 24, 2013, 11:38:10 pm
Assuming I get it working, what slot is it supposed to be in and what kind of save data should I expect?

EDIT: The save file only has data in the first save slot, the other 2 are empty. Although it looks like you also put data at where a hypothetical 4th save slot would be. That data is loading fine though when I put it in the other slot. Unless it's not supposed to load 69 HP, 58 minutes at Tourian?

As a reminder, the save slots IDs in the game are 0, 1 and 2, so their offsets are +0x80, +0x12a0 and +0x24c0.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 25, 2013, 12:15:00 am
Slot 0/A

(http://i.imgur.com/tKaqUBu.png)
(http://i.imgur.com/RhHNgbU.png)
(http://i.imgur.com/q5mi1l9.png)

I know these screenshots seem 'messed-up'/impossible, but they are the result of various modifications (and verified working). If you're curious, SRAM can be modified after bootup, hence how I was able to map it without a checksum algorithm. The checksum will be recalculated at system shutdown or player death (return to title).

October 25, 2013, 12:18:48 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Although it looks like you also put data at where a hypothetical 4th save slot would be.

That's quite interesting, but no, I did not put data into the hypothetical 4th save slot. Perhaps, it is a temporary buffer area?
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: KingMike on October 25, 2013, 12:27:04 am
Would a Zero Mission SRAM Checksum also need to include password memory for the unlockable NES game?
Or is that already part of the SRAM data?
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 25, 2013, 12:33:55 am
Slot 0/A
I know these screenshots seem 'messed-up'/impossible, but they are the result of various modifications (and verified working). If you're curious, SRAM can be modified after bootup, hence how I was able to map it without a checksum algorithm. The checksum will be recalculated at system shutdown or player death (return to title).

That's quite interesting, but no, I did not put data into the hypothetical 4th save slot. Perhaps, it is a temporary buffer area?
In that case, what is the problem? The checksum is fine, and the save data is being read. What kind of behavior are you expecting this save data to have?
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 25, 2013, 12:46:56 am
Would a Zero Mission SRAM Checksum also need to include password memory for the unlockable NES game?
Or is that already part of the SRAM data?

Good question, I'll have to get back to you on that. Guesstimate: probably.

In that case, what is the problem? The checksum is fine, and the save data is being read. What kind of behavior are you expecting this save data to have?

Sorry, I should have specified - the SRAM is modifiable while in memory, using VBA. :P

I need an algorithm for the checksum, so that I can create/edit savegames from scratch, without the use of an emulator. Again, any help is very much appreciated, and you will be credited in the app that I finish creating.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 25, 2013, 12:58:43 am
Well, what I posted earlier should work? I don't code in C so here's the pseudo code algorithm:

Code: [Select]
saveOffset = saveID*0x1220 + 0x80
rom.write("ZERO_MISSION_010", saveOffset) ; 16 characters
rom.write("Planet Zebes... ", saveOffset+0x4f) ; that's Planet[Space]Zebes...[SPACE] for a total of 16 characters
rom.write(" - Samus Aran - ", saveOffset+0x250) ; [Space]-[Space]Samus[Space]Aran[Space]-[Space] for a total of 16 characters

saveValue = 0
for i from 0 to 3:
    saveValue += rom.readWord(saveOffset + i*4) ; that's 4 bytes, reversed
    saveValue && 0xFFFFFFFF ; bitwise and

for i from 6 to 1159:
    saveValue += rom.readWord(saveOFfset + i*4)
    saveValue && 0xFFFFFFFF

checkSum = (saveValue - 1) && 0xFFFFFFFF
negCheckSum = (-1 - checkSum) && 0xFFFFFFFF
rom.writeWord(checkSum, saveOffset+16)
rom.writeWord(negCheckSum, saveOffset+20)
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 25, 2013, 10:41:36 am
Well, that certainly worked, x0_000. Many thanks to You! :beer:

In your initial post, you made it seem like the strings are to be written afterward, which is exactly where I went wrong.

Anyways, it's fixed now, and here's the code in C (for future reference from anyone interested):

Code: [Select]
// This brief example sums an extracted save slot data (0),
// beginning at 0x80 in the SRAM file (0x1220 bytes).

signed int Sum = 0;
signed int Buf = 0;
signed int NegSum = 0;
signed long int _Offset = 0x00; // Starting at "ZERO_MISSION_010" string

for(unsigned int n = 0; n < 1159; n++, _Offset+=0x04)
{
switch(_Offset)
{
case 0x10:
case 0x14:
break;
default:
fseek(_File, _Offset, SEEK_SET);
fread(&Buf, 4, 1, _File);

Buf && 0xFFFFFFFF;
Sum += Buf;
break;
}

}

Sum -= 1;
NegSum = (-1 - Sum);
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: x0_000 on October 25, 2013, 01:13:58 pm
Aha! Good to see it works now.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on October 31, 2013, 02:11:58 pm
Small Progress Report:

The "hypothetical 4th save slot", mentioned earlier in this thread, isn't a buffer area.

It is a backup slot. In fact, the area 0x36E0~0x6D40 (0x1220*3) is reserved for backup-copies of the three save games.

For example, if the data in save slot #2 is corrupt, you will receive the following error message, and the backup located at 0x4900 will be copied to 0x12A0 (the area reserved for save slot #2):

(http://i.imgur.com/HRBGfLn.png)

That said, each save slot ID is stored twice in the SRAM and should be properly handled during modification, deletion, copy, etc.

November 02, 2013, 12:57:37 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Small Progress Report:

Metroid Fusion uses the same algorithm for checksum calculation, only the SRAM is structured slightly different.

Each save game is 0x1200 bytes, and data begins at offset 0x200 in the SRAM. Like Zero Mission, each save game is copied for backup purpose, but again, structured differently.

Code: [Select]
Metroid Fusion Save Data
0x0200 Save Game A
0x1400 Save Game A (backup-copy)
0x2600 Save Game B
0x3800 Save Game B (backup-copy)
0x4A00 Save Game C
0x5C00 Save Game C (backup-copy)
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on November 07, 2013, 03:58:20 pm
I can haz special edition GBA?! :D

(http://i.imgur.com/FDrnACs.png)

^ I have no idea how to change the ID, as it seems to be hardcoded into the ROM.


I've also made more progress with the overall SRAM of Zero Mission... and the amount of checksums this thing undergoes is fucking ridiculous.

1 checksum for the header + two backups (total of 3)
1 for each save game+backup (total of 6)
1 for each 'key' setting (total of 4)
1 for 'time attack' + backup (total of 2)
1 for original Metroid data + backup (total of 2)

...for a grand total of 17 checksums (!), and I haven't even looked into the button log info for the Demo that plays at the title screen (produced by Debug ver. ROM, usable in retail).


The original Metroid data is strange (to me), and any attempt to modify it results in erasure. I included John Ratliff's password algorithm code into my app, to see if the raw and/or converted data is the same as MZM data... and it is not.

The original Metroid data begins at offset 0x7FD8, and backup is stored at 0x7FB0. Any help figuring this last piece of the puzzle would be appreciated.


Furthermore, because I went through the trouble of including John Ratliff's password algorithm, the app I am creating will be a universal savegame creator/modifier for the following games:

Metroid
Metroid II (nothing coded, yet)
Super Metroid
Metroid Fusion
Metroid Zero Mission

With the exception of figuring out how original Metroid data is handled for MZM, the only thing left to do is creation of GUI dialog, so, this app will be finished soon.
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: KingMike on November 07, 2013, 07:23:40 pm
Is the original Metroid actual data or just a password? Are you sure it decodes to a valid password?
(like I know the password ENGAGE RIDLEY MOTHER F***ER that crashes a real NES, most likely because it causes the game to jump to invalid code, and supposedly will crash a 3DS, will just reset to the title screen on the GBA)
(as in, that password uncensored will pass the NES game's checksum test even though its data is not valid)
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: MeganGrass on November 07, 2013, 08:11:35 pm
A very small amount of data is stored for the original Metroid.

Save data for original Metroid is 0x28 bytes, and begins with the following 'header':

Code: [Select]
Hex: 11 19 19 30 52 4F 49 44 5F 33 5F 42
ASCII: ...0ROID_3_B

The rest of the data...

Code: [Select]
57 CC 00 20 00 00 00 00 00 00 00 00 00 02 06 06 00 00 50 36 A4 BB 66 46 64 66
...somehow produces the following password:

002000 000000
00W06O 0000bD


As mentioned, I ported the essential code from John Ratliff's password generator, ran that password through it and dumped both the raw and decoded data - no match. It doesn't even resemble the data provided in the Zero Mission SRAM.

I should note that the password generator code was successfully ported, and is verified to be working 100% properly - there isn't any error.

Here are both the raw and decoded forms of data, from the password above, ran through the password algorithm:

Code: [Select]
00 00 80 00 00 00 00 00 00 00 08 00 19 80 00 00 09 4D 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 10 00 33 00 00 00 00 09 4D 00 00 00 00 00 00

Any attempt to manually modify the data will result in a black screen upon boot of original Metroid; pressing start button will go to the title screen. The save data gets erased and the password is reset to NULL (all zeroes).

That said, I believe the MZM data for original Metroid is custom, unless the data goes through more conversions and en/decodings (note: I never looked into FDS savegame data).
Title: Re: Metroid Zero Mission - SRAM Checksum
Post by: KingMike on November 07, 2013, 10:51:38 pm
I would doubt it, even the Japanese version of MZM contained the NES version of Metroid (the FDS version was only released in the Famicom Mini version of Metroid).