mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2024-11-30 07:10:37 +00:00
122 lines
4.4 KiB
C++
122 lines
4.4 KiB
C++
#include "metadatastringdec.h"
|
|
|
|
#include <stdexcept>
|
|
#include <random>
|
|
#include <stdio.h>
|
|
|
|
struct m_header_fields {
|
|
char filler1[0x18];
|
|
uint32_t stringLiteralDataOffset; // 18
|
|
uint32_t stringLiteralDataCount; // 1c
|
|
uint32_t stringLiteralOffset; // 20
|
|
uint32_t stringLiteralCount; // 24
|
|
char filler2[0xd8 - 0x28];
|
|
uint32_t stringOffset, stringCount;
|
|
};
|
|
|
|
struct m_literal {
|
|
uint32_t offset, length;
|
|
};
|
|
|
|
void generate_key_for_global_metadata_header_string(uint8_t* data, size_t len, uint8_t* literal_dec_key) {
|
|
if (len < sizeof(m_header_fields))
|
|
throw std::out_of_range("data not big enough for global metadata header");
|
|
|
|
uint32_t values[0x12] = {
|
|
*(uint32_t *) (data + 0x60),
|
|
*(uint32_t *) (data + 0x64),
|
|
*(uint32_t *) (data + 0x68),
|
|
*(uint32_t *) (data + 0x6c),
|
|
*(uint32_t *) (data + 0x140),
|
|
*(uint32_t *) (data + 0x144),
|
|
*(uint32_t *) (data + 0x148),
|
|
*(uint32_t *) (data + 0x14c),
|
|
*(uint32_t *) (data + 0x100),
|
|
*(uint32_t *) (data + 0x104),
|
|
*(uint32_t *) (data + 0x108),
|
|
*(uint32_t *) (data + 0x10c),
|
|
*(uint32_t *) (data + 0xf0),
|
|
*(uint32_t *) (data + 0xf4),
|
|
*(uint32_t *) (data + 8),
|
|
*(uint32_t *) (data + 0xc),
|
|
*(uint32_t *) (data + 0x10),
|
|
*(uint32_t *) (data + 0x14)
|
|
};
|
|
|
|
uint64_t seed = ((uint64_t) values[values[0] & 0xfu] << 0x20u) | values[(values[0x11] & 0xf) + 2];
|
|
|
|
std::mt19937_64 rand (seed);
|
|
|
|
for (int i = 0; i < 6; i++) // Skip
|
|
rand();
|
|
|
|
auto key64 = (uint64_t *) literal_dec_key;
|
|
for (int i = 0; i < 0xa00; i++)
|
|
key64[i] = rand();
|
|
}
|
|
|
|
void recrypt_global_metadata_header_string_fields(uint8_t *data, size_t len, uint8_t *literal_dec_key) {
|
|
if (len < sizeof(m_header_fields))
|
|
throw std::out_of_range("data not big enough for global metadata header");
|
|
|
|
uint32_t values[0x12] = {
|
|
*(uint32_t *) (data + 0x60),
|
|
*(uint32_t *) (data + 0x64),
|
|
*(uint32_t *) (data + 0x68),
|
|
*(uint32_t *) (data + 0x6c),
|
|
*(uint32_t *) (data + 0x140),
|
|
*(uint32_t *) (data + 0x144),
|
|
*(uint32_t *) (data + 0x148),
|
|
*(uint32_t *) (data + 0x14c),
|
|
*(uint32_t *) (data + 0x100),
|
|
*(uint32_t *) (data + 0x104),
|
|
*(uint32_t *) (data + 0x108),
|
|
*(uint32_t *) (data + 0x10c),
|
|
*(uint32_t *) (data + 0xf0),
|
|
*(uint32_t *) (data + 0xf4),
|
|
*(uint32_t *) (data + 8),
|
|
*(uint32_t *) (data + 0xc),
|
|
*(uint32_t *) (data + 0x10),
|
|
*(uint32_t *) (data + 0x14)
|
|
};
|
|
|
|
uint64_t seed = ((uint64_t) values[values[0] & 0xfu] << 0x20u) | values[(values[0x11] & 0xf) + 2];
|
|
|
|
std::mt19937_64 rand (seed);
|
|
|
|
auto header = (m_header_fields *) data;
|
|
header->stringCount ^= (uint32_t) rand();
|
|
header->stringOffset ^= (uint32_t) rand();
|
|
rand();
|
|
header->stringLiteralOffset ^= (uint32_t) rand();
|
|
header->stringLiteralDataCount ^= (uint32_t) rand();
|
|
header->stringLiteralDataOffset ^= (uint32_t) rand();
|
|
|
|
auto key64 = (uint64_t *) literal_dec_key;
|
|
for (int i = 0; i < 0xa00; i++)
|
|
key64[i] = rand();
|
|
}
|
|
|
|
void recrypt_global_metadata_header_string_literals(uint8_t *data, size_t len, uint8_t *literal_dec_key) {
|
|
if (len < sizeof(m_header_fields))
|
|
throw std::out_of_range("data not big enough for global metadata header");
|
|
|
|
auto header = (m_header_fields *) data;
|
|
if ((size_t) header->stringLiteralCount + header->stringLiteralOffset > len)
|
|
throw std::out_of_range("file trimmed or string literal offset/count field invalid");
|
|
|
|
auto literals = (m_literal *) (data + header->stringLiteralOffset);
|
|
auto count = header->stringLiteralCount / sizeof(m_literal);
|
|
for (size_t i = 0; i < count; i++) {
|
|
auto slen = literals[i].length;
|
|
uint8_t *str = data + header->stringLiteralDataOffset + literals[i].offset;
|
|
uint8_t *okey = literal_dec_key + (i % 0x2800);
|
|
|
|
if ((size_t) header->stringLiteralDataOffset + literals[i].offset + slen > len)
|
|
throw std::out_of_range("file trimmed or contains invalid string entry");
|
|
|
|
for (size_t j = 0; j < slen; j++)
|
|
str[j] ^= literal_dec_key[(j + 0x1400u) % 0x5000u] ^ (okey[j % 0x2800u] + (uint8_t) j);
|
|
}
|
|
}
|