Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.
Zero Tolerance for Disrespect

Chrono Cross PS1 Memory Card Checksum

Featured Replies

I'm having an issue with trying to hack a PS1 memory card save checksum. The game is Chrono Cross and the format is .MCS from the pSX emulator. I have provided two files to illustrate the issue. The only difference between them is address 0x13E7 and the last four bytes which are probably the checksum. It isn't a Checksum-32 or any other common checksum that I know of. I ran it through a web-based checksum fixer but I would rather just write my own editor program than use that one.

Chrono Cross.7z

  • Localization

In Silent Hill 1 on PS1 checksum is just a simple XOR operation on all bytes. Maybe this is the same

  • Author

I wrote some code to check this but it doesn't seem to work

for (int aa = 0; aa < byteFile.Length - 4; aa++)
{
	fileSum ^= byteFile[aa];
}

 

  • Localization

No, not the whole memory card. Try only on the save block, or more realistically only on one of the structures inside the save block. It is not for the whole memory card.

Edited by Sparagas

  • 1 year later...

Hi spamzilla,

I had a look at your two samples and I think the checksum is solved.

**Algorithm:** it's a plain unsigned byte sum, stored as a little-endian uint32.

- Sum every byte of the 8 KiB save block from block offset `0x0000` to `0x1FF7` (inclusive).

- Store the result as little-endian uint32 at block offset `0x1FFC`.

- In your `.mcs` files the block starts after the 128-byte header, so that's file range `0x0080`–`0x2077`, with the checksum at file offset `0x207C`.

- The 4 bytes at `0x2078`–`0x207B` (`06 01 00 00` in both files) are **not** included.

**Why I'm fairly confident:**

- Original checksum `0x0004DFF0`, modified `0x0004E074`. The difference is `0x84` = 132 = 192 − 60, exactly the change you made at `0x13E7`. That rules out XOR/CRC.

- Searching all contiguous ranges containing `0x13E7`, `[0x80, 0x2078)` is the only one whose sum matches.

- Taking your original file, setting `0x13E7` to 192 and recomputing gives a file byte-identical to your "(Modified)" file.

That's also why the whole-file XOR didn't work.

**Tool:** I wrote a small Python script, `cc_checksum.py`, with no dependencies:

```

python3 cc_checksum.py verify save.mcs

python3 cc_checksum.py fix save.mcs # in place

python3 cc_checksum.py fix save.mcs -o out.mcs

```

It accepts single-block `.mcs` (8320 bytes) or a raw 8192-byte save block.

**Caveats:**

- I only had one pair of files, and haven't test-loaded an edited save in an emulator yet. Please confirm it loads on your side.

- If you have saves from other slots or later in the game, they'd help confirm the `0x1FF8` field never matters.

Hope this helps with your editor!

cc_checksum.py

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.