SD2 - themeldingwars/Documentation GitHub Wiki
Static Database, clientdb.sd2
located in system/db
is the database file that contains the stats and item info for the items and entities in the game.
- Reader and Writer have been implemented in FauFau: StaticDB.cs
- Decoding C++ Code below
- Magic is a signed int equaling
-629,491,106
- Most recent file version is (build 1861)
11
- Seems to be compressed using
deflate 1.2.8
with a window size of15
Always 128 bytes long
int32 Magic; // -629,491,106 | 0xDA7ABASE in big-endian
int32 Version; // 11 - 12
int32 FileSize; // Size of the file contents (After Header)
int32 Flags; // ???
int64 Timestamp;
char[104] FirefallPatch; // beta-xxxx, ascii encoded, null-terminated, zero padded
Starts at offset 128 with the length set in FileSize
in the header
The payload is encrypted with the help of a Mersenne Twister random number generator. The seed is the FNV hash of the patch version, e.g. beta-1869
. An implementation of the MT RNG can be found below, but it's not producing an inflatable stream.
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
unsigned int fnv(char* a1)
{
char v1;
int i;
v1 = *a1;
for(i = 0x811C9DC5; *a1; v1 = *a1) // FNV hash function
{
++a1;
i = 0x1000193 * (i ^ (unsigned int)v1);
}
unsigned int res = 33 * (9 * (8193 * i ^ ((unsigned int)(8193 * i) >> 7)) ^ (9 * (8193 * i ^ ((unsigned int)(8193 * i) >> 7)) >> 17));
return res;
}
struct MT {
uint32_t *next;
uint32_t items;
uint32_t mt[624];
};
static uint8_t MT_getnext(struct MT *MT) {
uint32_t r;
if (!--MT->items) {
uint32_t *mt = MT->mt;
unsigned int i;
MT->items = 624;
MT->next = mt;
for (i=0; i<227; i++)
mt[i] = ((((mt[i] ^ mt[i+1])&0x7ffffffe)^mt[i])>>1)^((0-(mt[i+1]&1))&0x9908b0df)^mt[i+397];
for (; i<623; i++)
mt[i] = ((((mt[i] ^ mt[i+1])&0x7ffffffe)^mt[i])>>1)^((0-(mt[i+1]&1))&0x9908b0df)^mt[i-227];
mt[623] = ((((mt[623] ^ mt[0])&0x7ffffffe)^mt[623])>>1)^((0-(mt[0]&1))&0x9908b0df)^mt[i-227];
}
r = *(MT->next++);
r ^= (r >> 11);
r ^= ((r & 0xff3a58ad) << 7);
r ^= ((r & 0xffffdf8c) << 15);
r ^= (r >> 18);
return (uint8_t)(r >> 1);
}
static void MT_decrypt(unsigned char *buf, unsigned int size, uint32_t seed) {
struct MT MT;
unsigned int i;
uint32_t *mt = MT.mt;
*mt=seed;
for(i=1; i<624; i++)
mt[i] = i+0x6c078965*((mt[i-1]>>30)^mt[i-1]);
MT.items = 1;
MT.next = MT.mt;
while(size--)
*buf++ ^= MT_getnext(&MT);
}
int main()
{
unsigned int hash = fnv("stabilization-1350");
std::ifstream is ("db.sdb", std::ios::binary);
if(is)
{
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
std::vector<char> buffer(length, 0);
//std::cout << "Reading " << length << " characters... \n";
// read data as a block:
is.read(buffer.data(), length);
if (!is)
std::cout << "error: only " << is.gcount() << " could be read\n";
is.close();
MT_decrypt(reinterpret_cast<unsigned char*>(buffer.data()), buffer.size(), hash);
std::ofstream os ("out.zip", std::ios::binary);
if(os)
{
std::copy(buffer.begin(), buffer.end(), std::ostream_iterator<char>(os));
os.close();
}
else
std::cerr << "Couldn't open out.zip\n";
}
}
struct FILE
{
struct HEADER // size 128b
{
uint magic; // 3665476190 // 0xDA7ABA5E
uint version;
uint payloadSize;
uint flags; // bitmask 13 = 1101
byte unknown[8];
char firefallPatch[9]; // beta-XXXX (larger for stabilization)
byte padding[95];
} header;
byte compressed[header.payloadSize];
} file;
- Latest: prod-1962
- Earliest: prod-1931
- Latest: beta-1869
- Earliest: beta-1475
- Latest: beta-1460
- Earliest: beta-1384
- Latest: beta-1297
- Earliest: beta-1297