notes
[ru / en]

Adding coins to your balance in LEGO Games

2026.05.05

Attention! This is not for all Lego games.

Naturally, this is done by editing a saved game.

However, the data is checked against the checksum.

That's what we're going to explore.

But if you're lazy, you can use this tool:

  • LEGO® Indiana Jones™ 2
  • LEGO® Star Wars™: The Complete Saga
  • LEGO® Batman™
Select a saved game file, enter your balance, and receive the file.
The file is being edited in the browser. Don't forget about backups.

If you're interested, there are two ways: find and use a checksum generation algorithm.

Or patch the game itself at the point where the checksum is checked.

Let's explore LEGO Indiana Jones 2 as an example.

Where is the balance?

First, we take a saved game file from:

  • %appdata%\LucasArts\LEGO® Indiana Jones™ 2\SavedGames
  • %appdata%\..\Local\LucasArts\LEGO Star Wars - The Complete Saga\SavedGames
  • %appdata%\..\Local\Warner Bros. Interactive Entertainment\LEGO Batman\Saved Games

The file itself is a Rich Saved Games format with the following structure:

typedef struct _RICH_GAME_MEDIA_HEADER\n{\n    DWORD         dwMagicNumber;\n    DWORD         dwHeaderVersion;\n    DWORD         dwHeaderSize;\n    LARGE_INTEGER liThumbnailOffset;\n    DWORD         dwThumbnailSize;\n    GUID          guidGameId;\n    WCHAR         szGameName[RM_MAXLENGTH];\n    WCHAR         szSaveName[RM_MAXLENGTH];\n    WCHAR         szLevelName[RM_MAXLENGTH];\n    WCHAR         szComments[RM_MAXLENGTH];\n} RICH_GAME_MEDIA_HEADER;

We are interested in two values:

  • dwMagicNumber - four bytes should be equal to HMGR, indicating that the file is the same
  • dwHeaderSize - this is the size of the entire header, followed by custom data that is summed up

We look at the current balance, convert it to HEX, and search for it in the file. Don't forget about the byte order, as we have little endian. In other words, if HEX = 00005F32, we should search for 32 5F 00 00.

In LEGO Indiana Jones 2, this is the offset 0x22FF0 from the beginning of the file. Alternatively, the offset within the data for the checksum is (0x22FF0-dwHeaderSize)=0x20FC8

The generation algorithm

The checksum is calculated by simply adding (add) four bytes (dword) to the constant 0x5c09999:

09AB1D2 mov     esi, 05C0999\n09AB1D7 jle     09AB1EA\n09AB1D9 mov     edx, [esp+4+arg_0]\n09AB1DD lea     ecx, [ecx+0]\n09AB1E0 add     esi, [edx+ecx*4]\n09AB1E3 add     ecx, 1\n09AB1E6 cmp     ecx, eax\n09AB1E8 jl      09AB1E0

And it starts exactly after RICH_GAME_MEDIA_HEADER header, that is, with an offset of dweadersize bytes, and continues to the end of the file minus 8 bytes, which are:

  • 4 bytes is the checksum that is compared with the one calculated earlier
  • 4 bytes is the percentage of passing in the game

That is, we get this code:

start = dwHeaderSize;\nlength = filesize - dwHeaderSize - 8;\nchecksum = 0x5C0999;\n\nfor (i = start; i < length; i = i + 4) {\n\tchecksum += data[i]; // DWORD, 4 bytes\n}

Game Patch

You can take a different approach. Instead of recalculating the checksum every time, you can simply change the number of coins by patching the LEGOIndy2.exe file.

09AB4FF cmp     eax, [edi+ebx] ; 3B 04 1F\n09AB502 jnz     09AB529 ; 75 25

If the checksums are not equal, it jumps away. You just need to not jump. Change one byte 25 -> 00:

09AB502 jnz     09AB504 ; 75 00

For LEGOStarWarsSaga.exe and LEGOBatman.exe, you need to jump. We also look for 3B 04 1F:

0XXXXXX cmp     eax, [edi+ebx] ; 3B 04 1F\n0XXXXXX jz      0XXXXXX ; 74 12

The same checksum check, and if equal, then jumps to the right place. You need to force 74 -> EB:

0XXXXXX jmp     0XXXXXX ; EB 12
more topics: reverse, patch, lego