Last active
November 29, 2019 20:06
-
-
Save x1nixmzeng/c55c248c384bf1c9df2a to your computer and use it in GitHub Desktop.
Conker
This file contains hidden or 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 <cstdio> | |
typedef signed char s8; | |
typedef unsigned char u8; | |
typedef unsigned short u16; | |
typedef unsigned int u32; | |
u8 default_rbm[384] = { | |
0x43, 0x41, 0x46, 0x46, 0x32, 0x38, 0x2E, 0x30, 0x31, 0x2E, 0x30, 0x35, 0x2E, 0x30, 0x30, 0x33, | |
0x31, 0x00, 0x00, 0x00, 0x50, 0x5D, 0xC9, 0x02, 0x7A, 0x01, 0x00, 0x00, 0xF2, 0x01, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x74, 0x05, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x02, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, | |
0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, | |
0x04, 0xBF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0xB4, 0x59, 0x00, 0x00, 0x2E, 0x67, 0x70, 0x75, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x9A, 0x01, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
}; | |
/* likely an extern to something automatically generated */ | |
const char *gCurrentRevision = "28.01.05.0031"; | |
bool checkString(const u8* a, const u8* b, u32 length) | |
{ | |
for( u32 i(0); i < length; ++i, ++a, ++b ) { | |
/* check characters against each other */ | |
if( *a != *b ) { | |
return false; | |
} | |
} | |
return true; | |
} | |
bool checkEndian(u8 *fileBuffer) | |
{ | |
const u8 endian_flag = *(u8*)(fileBuffer + 60); | |
/* marker for big endian */ | |
return ( endian_flag & 1 ); | |
} | |
u32 doCaffChecksumByte(const u32 initialVal, const u8 currentByte) | |
{ | |
/* the byte buffer is actually signed */ | |
int val = (initialVal << 4) + static_cast<s8>(currentByte); | |
int val_mask = val & 0xF0000000; | |
if( val_mask ) { | |
/* copy the mask over 0xF00000F0 */ | |
val_mask |= ( (u32)val_mask >> 24 ); | |
val ^= val_mask; | |
} | |
return val; | |
} | |
u32 checkCaff(u8 *fileBuffer, u32 fileHash) | |
{ | |
u32 result = 0; | |
/* check file magic */ | |
if( !checkString( fileBuffer, reinterpret_cast<const u8*>("CAFF"), 4 ) ) { | |
result = 1; | |
} | |
/* check asset revision */ | |
else if( !checkString( fileBuffer + 4, reinterpret_cast<const u8*>(gCurrentRevision), 13 ) ) { | |
result = 2; | |
} | |
/* validate file hash */ | |
else | |
{ | |
fileHash = *(u32*)(fileBuffer + 20); | |
/* fix file hash if file endian is marked */ | |
if( checkEndian(fileBuffer) ) { | |
fileHash = ( ( fileHash >> 24 ) & 0x000000FF ) | |
| ( ( fileHash << 24 ) & 0xFF000000 ) | |
| ( (fileHash << 8 ) & 0x00FF0000 ) | |
| ( ( fileHash >> 8 ) & 0x0000FF00 ); | |
} | |
/* clear hash from buffer */ | |
*(u32*)(fileBuffer + 20) = 0; | |
u32 chksmLocal = 0; | |
u8 *chkcmBuffer = fileBuffer; | |
/* runs over (64 * 6) bytes */ | |
const u32 run_count = 64 * 6; | |
for( u32 run = 0; run < run_count; ++run, ++chkcmBuffer ) { | |
/* the xbe file runs though 6 bytes at a time */ | |
chksmLocal = doCaffChecksumByte(chksmLocal, *chkcmBuffer); | |
} | |
printf("Result %08X\n", chksmLocal); | |
printf("Expected %08X\n", fileHash); | |
if( chksmLocal != fileHash ) { | |
result = 3; | |
} | |
} | |
return result; | |
} | |
void getFileInfo(u8 *data) | |
{ | |
u8 count = *(u8*)(data + 61); | |
#pragma pack(push,1) | |
struct CAFF_SECTION_HEADER | |
{ | |
char name[6]; | |
char pad[30]; | |
u32 size; | |
}; | |
#pragma pack(pop) | |
u8 *ptr = (data + 64); | |
CAFF_SECTION_HEADER d; | |
u32 total_size = 0; | |
for( u8 i = 0; i < count; ++i, ptr += 40 ) | |
{ | |
d = *(CAFF_SECTION_HEADER*)(ptr); | |
printf("Found block named %s (size %u)\n", d.name, d.size); | |
total_size += d.size; | |
} | |
u32 data_starts = *(u32*)(data + 56); | |
printf("Data offset = %u\n", data_starts); | |
printf("Data length = %u\n", total_size); | |
} | |
int main(int, char**) | |
{ | |
getFileInfo(default_rbm); | |
int result = checkCaff(default_rbm, 0); | |
switch( result ) | |
{ | |
case 1: | |
printf("Unsupported file\n"); | |
break; | |
case 2: | |
printf("File is out of date (expected %s)\n", gCurrentRevision); | |
break; | |
case 3: | |
printf("Checksum failed\n"); | |
break; | |
default: | |
printf("Valid file\n"); | |
break; | |
} | |
return 0; | |
} |
This file contains hidden or 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
A quick look at 'Conker: Live & Reloaded' (xbox) | |
The sourcecode runs the same initial checks as the game to check the file validity (magic, asset version, and checksum) | |
Some of the data files are futher compressed using an unknown algorithm. | |
After reading the segment offsets and sizes, the compressed data is stored in chunks: | |
u32 chunk_size; | |
u32 length; | |
u8 data[length] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Revision 5: