Skip to content

Instantly share code, notes, and snippets.

@viliml
Created September 9, 2020 14:12
Show Gist options
  • Save viliml/e70ee7c9b14c7591ee3bd14809e2851c to your computer and use it in GitHub Desktop.
Save viliml/e70ee7c9b14c7591ee3bd14809e2851c to your computer and use it in GitHub Desktop.
arguments: decrypted list file, data file, extraction folder
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdint>
#include <cassert>
#include <sstream>
#include <sys/stat.h>
#ifdef _WIN32
#include <direct.h>
#endif
using namespace std;
bool folder_exists(string foldername)
{
struct stat st;
stat(foldername.c_str(), &st);
return st.st_mode & S_IFDIR;
}
int __mkdir(const char *path)
{
#ifdef _WIN32
return _mkdir(path);
#else
#if _POSIX_C_SOURCE
return mkdir(path);
#else
return mkdir(path, 0755);
#endif
#endif
}
int mkdir(const char *path)
{
string current_level = "";
string level;
stringstream ss(path);
while (!getline(ss, level, '/').eof())
{
current_level += level;
// create current level
if (!folder_exists(current_level) && __mkdir(current_level.c_str()) != 0)
return -1;
current_level += "/";
}
return 0;
}
char buffer[1024];
struct group_t {
uint32_t size;
char *name;
};
struct item_t {
char *name;
uint16_t gid;
uint32_t id;
uint64_t offset;
uint32_t size;
uint64_t hash;
};
struct list_t {
uint32_t gcnt;
group_t *groups;
uint32_t icnt;
item_t *items;
};
template<typename T>
void read_atom(FILE* file, T& atom) {
fread(&atom, sizeof atom, 1, file);
}
void read_string(FILE* file, char* &str) {
size_t len = 0;
do {
read_atom(file, buffer[len]);
} while (buffer[len++]);
str = new char[len];
strcpy(str, buffer);
}
void read_group(FILE* file, group_t &group) {
read_atom(file, group.size);
read_string(file, group.name);
}
void read_item(FILE* file, item_t &item) {
read_string(file, item.name);
read_atom(file, item.gid);
read_atom(file, item.id);
read_atom(file, item.offset);
read_atom(file, item.size);
read_atom(file, item.hash);
}
void read_list(FILE* file, list_t &list) {
read_atom(file, list.gcnt);
list.groups = new group_t[list.gcnt];
for (size_t i = 0; i < list.gcnt; ++i) {
read_group(file, list.groups[i]);
}
read_atom(file, list.icnt);
list.items = new item_t[list.icnt];
for (size_t i = 0; i < list.icnt; ++i) {
read_item(file, list.items[i]);
}
}
void destroy_group(group_t &group) {
delete[] group.name;
}
void destroy_item(item_t &item) {
delete[] item.name;
}
void destroy_list(list_t &list) {
for (size_t i = 0; i < list.gcnt; ++i) {
destroy_group(list.groups[i]);
}
delete[] list.groups;
for (size_t i = 0; i < list.icnt; ++i) {
destroy_item(list.items[i]);
}
delete[] list.items;
}
uint64_t decrypt(char* dst, const char* src, size_t len, uint64_t key) {
uint64_t hash = 0xcbf29ce484222325;
uint8_t x = 0;
uint8_t srcprev = (uint8_t)key;
for (size_t i = 0; i < len; i++) {
uint8_t srcbyte = src[i];
uint8_t dstbyte = (srcbyte - x) ^ srcprev;
dst[i] = dstbyte;
hash = (hash * 0x100000001b3ULL) ^ dstbyte;
x += (uint8_t)(key >> (((i + 1) % 8) * 8));
srcprev = srcbyte;
}
return hash;
}
int main(int argc, const char *argv[]) {
list_t list;
FILE* flist = fopen(argv[1], "rb");
read_list(flist, list);
fclose(flist);
FILE* data = fopen(argv[2], "rb");
for (size_t i = 0; i < list.icnt; ++i) {
fseek(data, list.items[i].offset, SEEK_SET);
char *src = new char[list.items[i].size];
fread(src, list.items[i].size, 1, data);
char *dst = new char[list.items[i].size];
assert(list.items[i].hash == decrypt(dst, src, list.items[i].size, list.items[i].hash));
delete[] src;
strcpy(buffer, argv[3]);
strcat(buffer, list.groups[list.items[i].gid].name);
strcat(buffer, "/");
strcat(buffer, list.items[i].name);
strcat(buffer, ".unity3d");
mkdir(buffer);
FILE* const output = fopen(buffer, "wb");
fwrite(dst, list.items[i].size, 1, output);
fclose(output);
delete[] dst;
}
fclose(data);
destroy_list(list);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment