/* _____ _ _ _____ ____ | ___(_) ___ ___| |_ __ _| ___/ ___| | |_ | |/ _ \/ __| __/ _` | |_ \___ \ | _| | | __/\__ \ || (_| | _| ___) | |_| |_|\___||___/\__\__,_|_| |____/ Fiesta 2 Raw Extract */ #include "f2rawextract.h" using namespace std; char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) { *output_length = 4 * ((input_length + 2) / 3); char *encoded_data = (char*)malloc(*output_length); if (encoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { unsigned int octet_a = i < input_length ? data[i++] : 0; unsigned int octet_b = i < input_length ? data[i++] : 0; unsigned int octet_c = i < input_length ? data[i++] : 0; unsigned int triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; } for (int i = 0; i < mod_table[input_length % 3]; i++) encoded_data[*output_length - 1 - i] = '='; return encoded_data; } void build_decoding_table() { decoding_table = (char *)malloc(256); for (int i = 0; i < 64; i++) decoding_table[(unsigned char) encoding_table[i]] = i; } unsigned char *base64_decode(const char *data, size_t input_length, size_t *output_length) { if (decoding_table == NULL) build_decoding_table(); if (input_length % 4 != 0) return NULL; *output_length = input_length / 4 * 3; if (data[input_length - 1] == '=') (*output_length)--; if (data[input_length - 2] == '=') (*output_length)--; unsigned char *decoded_data = (unsigned char *)malloc(*output_length); if (decoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { unsigned int sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; unsigned int sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; unsigned int sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; unsigned int sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; unsigned int triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } return decoded_data; } void base64_cleanup() { free(decoding_table); } int gzipDecompress(char *body, char *outdata, int len, int outlen) { z_stream inflate_stream; // Set up the zlib stream inflate_stream.zalloc = Z_NULL; inflate_stream.zfree = Z_NULL; inflate_stream.opaque = NULL; if(inflateInit2(&inflate_stream, MAX_WBITS+32) != Z_OK) { return -1; } z_stream *zs = &inflate_stream; // Guess at 50% compression // int outlen = len*2; -- Receiving outputlen //char *outbuf; //outbuf = (char*) malloc(outlen); // Tell zlib where to find the data inflate_stream.next_in = (unsigned char*) body; inflate_stream.avail_in = (unsigned int)len; // Tell zlib where to put the data inflate_stream.next_out = (unsigned char*) outdata; inflate_stream.avail_out = (unsigned int) outlen; // Keep decompressing while (1) { int ret; ret = inflate(&inflate_stream, Z_SYNC_FLUSH); if(ret == Z_OK) // End of a block - will process more blocks { // Clear the buffer //outdata->append(outbuf); inflate_stream.next_out = (unsigned char*) outdata; inflate_stream.avail_out = (unsigned int) outlen; } else if(ret == Z_STREAM_END) // End of the stream - all data was processed { //outdata->append(outbuf); //free(outbuf); return 0; break; } else if(ret == Z_BUF_ERROR) { cout << "Buffer error" << endl; cout << inflate_stream.msg << endl; return -1; break; } else if(ret == Z_STREAM_ERROR) { cout << "Stream error" << endl; cout << inflate_stream.msg << endl; return -1; break; } else if(ret == Z_DATA_ERROR) { cout << "Data error" << endl; cout << inflate_stream.msg << endl; return -1; break; } else { cout << "Return code was " << ret << endl; cout << inflate_stream.msg << endl; return -1; break; } } } int main(int argc, char *argv[]) { unsigned long long offset; unsigned int size, uncsize; char *shiftedkeyb64, *filename, *target, *key, *amffile; bool nullrepacked = false, compressed = false; if(argc < 9) { cout << "Usage: rawextract offset size uncsize target filename compressed nullrepacked shiftedkey_b64 amffile" << endl; return 1; } build_decoding_table(); offset = atol(argv[1]); size = atol(argv[2]); uncsize = atol(argv[3]); target = argv[4]; filename = argv[5]; compressed = argv[6][0] == '1'; nullrepacked = argv[7][0] == '1'; shiftedkeyb64 = argv[8]; amffile = argv[9]; cout << "Extracting Name: " << filename << " Offset: " << hex << offset << " Size: " << dec << size << " Uncompressed size: "<< dec << uncsize << " Compressed: " << compressed << " Nullrepacked: "<< nullrepacked << " Key Encoded: " << shiftedkeyb64 << " "<< endl; size_t ksize = strlen(shiftedkeyb64); size_t k2size = 64; key = (char *)base64_decode((const char *)shiftedkeyb64, ksize, &k2size); /*cout << endl << "endl; for (const unsigned char* p = (unsigned char *)key; *p; ++p) { printf("0x%02x ", *p); } cout << endl;*/ FILE *amf = fopen(amffile,"rb"); FILE *output = fopen(target, "wb"); fseek(amf, offset, SEEK_SET); if(!compressed) { //Decrypt file int decryptedsize = 0; while(decryptedsize != size) { int readsize = (decryptedsize+CHUNK_SIZE)> 6; unsigned int keyshift = (0xB * blockcycles) & 0xFFFFFFFF; unsigned int chunkpos = 0; while(chunkpos != readsize) { int blocksize = (readsize-chunkpos)>64?64:readsize-chunkpos; unsigned int poison = (blockcycles + (keyshift >> 6)); unsigned int keybump = (((blockcycles + (blockcycles >> 6)) & 0x3F)); blockcycles++; keyshift += 11; for(int z=0;z size ? size : 64; if(readsize > 19) { readbuffer[0] ^= readbuffer[16]; readbuffer[1] ^= readbuffer[17]; readbuffer[2] ^= readbuffer[18]; readbuffer[3] ^= readbuffer[19]; } for(int z=0;z