NPA
Used in the following game(s):
- Demonbane
- Steins;Gate
Structure
Overall | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Size | Content | Description | ||||||||||||
4 Bytes | Index Size | |||||||||||||
? Bytes | Protected Index Data | |||||||||||||
? Bytes | Protected File Data |
Index Header | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Size | Content | Description | ||||||||||||
4 Bytes | File count | Number of index entries | ||||||||||||
Index Entry | ||||||||||||||
4 Bytes | Filename Length | |||||||||||||
? Bytes | Filename | Each character is 2 bytes | ||||||||||||
4 Bytes | File Size | |||||||||||||
4 Bytes | Offset | |||||||||||||
4 Bytes | Unknown | Always 0x00000000 |
Research
The index data is protected. The way the program reads and processes this space is by first loading 4 bytes at the start of the file that is the size of the protected index. It then loads the whole index into memory. It then puts some data into the XMM0 register, which looks like the key. So far, it looks like it's static but I'll have to check if that's true for other files. It then enters the main decoding loop and loads 16 bytes into the next register, XMM1. It then XOR XMM1 by XMM0. It then puts the decoded part back into memory. By using SIMD related stuff, the program can decode 16 bytes at once with just a few instructions compared to exponentiation more steps to decode 1 byte at a time with a different key, constantly moving data in and out of the general registers. Just need to figure out if I can find a C/C++ implementation that can let me do the same. (128bit number xor? o.O wut...)
Some notes about structure. File names appear to be 2 byte char strings (wstrings?).
Key = BD AA BC B4 AB B6 BC B4 Unsure if this applies to other games but it works for Steins;Gate.
Also, file data is protected in the same way the index data is.
Tools
Coming soon...