Page 1 of 1

Bloodstained: Curse of the Moon 1 & 2 stuff

Posted: Sun May 02, 2021 6:48 am
by xttl
Hello everyone, I managed to find out very little information about these games from the interwebs, so maybe someone will find this useful.

Here's a tool for decrypting/encrypting (if you can really call it encryption, it's not using AES or any other real encryption algorithm) datafiles from COTM1 and COTM2. Not all files encrypted, and I think some are compressed in addition to being encrypted. It's a very simple single file C program, should compile and work fine with gcc, clang, msvc, pretty much anything.

It may also work for some other Inti Creates games, but I haven't tried.

I have no idea where the game code reads or calculates the keys for the "encryption algorithm", but it seems there are four different possible keys used with the same decryption code, one per data type ("obj", "bft", "set" or "scroll").

The same keys seem to work for both COTM1 and COTM2 on all platforms.

Also, in the PC versions of both games, the filenames have been obfuscated changing each file's name to the MD5 hash of the actual filename. It is possible to recover the original filenames by logging them as the game accesses them (by eg. hacking the binary to report them via OutputDebugStringA), or using file listings from console versions which don't have obfuscated filenames. Note that for some filenames, you'll need to add a platform specific "Win/" directory prefix before hashing the filename (on Switch, these files would be in an actual "NX/" subdirectory inside the romfs, for some reason there is no equivalent subdirectory inside the PS4 version's package).

Using these methods, I have recovered original filenames for all but two of the files in the the DataHash directory on PC for COTM2. (I played through the game multiple times taking different routes, but the logger didn't catch anything which would match those two when MD5 hashed, unfortunately it's not really feasible to brute force the remaining ones, at least not with only a single albeit reasonably powerful GPU, the filenames could be up to 20-30 characters or even more, and may contain at least lowercase and capital letters, numbers, underscores and a single dot.)

For COTM1, I have recovered 261 of 296 filenames based on file listings from console versions. I'll need to play through it a few times with a logger patched one day...

Next up is going to be figuring out the actual map and background graphics formats. I want to write a program which can show the maps. :-)

Btw. if you want to look at them, use the "set" key for map*.stb files and "scroll" key for map*.scb files. *.osb files use the "obj" key.

The zip includes the encdec.c program and MD5 filename hash lists for COTM1 and COTM2.
inti_encdec.zip
edit: oh yeah, if you rename map00.stb to map01.stb (look at the hash lists), you'll get a debug map (in both games) when you start the game! nothing that interesting or useful there, though.

edit2: forgot the line for ARGV0 in the args enum...

edit3: "bft" key is used for fonts, and the keys for all four data types are generated like this:

Code: Select all

#define WTFSTRING "90210"
#define BASEKEY 0xA1B34F58CAD705B2LL

uint64_t type2key (const char *type)
{
  uint64_t key;
  int i, l;
  char buf[12];
  
  strcpy(buf,type);
  strcat(buf,WTFSTRING);
  
  l = strlen(buf);
  
  key = BASEKEY;
  
  for (i=0; i<l; i++)
  {
    key += buf[i];
    key *= 141;
  }
  
  return key;
}
(this gives correct 64-bit keys with input "obj", "bft", "scroll" or "set")

The scroll, font and obj data have been zlib compressed before obfuscation, set data seems uncompresed. The first four bytes are a header which tells the required length for decompression buffer.

Here are raw RGBA views of BMPFont.bfb and Win/map01.scb after deobfuscation and zlib decompression (imgur links because it seems only one attachment per post is permitted and I'll only make a 2nd post when/if I can do something interesting like editing the stage layout, or someone else posts which just happened):

pic1
pic2

I stll don't know the actual header (after decompression), stage layout, etc., etc. formats.

I changed the name of the program to inti_encdec since it also works for other Inti Creates games. The version in the zip can now decode/encode larger files which are found in games other than COTM1/COTM2. It can also now decode/encode the system and game save data files in COTM1 and COTM2! (but probably not any of the other games, the save keys are different between COTM1 and COTM2 so probably the other games all use their own keys too).

I have also added file lists for other games to the zip (thanks RandomTBush) plus added the missing files to the COTM1/COTM2 lists.


I have tested decoding & re-encoding the map01 files with it and the game still loads it fine. :) Next up will be figuring out the actual map formats...

