Initial commit
This commit is contained in:
		
							
								
								
									
										45
									
								
								Base64.hpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										45
									
								
								Base64.hpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #pragma once | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| typedef unsigned char uchar; | ||||
|  | ||||
| namespace base64 { | ||||
| 	const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
|  | ||||
| 	std::string Encode(const std::string &in) | ||||
| 	{ | ||||
| 		std::string out; | ||||
| 		int val = 0, valb = -6; | ||||
| 		for (uchar c : in) { | ||||
| 			val = (val << 8) + c; | ||||
| 			valb += 8; | ||||
| 			while (valb >= 0) { | ||||
| 				out.push_back(base64_chars[(val >> valb) & 0x3F]); | ||||
| 				valb -= 6; | ||||
| 			} | ||||
| 		} | ||||
| 		if (valb > -6) out.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]); | ||||
| 		while (out.size() % 4) out.push_back('='); | ||||
| 		return out; | ||||
| 	} | ||||
|  | ||||
| 	std::string Decode(const std::string &in) | ||||
| 	{ | ||||
| 		std::string out; | ||||
| 		std::vector<int> T(256, -1); | ||||
| 		for (int i = 0; i < 64; i++) T[base64_chars[i]] = i; | ||||
|  | ||||
| 		int val = 0, valb = -8; | ||||
| 		for (uchar c : in) { | ||||
| 			if (T[c] == -1) break; | ||||
| 			val = (val << 6) + T[c]; | ||||
| 			valb += 6; | ||||
| 			if (valb >= 0) { | ||||
| 				out.push_back(char((val >> valb) & 0xFF)); | ||||
| 				valb -= 8; | ||||
| 			} | ||||
| 		} | ||||
| 		return out; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										155
									
								
								GDGameSave.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								GDGameSave.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <fstream> | ||||
| #include <zlib.h> | ||||
| #include "Base64.hpp" | ||||
|  | ||||
| constexpr int CHUNK = 16384; | ||||
| constexpr int WINDOW_BITS = 15;  | ||||
|  | ||||
| //Reads the contents of a given file into a string | ||||
| std::string FileToStr(const std::string& filename) { | ||||
| 	std::ifstream file(filename, std::ios::binary); | ||||
| 	if (!file.good()) | ||||
| 		return ""; | ||||
| 	std::string ret(std::istreambuf_iterator<char>(file), {}); | ||||
| 	file.close(); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| //Writes the contents of a string to the given file | ||||
| void StrToFile(const std::string& filename, const std::string& data) { | ||||
| 	std::ofstream ofile; | ||||
| 	ofile.open(filename); | ||||
| 	ofile << data; | ||||
| 	ofile.close(); | ||||
| } | ||||
|  | ||||
| //XORs each byte of a string reference | ||||
| void Xor_Str(std::string& str, unsigned char key) { | ||||
| 	for (auto& c : str) { | ||||
| 		c = c^key; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string GZipDecompress(const std::string& in) | ||||
| { | ||||
| 	//Initialize all members of strm to be 0 | ||||
| 	z_stream strm = {}; | ||||
| 	//Output buffer | ||||
|   	char out[CHUNK]; | ||||
| 	//Holds return value   | ||||
| 	std::string final_output; | ||||
| 	//Initialize GZip decompression; except on failure | ||||
| 	if(inflateInit2(&strm, WINDOW_BITS + 16) != Z_OK) | ||||
| 		throw(std::exception()); | ||||
| 	//Tell zlib where to find the data we want to decompress | ||||
|   	strm.avail_in = in.size(); | ||||
|   	strm.next_in = (Bytef*)in.data(); | ||||
|  | ||||
|   	do { | ||||
|         //Tell zlib where to store the decompressed output data | ||||
|   	  	strm.avail_out = CHUNK; | ||||
|   	  	strm.next_out = (Bytef*)out; | ||||
| 		//Decompress our input data; except on failure | ||||
|   	  	switch (inflate(&strm, Z_FINISH)) { | ||||
|   	  	  	case Z_NEED_DICT: | ||||
| 				  throw(std::exception()); | ||||
|   	  	  	case Z_DATA_ERROR: | ||||
| 				  throw(std::exception()); | ||||
|   	  	  	case Z_MEM_ERROR: | ||||
| 				  throw(std::exception()); | ||||
|   	  	} | ||||
| 		//How many bytes we received into our output buffer | ||||
|   	  	unsigned int have = CHUNK - strm.avail_out; | ||||
| 		//Append received data to our return string | ||||
| 		final_output.append(reinterpret_cast<const char*>(out), have); | ||||
|   	} while (strm.avail_out == 0); | ||||
| 	//Clean up and return | ||||
| 	inflateEnd(&strm); | ||||
| 	return final_output; | ||||
| } | ||||
|  | ||||
| std::string GZipCompress(const std::string& in) | ||||
| { | ||||
| 	//Initialize all members of strm to be 0 | ||||
|     z_stream strm = {}; | ||||
| 	//Output buffer | ||||
|     unsigned char out[CHUNK]; | ||||
| 	//Return value | ||||
| 	std::string final_output; | ||||
| 	//Initialize GZip compression; except on failure | ||||
|     if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK) | ||||
| 		throw(std::exception()); | ||||
| 	//Tell zlib where to find the data we want to compress | ||||
|     strm.avail_in = in.size();  | ||||
|     strm.next_in = (Bytef*)in.data(); | ||||
|  | ||||
|     do { | ||||
|         //Tell zlib where to store the compressed output data | ||||
|         strm.avail_out = CHUNK; | ||||
|         strm.next_out = out; | ||||
| 		//Compress our input data; except on failure | ||||
|         if(deflate(&strm, Z_FINISH) == Z_STREAM_ERROR) | ||||
| 			throw(std::exception()); | ||||
| 		//How many bytes we received into our output buffer | ||||
|         unsigned int have = CHUNK - strm.avail_out; | ||||
| 		//Append received data to our return string | ||||
| 		final_output.append(reinterpret_cast<const char*>(out), have); | ||||
|     } while (strm.avail_out == 0); | ||||
| 	//Clean up and return | ||||
|     deflateEnd(&strm); | ||||
| 	return final_output; | ||||
| } | ||||
|  | ||||
| std::string Decrypt(const std::string& filename) { | ||||
| 	//load file | ||||
| 	std::string ret = FileToStr(filename); | ||||
| 	//Xor with value 11 | ||||
| 	Xor_Str(ret, 11); | ||||
| 	//replace - with + and _ with / | ||||
| 	for (auto& i : ret) { | ||||
| 		if (i == '-') | ||||
| 			i = '+'; | ||||
| 		if (i == '_') | ||||
| 			i = '/'; | ||||
| 	} | ||||
| 	//Decrypt with Base64 | ||||
| 	ret = base64::Decode(ret); | ||||
| 	//Decompress with GZip | ||||
| 	ret = GZipDecompress(ret); | ||||
| 	//Return | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| std::string Encrypt(const std::string& filename) { | ||||
| 	//load file | ||||
| 	std::string data = FileToStr(filename); | ||||
| 	//Calculate crc32 checksum | ||||
| 	uLong crc = crc32(0L, Z_NULL, 0); | ||||
| 	uint32_t crc32_sum = crc32(crc, (Bytef*)data.data(), data.size()); | ||||
| 	uint32_t dataSize = data.size(); | ||||
| 	//Compress with GZip | ||||
| 	std::string ret = GZipCompress(data); | ||||
| 	//Remove first 2 and last 4 chars of string | ||||
| 	ret = ret.substr(2, ret.size() - 4 - 2); | ||||
| 	//Add header, checksum and size | ||||
| 	char header[10] = {'\x1f', '\x8b', '\x08', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0b'}; | ||||
| 	ret =  std::string(header, sizeof(header)) + | ||||
| 			ret + | ||||
| 			std::string((const char*)&crc32_sum, sizeof(crc32_sum)) + //Use raw binary data | ||||
| 			std::string((const char*)&dataSize, sizeof(dataSize)); //Use raw binary data | ||||
| 	//Encrypt with Base64 | ||||
| 	ret = base64::Encode(ret); | ||||
| 	//replace + with - and / with _ | ||||
| 	for (auto& i : ret) { | ||||
| 		if (i == '+') | ||||
| 			i = '-'; | ||||
| 		if (i == '/') | ||||
| 			i = '_'; | ||||
| 	} | ||||
| 	//Xor with value 11 | ||||
| 	Xor_Str(ret, 11); | ||||
| 	//Return | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										48
									
								
								Main.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								Main.cpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| #include <iostream> | ||||
| #include "GDGameSave.hpp" | ||||
|  | ||||
| #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) | ||||
| 	// Using Windows | ||||
| 	const std::string gdLocalFolder = getenv("APPDATA") + std::string("\\..\\Local\\GeometryDash\\"); | ||||
| #else | ||||
| 	// Using GNU/Linux | ||||
| 	const std::string gdLocalFolder = getenv("HOME") + std::string("/.local/share/Steam/steamapps/compatdata/322170/pfx/drive_c/users/steamuser/Local Settings/Application Data/GeometryDash/"); | ||||
| #endif | ||||
|  | ||||
| const std::string usage = R"(Usage: | ||||
| 	-d: decrypt | ||||
| 	-e: encrypt | ||||
| 	-es: encrypt and save to GD folder)"; | ||||
|  | ||||
| const std::string saves[2] = { | ||||
| 	"CCGameManager.dat", | ||||
| 	"CCLocalLevels.dat", | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char** argv) { | ||||
| 	std::vector<std::string> args; | ||||
| 	for(int i = 0; i < argc; i++) | ||||
| 		args.push_back(argv[i]); | ||||
|  | ||||
| 	if(argc < 2) | ||||
| 	{ | ||||
| 		std::cout << usage << std::endl; | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if(args[1] == "-d") | ||||
| 	{ | ||||
| 		const std::string decrypted = Decrypt(gdLocalFolder + saves[0]); | ||||
| 		StrToFile(saves[0] + ".xml", decrypted); | ||||
| 	} | ||||
| 	else if(args[1] == "-e" || args[1] == "-es") | ||||
| 	{ | ||||
| 		const std::string encrypted = Encrypt(saves[0] + ".xml"); | ||||
| 		if(args[1] == "-e") | ||||
| 			StrToFile(saves[0], encrypted); | ||||
| 		else | ||||
| 			StrToFile(gdLocalFolder + saves[0], encrypted); | ||||
| 	} | ||||
|  | ||||
| 	exit(0); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user