f2rawextract.cpp
· 7.2 KiB · C++
Sin formato
/*
_____ _ _ _____ ____
| ___(_) ___ ___| |_ __ _| ___/ ___|
| |_ | |/ _ \/ __| __/ _` | |_ \___ \
| _| | | __/\__ \ || (_| | _| ___) |
|_| |_|\___||___/\__\__,_|_| |____/
Fiesta 2 Raw Extract
By: SkyFlow
*/
#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)<size?CHUNK_SIZE:size-decryptedsize;
fread(readbuffer, readsize, 1, amf);
int blockcycles = decryptedsize >> 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<blocksize;z++)
readbuffer[chunkpos+z] ^= (poison + key[keybump^z]) & 0xFF;
chunkpos += blocksize;
}
decryptedsize += readsize;
fwrite(readbuffer, readsize, 1, output);
}
}else{
//Decrypt compressed file
readbuffer = new char[size];
char *outbuffer = new char[uncsize];
fread(readbuffer, size, 1, amf);
int readsize = 64 > 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<readsize;z++)
readbuffer[z] = (readbuffer[z] + key[z]) & 0xFF;
gzipDecompress(readbuffer, outbuffer, size, uncsize);
fwrite(outbuffer, uncsize, 1, output);
}
fclose(amf);
fclose(output);
base64_cleanup();
return 0;
}
| 1 | /* |
| 2 | _____ _ _ _____ ____ |
| 3 | | ___(_) ___ ___| |_ __ _| ___/ ___| |
| 4 | | |_ | |/ _ \/ __| __/ _` | |_ \___ \ |
| 5 | | _| | | __/\__ \ || (_| | _| ___) | |
| 6 | |_| |_|\___||___/\__\__,_|_| |____/ |
| 7 | |
| 8 | Fiesta 2 Raw Extract |
| 9 | |
| 10 | By: SkyFlow |
| 11 | */ |
| 12 | |
| 13 | #include "f2rawextract.h" |
| 14 | |
| 15 | using namespace std; |
| 16 | |
| 17 | char *base64_encode(const unsigned char *data, |
| 18 | size_t input_length, |
| 19 | size_t *output_length) { |
| 20 | |
| 21 | *output_length = 4 * ((input_length + 2) / 3); |
| 22 | |
| 23 | char *encoded_data = (char*)malloc(*output_length); |
| 24 | if (encoded_data == NULL) return NULL; |
| 25 | |
| 26 | for (int i = 0, j = 0; i < input_length;) { |
| 27 | |
| 28 | unsigned int octet_a = i < input_length ? data[i++] : 0; |
| 29 | unsigned int octet_b = i < input_length ? data[i++] : 0; |
| 30 | unsigned int octet_c = i < input_length ? data[i++] : 0; |
| 31 | |
| 32 | unsigned int triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; |
| 33 | |
| 34 | encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; |
| 35 | encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; |
| 36 | encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; |
| 37 | encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; |
| 38 | } |
| 39 | |
| 40 | for (int i = 0; i < mod_table[input_length % 3]; i++) |
| 41 | encoded_data[*output_length - 1 - i] = '='; |
| 42 | |
| 43 | return encoded_data; |
| 44 | } |
| 45 | |
| 46 | void build_decoding_table() { |
| 47 | decoding_table = (char *)malloc(256); |
| 48 | for (int i = 0; i < 64; i++) |
| 49 | decoding_table[(unsigned char) encoding_table[i]] = i; |
| 50 | } |
| 51 | unsigned char *base64_decode(const char *data, |
| 52 | size_t input_length, |
| 53 | size_t *output_length) { |
| 54 | |
| 55 | if (decoding_table == NULL) build_decoding_table(); |
| 56 | |
| 57 | if (input_length % 4 != 0) return NULL; |
| 58 | |
| 59 | *output_length = input_length / 4 * 3; |
| 60 | if (data[input_length - 1] == '=') (*output_length)--; |
| 61 | if (data[input_length - 2] == '=') (*output_length)--; |
| 62 | |
| 63 | unsigned char *decoded_data = (unsigned char *)malloc(*output_length); |
| 64 | |
| 65 | if (decoded_data == NULL) return NULL; |
| 66 | |
| 67 | for (int i = 0, j = 0; i < input_length;) { |
| 68 | |
| 69 | unsigned int sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; |
| 70 | unsigned int sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; |
| 71 | unsigned int sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; |
| 72 | unsigned int sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; |
| 73 | |
| 74 | unsigned int triple = (sextet_a << 3 * 6) |
| 75 | + (sextet_b << 2 * 6) |
| 76 | + (sextet_c << 1 * 6) |
| 77 | + (sextet_d << 0 * 6); |
| 78 | |
| 79 | if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; |
| 80 | if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; |
| 81 | if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; |
| 82 | } |
| 83 | |
| 84 | return decoded_data; |
| 85 | } |
| 86 | |
| 87 | |
| 88 | |
| 89 | void base64_cleanup() { |
| 90 | free(decoding_table); |
| 91 | } |
| 92 | |
| 93 | int gzipDecompress(char *body, char *outdata, int len, int outlen) |
| 94 | { |
| 95 | |
| 96 | z_stream inflate_stream; |
| 97 | |
| 98 | // Set up the zlib stream |
| 99 | inflate_stream.zalloc = Z_NULL; |
| 100 | inflate_stream.zfree = Z_NULL; |
| 101 | inflate_stream.opaque = NULL; |
| 102 | |
| 103 | if(inflateInit2(&inflate_stream, MAX_WBITS+32) != Z_OK) |
| 104 | { |
| 105 | return -1; |
| 106 | } |
| 107 | |
| 108 | z_stream *zs = &inflate_stream; |
| 109 | |
| 110 | // Guess at 50% compression |
| 111 | // int outlen = len*2; -- Receiving outputlen |
| 112 | //char *outbuf; |
| 113 | //outbuf = (char*) malloc(outlen); |
| 114 | |
| 115 | // Tell zlib where to find the data |
| 116 | inflate_stream.next_in = (unsigned char*) body; |
| 117 | inflate_stream.avail_in = (unsigned int)len; |
| 118 | |
| 119 | // Tell zlib where to put the data |
| 120 | inflate_stream.next_out = (unsigned char*) outdata; |
| 121 | inflate_stream.avail_out = (unsigned int) outlen; |
| 122 | |
| 123 | // Keep decompressing |
| 124 | while (1) { |
| 125 | |
| 126 | int ret; |
| 127 | |
| 128 | ret = inflate(&inflate_stream, Z_SYNC_FLUSH); |
| 129 | |
| 130 | if(ret == Z_OK) // End of a block - will process more blocks |
| 131 | { |
| 132 | |
| 133 | // Clear the buffer |
| 134 | //outdata->append(outbuf); |
| 135 | inflate_stream.next_out = (unsigned char*) outdata; |
| 136 | inflate_stream.avail_out = (unsigned int) outlen; |
| 137 | |
| 138 | } |
| 139 | |
| 140 | else if(ret == Z_STREAM_END) // End of the stream - all data was processed |
| 141 | { |
| 142 | |
| 143 | //outdata->append(outbuf); |
| 144 | //free(outbuf); |
| 145 | |
| 146 | return 0; |
| 147 | break; |
| 148 | |
| 149 | } |
| 150 | |
| 151 | else if(ret == Z_BUF_ERROR) |
| 152 | { |
| 153 | cout << "Buffer error" << endl; |
| 154 | cout << inflate_stream.msg << endl; |
| 155 | return -1; |
| 156 | break; |
| 157 | } |
| 158 | |
| 159 | else if(ret == Z_STREAM_ERROR) |
| 160 | { |
| 161 | cout << "Stream error" << endl; |
| 162 | cout << inflate_stream.msg << endl; |
| 163 | return -1; |
| 164 | break; |
| 165 | } |
| 166 | |
| 167 | else if(ret == Z_DATA_ERROR) |
| 168 | { |
| 169 | cout << "Data error" << endl; |
| 170 | cout << inflate_stream.msg << endl; |
| 171 | return -1; |
| 172 | break; |
| 173 | } |
| 174 | |
| 175 | else { |
| 176 | cout << "Return code was " << ret << endl; |
| 177 | cout << inflate_stream.msg << endl; |
| 178 | return -1; |
| 179 | break; |
| 180 | } |
| 181 | |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | |
| 186 | int main(int argc, char *argv[]) { |
| 187 | unsigned long long offset; |
| 188 | unsigned int size, uncsize; |
| 189 | char *shiftedkeyb64, *filename, *target, *key, *amffile; |
| 190 | bool nullrepacked = false, compressed = false; |
| 191 | if(argc < 9) { |
| 192 | cout << "Usage: rawextract offset size uncsize target filename compressed nullrepacked shiftedkey_b64 amffile" << endl; |
| 193 | return 1; |
| 194 | } |
| 195 | |
| 196 | build_decoding_table(); |
| 197 | |
| 198 | offset = atol(argv[1]); |
| 199 | size = atol(argv[2]); |
| 200 | uncsize = atol(argv[3]); |
| 201 | target = argv[4]; |
| 202 | filename = argv[5]; |
| 203 | compressed = argv[6][0] == '1'; |
| 204 | nullrepacked = argv[7][0] == '1'; |
| 205 | shiftedkeyb64 = argv[8]; |
| 206 | amffile = argv[9]; |
| 207 | |
| 208 | cout << "Extracting Name: " << filename << " Offset: " << hex << offset << " Size: " << dec << size << " Uncompressed size: "<< dec << uncsize << " Compressed: " << compressed << " Nullrepacked: "<< nullrepacked << " Key Encoded: " << shiftedkeyb64 << " "<< endl; |
| 209 | |
| 210 | |
| 211 | size_t ksize = strlen(shiftedkeyb64); |
| 212 | size_t k2size = 64; |
| 213 | key = (char *)base64_decode((const char *)shiftedkeyb64, ksize, &k2size); |
| 214 | /*cout << endl << "endl; |
| 215 | for (const unsigned char* p = (unsigned char *)key; *p; ++p) |
| 216 | { |
| 217 | printf("0x%02x ", *p); |
| 218 | } |
| 219 | cout << endl;*/ |
| 220 | FILE *amf = fopen(amffile,"rb"); |
| 221 | FILE *output = fopen(target, "wb"); |
| 222 | fseek(amf, offset, SEEK_SET); |
| 223 | if(!compressed) { |
| 224 | //Decrypt file |
| 225 | int decryptedsize = 0; |
| 226 | while(decryptedsize != size) { |
| 227 | int readsize = (decryptedsize+CHUNK_SIZE)<size?CHUNK_SIZE:size-decryptedsize; |
| 228 | fread(readbuffer, readsize, 1, amf); |
| 229 | int blockcycles = decryptedsize >> 6; |
| 230 | unsigned int keyshift = (0xB * blockcycles) & 0xFFFFFFFF; |
| 231 | unsigned int chunkpos = 0; |
| 232 | while(chunkpos != readsize) { |
| 233 | int blocksize = (readsize-chunkpos)>64?64:readsize-chunkpos; |
| 234 | unsigned int poison = (blockcycles + (keyshift >> 6)); |
| 235 | unsigned int keybump = (((blockcycles + (blockcycles >> 6)) & 0x3F)); |
| 236 | blockcycles++; |
| 237 | keyshift += 11; |
| 238 | for(int z=0;z<blocksize;z++) |
| 239 | readbuffer[chunkpos+z] ^= (poison + key[keybump^z]) & 0xFF; |
| 240 | chunkpos += blocksize; |
| 241 | } |
| 242 | decryptedsize += readsize; |
| 243 | fwrite(readbuffer, readsize, 1, output); |
| 244 | } |
| 245 | }else{ |
| 246 | //Decrypt compressed file |
| 247 | readbuffer = new char[size]; |
| 248 | char *outbuffer = new char[uncsize]; |
| 249 | fread(readbuffer, size, 1, amf); |
| 250 | int readsize = 64 > size ? size : 64; |
| 251 | if(readsize > 19) { |
| 252 | readbuffer[0] ^= readbuffer[16]; |
| 253 | readbuffer[1] ^= readbuffer[17]; |
| 254 | readbuffer[2] ^= readbuffer[18]; |
| 255 | readbuffer[3] ^= readbuffer[19]; |
| 256 | } |
| 257 | for(int z=0;z<readsize;z++) |
| 258 | readbuffer[z] = (readbuffer[z] + key[z]) & 0xFF; |
| 259 | gzipDecompress(readbuffer, outbuffer, size, uncsize); |
| 260 | fwrite(outbuffer, uncsize, 1, output); |
| 261 | } |
| 262 | fclose(amf); |
| 263 | fclose(output); |
| 264 | |
| 265 | base64_cleanup(); |
| 266 | return 0; |
| 267 | } |