-
-
Save viliml/e70ee7c9b14c7591ee3bd14809e2851c to your computer and use it in GitHub Desktop.
arguments: decrypted list file, data file, extraction folder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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