Re: Bloodstained: Curse of the Moon 1 & 2 stuff

Posted: Mon May 03, 2021 6:08 am
by RandomTBush
Ah, if only I had this sorta thing earlier. Excellent! :)

I actually went through the effort of matching the MD5s to the filenames myself a while back, here's the remaining hash/filename pairs you missed from Curse of the Moon 1:

Code: Select all

b507cdff033c27d984488a2bc3f3d2ba MapList.json
c9b695137c3dbd390150e4348f074456 Patch/BMPFont.bfb
1bfe6e6cf774a0870c018295951bf12b Patch/Calibration.ttb
84e0bdd4f11b909afd106b92b7fa2eec Patch/Calibration00.osb
71252704d813442e58c71c759d4d4ad1 Patch/EndingText00.osb
f9cf939192ce50e965fa11c4a0de01b2 Patch/GraphicText00.osb
98fbc7acc38ac990b17a5378670d554c Patch/GraphicText04.osb
be2e9161a3a6bb7ef65ca32561ac77e4 Patch/IconClear00.osb
8689aef4b3ef37c2971f133a5f0a459e Patch/map01.scb
0fd633200c773c7e84f748b628328cc2 Patch/map01.stb
e60dfd11647f3c2e1177d03c2eb8fa0c Patch/map02.scb
32cc4ef02249169f6e0a7fc79054a1a7 Patch/map02.stb
c4c6b279e307d8b2f7f46fc63430e8b5 Patch/map03.scb
b004be0f1bee105e0833d8b6456b6b75 Patch/map03.stb
5c035e8886b9d1ce24515a858f7efdb2 Patch/map04.scb
1ea347e5b1a0403acf227c16e11eee22 Patch/map04.stb
2bf50e8a81ac3922e77961d4964c4bbe Patch/map05.scb
5af88824a4446fe0d2f1aaa909038549 Patch/map05.stb
88d5983aa1760c94ccc8dfe103b21382 Patch/map06.scb
02d49b6034dac68b8bb19fa07edf4fcd Patch/map06.stb
4c14f860a52c402993341f172fd74f4e Patch/map07.stb
ae64a0c89814868a34acb4b62200548c Patch/map08.scb
9f8740b5f4013f455c4092d25d7441ec Patch/map08.stb
268d9be0086f14534c599281eec71c0f Patch/map09.scb
a53f870e5c4c376ec19450a8e8ba3d7f Patch/map09.stb
4112b562760811b246db33484dce725b Patch/MapDemo00.osb
88023ef468a04af2f2901a6a3683cf11 Patch/MapDemo03.osb
48fb4636e9cd3dacf77a6a6bf98e5703 Patch/Openingext00_en.osb
ad3cd8a3bda596b1547359e2479e0625 Patch/Option.ttb
39b9333c89ce132badcc0c2de3a58912 Patch/OptionKeyboard.ttb
2f493b619a9cf9f79e8291655dbc5e36 Patch/PauseMenu.ttb
7ce96b6103c39567090f03eb5dff9e56 Patch/Side01.osb
635acf9a9f63b05d9b1ce9382633a8a6 Patch/Staffroll_Picture00.osb
ccda2e2e84f49dfd56530e35616a3b44 Patch/Title00.osb
8e2a602aadb120226e2393c6afb24dcf Patch/Window00.osb
And one from Curse of the Moon 2:

Code: Select all

7f51424d446ad5e968e5251366c617ce Win/Window00.osb
That should just leave one file from Curse of the Moon 2 (db5f673dd61144c9c37e7b388e74e42e), which apparently doesn't belong to CotM2 at all, as it's the Demonpillar (zk04_im0.osb) from Dragon Marked for Death.

(EDIT: I can also confirm that your program also works just fine with files from both Blaster Master Zero 2 and Mighty Gunvolt Burst! I assume Dragon Marked for Death will work too, if the leftover file in CotM2 is any indication.)
(EDIT the 2nd: Yep, Dragon Marked for Death also works, barring a handful of files.)

Re: Bloodstained: Curse of the Moon 1 & 2 stuff

Posted: Mon May 03, 2021 7:32 am
by xttl
Oh yeah, I got my file list for COTM1 from an unpatched Switch version, that explains why all the Patch/* files were missing. MapList.json was missed because I didn't think to check if any of the hashes from COTM2 match COTM1. The proper filename for the file from the wrong game could probably be found from the console versions of that game.

Btw. which RGBA viewer are you using? I can't figure out how to get the colors right in BinxelView. Wrong R/G/B/A byte ordering I guess, actually it seems the program may not have proper support for 32bpp RGBA at all, only 24bpp RGB.

I thought I could avoid having to write any graphics code until later (if/when I have enough of the formats figured out for drawing the actual stage maps), but if there's not a better raw RGBA data viewer I guess it can't be helped...

Re: Bloodstained: Curse of the Moon 1 & 2 stuff

Posted: Mon May 03, 2021 8:12 am
by RandomTBush
xttl wrote:
Mon May 03, 2021 7:32 am
Oh yeah, I got my file list for COTM1 from an unpatched Switch version, that explains why all the Patch/* files were missing. MapList.json was missed because I didn't think to check if any of the hashes from COTM2 match COTM1. The proper filename for the file from the wrong game could probably be found from the console versions of that game.

Btw. which RGBA viewer are you using? I can't figure out how to get the colors right in BinxelView. Wrong R/G/B/A byte ordering I guess, actually it seems the program may not have proper support for 32bpp RGBA at all, only 24bpp RGB.

I thought I could avoid having to write any graphics code until later (if/when I have enough of the formats figured out for drawing the actual stage maps), but if there's not a better raw RGBA data viewer I guess it can't be helped...
Yeah, that would explain it then, heh.

Anyway, I use TiledGGD for previewing the files, with the following adjustments: Image > Format > 32 Bit per pixel, Palette > Colour order > RGB, and Palette > Alpha Settings... > Uncheck "Ignore Alpha value", then you can just adjust the width and height with the arrow keys, and shift the image with Page Up/Page Down. Some files in CotM2 specifically (including the unused file) will look like an outline / silhouette in the program, that's because they use palettes located above the image (which is then applied to the image's red channel).

Re: Bloodstained: Curse of the Moon 1 & 2 stuff

Posted: Tue May 04, 2021 4:47 am
by xttl
Updated the zip in first post:
  • Turns out, the key is NOT supposed to be reset every 384kB, large files (which some Inti games other than COTM1/COTM2 have) can now be unpacked and repacked successfully. Thanks to RandomTBush for testing this.
  • Added system and game save data decryption/encryption for COTM1 and COTM2. The same code (actually it's just the same obfuscation applied twice with different keys) could also work for other Inti games, but game specific keys/keystrings are required.
  • Added three new possible asset types/keys to the list "txt20170401", "snd90210", "json180601", cannot be tested with any files from COTM1/COTM2. (unless with something from inside one of the large archive files..?)
(the save data may well be checksummed in addition to the obfuscation, I haven't tried to edit it yet)

I may need to update the tool to use memorymapped files, compress/decompress in chunks and/or encode/decode inside the same buffer to reduce memory use a bit if there are compatible games with even larger files out there...

edit: another little update:
- added key for tb2 files from Blaster Master Zero 2 & Dragon Marked for Death
- the program is using memory mapped files now, and decodes/encodes inside a single buffer (should require less memory for large files)