#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
struct pak_header_data {
unsigned char magic[4];
unsigned short flags;
unsigned short unknown1;
unsigned int block_sz;
unsigned int num_entries;
};
struct pak_entry_data {
unsigned int flags;
int startsector; // byte offset = startsector * 2048
int filesize;
char ident[4];
unsigned int unknown2;
unsigned int crc;
int unknown4;
int unknown5;
unsigned char namelen;
unsigned char filepath[255];
};
unsigned char *p_tab1;
unsigned char *p_tab2;
static unsigned char init_parm[4] = { 0x36, 0x05, 0xbf, 0xce };
unsigned char tab1[] =
{
0xf8, 0x96, 0x54, 0x41,
0xc7, 0x04, 0xb8, 0x41,
0x7c, 0x5d, 0xbe, 0x07,
0x6b, 0x62, 0x54, 0xc1,
};
unsigned char tab2[] =
{
0x15, 0xa0, 0x38, 0x25,
0x35, 0x1c, 0xad, 0x5b,
0x6d, 0x52, 0x7a, 0x36,
0xa8, 0x17, 0x1d, 0x20,
};
static struct _codec_parm
{
unsigned int seed;
unsigned int variable;
} codec_parm;
unsigned int get_u32_be(unsigned char *p)
{
unsigned int ret = 0;
if (p)
{
ret |= p[3];
ret |= p[2]<<8;
ret |= p[1]<<16;
ret |= p[0]<<24;
}
return ret;
}
unsigned int get_u32_le(unsigned char *p)
{
return *(unsigned int *)p;
}
unsigned int (*get_u32)(unsigned char *p);
#define SZ_KEYS (sizeof(tab1)/sizeof(unsigned int))
unsigned int Cal_KEY(unsigned int s_1, unsigned int s_2)
{
unsigned char i = 0;
for (;i < SZ_KEYS; i++)
{
unsigned int lo, hi, temp, seed = s_2;
temp = seed ^ get_u32(p_tab1+(i*4));
hi = ((temp >> 16) & 0xffff);
lo = ((temp) & 0xffff);
temp = (lo * lo) + ~(hi * hi);
temp = (temp << 16) | (temp >> 16);
s_2 = temp ^ get_u32(p_tab2+(i*4));
s_2 += lo * hi;
s_2 ^= s_1;
s_1 = seed;
}
return s_2;
}
void codec(unsigned char *buff, unsigned int size, struct _codec_parm *p_parm)
{
unsigned char *p_buff = buff;
unsigned int res, offset = 0;
unsigned char key[4];
struct _codec_parm temp;
temp.seed = ~(p_parm->seed - 1);
temp.variable = p_parm->variable;
while(size > offset)
{
if (!(offset & 3))
{
res = Cal_KEY(temp.seed, temp.variable);
key[3] = res;
key[2] = res >>= 1;
key[1] = res >>= 1;
key[0] = res >>= 1;
temp.variable += 1;
}
*p_buff++ ^= key[offset++ & 3];
};
p_parm->variable = temp.variable;
}
static unsigned int crc32_table[256];
static __inline unsigned int crc_reflect(unsigned int ref, unsigned int ch)
{
unsigned int value = 0, i;
for(i = 1; i < (ch + 1); i++)
{
if(ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
void crc_init()
{
#define POLY (0x04c11db7)
unsigned int value = 0, i, j;
for(i = 0; i <= 256 - 1; i++)
{
crc32_table[i] = crc_reflect(i, 8) << 24;
for (j = 0; j < 8; j++)
crc32_table[i] = (crc32_table[i] << 1) ^ (crc32_table[i] & (1 << 31) ? POLY : 0);
crc32_table[i] = crc_reflect(crc32_table[i], 32);
}
}
static __inline unsigned int get_crc(unsigned char *p, unsigned int len, unsigned int crc)
{
while(len--)
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *p++];
return ~crc;
}
void endian_init(void)
{
unsigned short endian = 1;
unsigned char *p_e = (unsigned char *)&endian;
if (!*p_e)
get_u32 = get_u32_be;
else
get_u32 = get_u32_le;
}
unsigned char init(unsigned int variable)
{
unsigned char t_tab1[] = {
0xbc, 0x1f, 0x46, 0x64,
0x09, 0x99, 0x82, 0x34,
0xc0, 0x25, 0x4f, 0xe5,
0xb7, 0xdb, 0x26, 0x25,
};
unsigned char t_tab2[] = {
0x35, 0xe0, 0xb8, 0x25,
0x9d, 0x4d, 0x0e, 0x1d,
0xdc, 0x31, 0xbc, 0xbb,
0x78, 0xb6, 0x5e, 0xa7,
};
p_tab1 = t_tab1;
p_tab2 = t_tab2;
codec_parm.seed = 0x6C69746E;
codec_parm.variable = variable;
codec((unsigned char*)init_parm, sizeof(unsigned int), &codec_parm);
codec(tab1, sizeof(tab1), &codec_parm);
codec(tab2, sizeof(tab2), &codec_parm);
p_tab1 = tab1;
p_tab2 = tab2;
codec_parm.seed = get_u32(init_parm);
codec_parm.variable = 1;
if (get_crc(tab1, sizeof(tab1), 0-1) != 0x5CBE2D0F ||
get_crc(tab2, sizeof(tab2), 0-1) != 0x7BA1A34F)
return 0;
else
return 1;
}
#define _UC(p) ((unsigned char *)p)
int main(int argc, char **argv)
{
FILE *infp, *outfp;
struct pak_header_data h;
struct pak_entry_data e;
char *f_name = "FILES.PAK";
unsigned int i, crc_f = 0;
if (argc > 2)
{
printf("Usage: codec_pak file.ext\n");
exit(1);
}
if (argc == 2)
f_name = argv[1];
if (!(infp = fopen(f_name, "rb")))
{
printf("Error: cannot open %s : %s\n", f_name, strerror(errno), NULL);
exit(1);
}
fread(&h, sizeof(h), 1, infp);
crc_init();
endian_init();
if (!init(get_u32((unsigned char*)&h.magic)))
goto out;
if (h.flags >> 9)
{
codec((unsigned char*)&h.unknown1, sizeof(h.unknown1), &codec_parm);
codec((unsigned char*)&h.block_sz, sizeof(h.block_sz), &codec_parm);
codec((unsigned char*)&h.num_entries, sizeof(h.num_entries), &codec_parm);
}
printf("HDR: ID:%c%c%c%c, entries:%d\n", h.magic[0], h.magic[1], h.magic[2], h.magic[3], get_u32(_UC(&h.num_entries)));
mkdir("extracted",0777);
chdir("extracted");
codec_parm.seed = get_u32(_UC(&h.num_entries)) + (1 << 31);
codec_parm.variable = 1;
#define entry_start(n) (sizeof(struct pak_header_data) + (sizeof(struct pak_entry_data) * n))
for (i = 0; i < get_u32(_UC(&h.num_entries)); i++)
{
static unsigned char temp[4*1024];
unsigned int count, sz, crc;
struct _codec_parm t_parm;
fseek(infp, entry_start(i), SEEK_SET);
if (fread(&e, sizeof(struct pak_entry_data), 1, infp) != 1)
{
printf("failed reading file: %s\n", strerror(errno));
break;
}
if (h.flags >> 8)
codec((unsigned char*)&e, sizeof(struct pak_entry_data), &codec_parm);
printf("E:%d: ID:%c%c%c%c, filepath:%s, size:%d, ", i+1, e.ident[0], e.ident[1], e.ident[2], e.ident[3], e.filepath, get_u32(_UC(&e.filesize)));
{
char *p_name = (char *)&e.filepath;
int ii = e.namelen - 1;
for (; ii > 0; ii --)
{
if ((p_name[ii] == '/') || (p_name[ii] == '\\'))
{
int iii;
char slash = p_name[ii];
p_name[ii] = '\0';
for (iii = 0; ii > iii;iii ++)
{
if ((p_name[iii] == '/') || (p_name[iii] == '\\')) {
p_name[iii] = '\0';
mkdir(e.filepath,0777);
p_name[iii] = slash;
}
}
mkdir(e.filepath,0777);
p_name[ii] = slash;
break;
}
}
}
/*
temp = (unsigned char *) calloc(1, get_u32(_UC(&e.filesize)));
fseek(infp, get_u32(_UC(&e.startsector)) * get_u32(_UC(&h.block_sz)), SEEK_SET);
fread(temp, get_u32(_UC(&e.filesize)), 1, infp);
*/
fseek(infp, get_u32(_UC(&e.startsector)) * get_u32(_UC(&h.block_sz)), SEEK_SET);
if (get_u32(_UC(&e.flags)) >> 31) // coded
{
t_parm.seed = get_u32(_UC(&e.filesize)) + get_u32(_UC(&e.flags));
t_parm.variable = 1;
}
if (!(outfp = fopen(e.filepath, "wb"))) {
printf("Error: cannot open %s for writing: %s\n", e.filepath, strerror(errno));
continue;
}
crc = 0-1;
for(count = get_u32(_UC(&e.filesize)); count > 0;)
{
sz = count > get_u32(_UC(&h.block_sz)) ? get_u32(_UC(&h.block_sz)) : count;
fread(temp, sz, 1, infp);
if (get_u32(_UC(&e.flags)) >> 31) // coded
codec((unsigned char*)temp, sz, &t_parm);
crc = ~get_crc(temp, sz, crc);
fwrite(temp, sz, 1, outfp);
count -= sz;
}
fclose(outfp);
printf("crc32:");
if (get_u32(_UC(&e.crc)) == ~crc)
printf("OK\n");
else
printf("%s %0X != %0X\n", (crc_f++, "FAIL"), get_u32(_UC(&e.crc)), crc);
}
printf("Files OK:%d, FAIL:%d\n", h.num_entries - crc_f, crc_f);
out:
fclose(infp);
exit(0);
}
Bookmarks