Bloodstained: Curse of the Moon 1 & 2 (and other Inti Creates) stuff
Posted: Sun May 02, 2021 6:48 am
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.
(removed, see viewtopic.php?p=176034#p176034)
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:
(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...
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.
(removed, see viewtopic.php?p=176034#p176034)
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;
}
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...