I made save editors for Sonic 3 and Sonic CD

Discussion in 'Engineering & Reverse Engineering' started by typhoon, Jun 21, 2020.

  1. I made a few Sonic-related web apps over the last year that I'd like to share with you guys to receive your input.

    Sonic 3 Save Editor

    Sonic 3 Save Editor (source code, format specification)

    I made this last September and posted it to Reddit to thunderous reception. As far as I know, it's the only editor implements the checksum algorithm used by the original game and works with original emulator saves. It can also do goofy things like enabling "Blue Knuckles" or assigning Death Egg Zone to Knuckles if you check "Show advanced options" (which reveals some extra save options as well). Based on Xfox Prower's format specification for the PC version.

    It originally only supported emulator saves, but I recently added support for the 1997 Sonic & Knuckles Collection, the 2011 Steam re-release, and Sonic 3 AIR. If anybody comes across a valid save that can't be opened in the editor or a save generated by the editor that can't be opened in one of the supported versions of Sonic 3, please post it here.

    (Edit: I recently reworked the Sonic 3 AIR part of the editor to work on persistentdata.bin rather than sram.bin. This lets it edit competition mode times as well.)

    Sonic CD Save Editor

    Sonic CD Save Editor (source code, console format, PC format, Retro format)

    I made this last week. It only supports emulator saves for the original Sega CD game. I've tested it in Gens and Kega Fusion, and it seems to work alright. I realize the original release is probably the least popular version of the game these days, so I don't expect that this will draw much interest. I do hope to add support for the 2011 Retro Engine release eventually.

    I'd also like to support the 1996 Sega PC release (for the sake of consistency with the Sonic 3 editor's support), but its save format looks completely inscrutable to me (maybe it's compressed?). If anybody knows of a resource that demystifies it any, please let me know (though, again, I understand that there probably isn't a ton of interest in the Windows 95 version of this game).

    (Edit: Now supports the 1996 Sega PC release and the 2011 Retro Engine release.)

    Tails Adventure Password Generator

    Tails Adventure Password Generator (source code)

    Oh, and I made this thing too, last November. It's based on Xfox Prower's password generator (which, like his S3&KC save editor, doesn't work in modern browsers anymore without some modification). It always generates the same password as Xfox Prower's generator, which, in my testing, is usually but not always a valid password. There isn't a nice disassembly of this game like Sonic 3, and I couldn't work out the password algorithm any better with a debugger, so this is probably as good as this will get unless somebody has some additional insight to share.

    Chaotix Save Editor

    Chaotix Save Editor (source code, format specification)

    And finally, an editor for the last of the classic 2D platformers. This one is fairly straightforward since, of course, there has only ever been one release of Chaotix. Tested in Gens, Kega Fusion, and PicoDrive.
    Last edited: Sep 21, 2020
  2. MainMemory


    Have no fear...Amy Rose is here! Tech Member
    Sonic CD PC
    Code (Text):
    1. signed int __stdcall WriteSaveData(int savenum, int *sdata, HFILE hFile)
    2. {
    3.   char PathName[256]; // [esp+Ch] [ebp-3E0h]
    4.   _BYTE *_sdata; // [esp+10Ch] [ebp-2E0h]
    5.   int i; // [esp+110h] [ebp-2DCh]
    6.   int Buffer; // [esp+114h] [ebp-2D8h]
    7.   HFILE _hFile; // [esp+118h] [ebp-2D4h]
    8.   _BYTE sdata2[720]; // [esp+11Ch] [ebp-2D0h]
    10.   if ( sdata )
    11.     _sdata = sdata;
    12.   else
    13.     _sdata = &dword_42CA70;
    14.   if ( hFile )
    15.   {
    16.     _hFile = hFile;
    17.   }
    18.   else
    19.   {
    20.     GetSaveFileName(PathName);
    21.     _hFile = lopen(PathName, 2);
    22.     if ( _hFile == -1 )
    23.     {
    24. LABEL_17:
    25.       MessageBoxA(0, aSaveDataErrorP, aSonicError_9, 0x10u);
    26.       if ( !hFile && _hFile != -1 )
    27.         lclose(_hFile);
    28.       return 0;
    29.     }
    30.   }
    31.   if ( hread(_hFile, &Buffer, 4) == -1 )
    32.     goto LABEL_17;
    33.   for ( i = 0; savenum > i; ++i )
    34.   {
    35.     if ( hread(_hFile, sdata2, 720) == -1 )
    36.       goto LABEL_17;
    37.   }
    38.   WriteSaveChecksum(_sdata);
    39.   DoWeirdSaveThing(_sdata, sdata2, 720);
    40.   if ( hwrite(_hFile, sdata2, 720) == -1 )
    41.     goto LABEL_17;
    42.   if ( !hFile )
    43.     lclose(_hFile);
    44.   return 1;
    45. }
    47. int __cdecl WriteSaveChecksum(char *a1)
    48. {
    49.   int result; // eax
    50.   unsigned int i; // [esp+Ch] [ebp-8h]
    51.   int v3; // [esp+10h] [ebp-4h]
    53.   v3 = 0;
    54.   for ( i = 0; i < 716; ++i )
    55.     v3 += *a1++;
    56.   result = v3;
    57.   *(_DWORD *)a1 = v3;
    58.   return result;
    59. }
    61. void __cdecl DoWeirdSaveThing(_BYTE *src, _BYTE *dst, int a3)
    62. {
    63.   int v3; // eax
    64.   int v4; // [esp+Ch] [ebp-4h]
    66.   srand(0x551u);
    67.   v4 = 0;
    68.   while ( v4 < a3 )
    69.   {
    70.     v3 = rand();
    71.     *dst = *src ^ (((v3 >> 31) ^ abs((_BYTE)v3)) - (v3 >> 31));
    72.     ++v4;
    73.     ++dst;
    74.     ++src;
    75.   }
    76. }
  3. Wow, thanks a lot. Very weird and interesting. Is this your own finding? I'd like to get the attribution right.

    So, basically:
    • The first four bytes of the file are always 0x00. (Edit: Not quite true, the first byte stores the currently selected save file, between 0 and 5.)
    • The rest of the file is broken into 720-byte sections (since the game supports multiple save files), which gives 6 sections. The last 4 bytes of each section are a checksum.
    • Each section is encoded using srand with a particular seed, presumably for obfuscation. The series that srand produces is implementation-specific, so I used msvc to reproduce it. Each byte in the section is xor-ed to the next word generated by rand. The provided code also does some other weird things (like shifting to the right by 31, which always gives 0 since msvc's rand gives 16-bit numbers, and then xor-ing that, which has no effect since xor with 0 doesn't do anything), which I assume is weirdness introduced by the compiler. We can also discard the high byte given by rand since we're working with bytes and not words (so it gets zeroed out anyway).
    Anyway, that lets me turn this nonsense (the highlighted part is the first save file) into this, which is definitely what I want. Interestingly, it's completely different from the Sega CD version's save format (for instance, it clearly uses ASCII for time attack initials whereas the Sega CD version simply indexes the sprite for the initial rather than using an actual character encoding). In comparison, Sonic & Knuckles Collection basically uses the same save format as Sonic 3 for the Genesis with minor changes (like no duplication, no checksum, and different start offsets). At any rate, I should be able to figure this out and add support for it over the weekend, which I'm happy about (and then the Retro Engine remake sometime after that).
    Last edited: Aug 23, 2020
  4. MainMemory


    Have no fear...Amy Rose is here! Tech Member
    Yeah, I just dug into the exe with IDA and that's what I found. Glad to know it helped!
  5. I updated my Sonic CD Save Editor to support the 1996 Sega PC release and the 2011 Retro Engine remake. If you accessed the older version of the editor, you'll probably get an error upon loading the page since a lot of things have changed; hit the "Reset" button on the bottom of the page to reset the local storage and do a Shift+Reload to reload without the cache.

    It took a bit longer than I expected because the three versions of the game use significantly different save formats and I had to rework parts of the editor (sometimes multiple times) to abstract out the differences (which included big things like how they handle multiple save slots and small things like how they handle times or even how they add up identical times slightly differently for the Time Attack total). I'm pleased with the way it came out, though, since (like the Sonic 3 editor) it lets you open or create a save in one format and then convert it to another if you want.

    The Retro support is based on the Windows version, since that's the only version I have, though it appears to be basically the same as the other versions going by this thread for the Android version and this thread for the iOS version.

    Additionally, I wrote save format specifications for posterity:

    I tried to write them in such a way that someone could create their own editor solely from the specifications if so inclined, which included documenting some of the subtler parts and providing examples when useful. I can add these to the wiki if people think it would be useful.

    (It's funny that the 1996 PC version has by far the most difficult save format to edit since it's obfuscated with a random number sequence that you need to disassemble the game to work out and then has a checksum on top of that, but the Retro version has achievements and leaderboards but its save format is wide open.)

    I also started early work on a Chaotix save editor since that's the only remaining classic-era game with battery saves. In theory, this should be fairly straightforward to figure out since it only stores three things (the current act for each attraction, the number of Chaos Rings obtained, and the total playtime). (Edit: It also stores the score and time of day.) It does use a checksum, though, and I imagine the disassembly is pretty hard to figure out since the 32X uses three CPUs in concert. I found the Sonic Retro Chaotix disassembly but can't open it in the version of IDA I have installed. (Edit: I installed a newer version of IDA and was able to open the Chaotix disassembly. It definitely looks like the checksum algorithm is in the 68k part and I'm close to having it worked out.)
    Last edited: Sep 2, 2020
  6. lordoftime


    Timelord Member
    Hi there I was wondering if while your updating stuff you had thaught about maybe adding support For S3 A.I.R?
  7. Sid Starkiller

    Sid Starkiller

    Virginia, USA
    Paying off student loans
    If he had, he would've already posted it here.
  8. The Sonic 3 editor supports AIR. It opens and writes the "persistentdata.bin" file.
  9. lordoftime


    Timelord Member
    There was no harm in asking was there?

    Excellent - very good to know!
  10. Chaotix Save Editor (source code)

    I completed it. The save format is pretty simple since it only stores 12 bytes of information per slot, but it was a bit of a pain finding the checksum algorithm in the disassembly. There are a couple of weird spots that I could probably smooth out later (the save format saves Knuckles and Charmy as the same value for some reason and doubles up on the times of day, and ideally, I'd come up with some more artful way of hiding these sorts of rough edges in the interface).

    As with Sonic CD, I wrote a save format specification if anyone is interested.

    That likely concludes my work on Sonic save editors until some fine day when Sega decides to port the Retro Engine Sonic 1 and 2 to the PC or commission a remake of Sonic 3 or Chaotix or something.
    Last edited: Sep 8, 2020
  11. BSonirachi


    Opa-Opa takes flight! Wiki Sysop
    Since the Sonic 3 Save Editor allows Blue Knuckles as an advanced option, do you think you could update it to add Knuckles and Flying Battery as options for Sonic 3 alone? As far as I know, both of them are valid values in Sonic 3 (with Flying Battery having its older icon) but load incomplete data when attempting to load them in the Mega Drive version, but in the S&KC version they load normally due to that version being based off S3&K's coding.
  12. That's a good idea. I went ahead and added both Knuckles and Flying Battery for Sonic 3 when "advanced options" is enabled. I also moved the platform selection to the top of the page like the Sonic CD editor. I recommend doing a Shift+Reload to reload without the cache so it shows the right zone icons and such.

    I also noticed that I had a mistake in the default data that prevented creating a valid Sonic 3-only save from scratch. I fixed this, but anyone who's used the editor before probably has to clear their cache for the new file to load properly. Or just load an existing valid save and base any modifications on that, which has always worked fine.