yepateam wrote: Are the .MRG container/archive files using compression for any of their assets?
This is some kind of LZSS. I removed the pseudo -cod through the dizassembler and corrected him that he would compile.ateam wrote: If so, have you identified the algorithm?
Code: Select all
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
uint8_t dictonary[40] =
{
0x0C, 0x03, 0x0B, 0x03, 0x0A, 0x03, 0x09, 0x03,
0x06, 0x03, 0x05, 0x03, 0x06, 0x02, 0x05, 0x02,
0x08, 0x04, 0x07, 0x04, 0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01, 0xF0, 0x0F, 0x00, 0x00,
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};
uint32_t BE2LE16(uint8_t *src)
{
return ((src[0] << 8) | src[1]);
}
uint32_t BE2LE32(uint8_t *src)
{
return ((src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]);
}
uint32_t FUN_8c01a45a(uint8_t *buffer, uint32_t *offset)
{
uint32_t ret;
if (!(*offset & 1))
{
ret = buffer[*offset >> 1] >> 4;
}
else
{
ret = buffer[*offset >> 1];
}
*offset = *offset + 1;
return ret & 0xf;
}
uint32_t FUN_8c01a480(uint8_t *buffer, uint32_t *offset)
{
uint32_t tmp;
uint32_t ret;
if ((*offset & 1) == 0)
{
ret = buffer[*offset >> 1];
*offset = *offset + 2;
}
else
{
tmp = FUN_8c01a45a(buffer, offset);
ret = FUN_8c01a45a(buffer, offset);
ret = tmp << 4 | ret;
}
return ret;
}
void FUN_8c01a4c0(uint8_t orval, uint8_t *dst, uint32_t *offset)
{
uint8_t val = dst[*offset >> 1];
if (!(*offset & 1))
{
val = (val & 0x0F) | ((orval & 0x0F) << 4);
}
else
{
val = (val & 0xF0) | (orval & 0xf);
}
dst[*offset >> 1] = val;
*offset = *offset + 1;
}
uint32_t mrg_algo0(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
uint8_t bVar1;
uint8_t bVar2;
uint8_t bVar3;
uint32_t uVar7;
uint32_t uVar8;
int iVar9;
uint8_t *pbVar10;
uint16_t control_byte;
uint32_t i;
control_byte = 0x7F80;
bVar1 = dictonary[param_4 << 1];
bVar3 = dictonary[(param_4 << 1) + 1];
i = 0;
do
{
control_byte <<= 1;
if (control_byte == 0xFF00)
{
control_byte = (*src++ << 8) | 0xFF;
}
if (!(control_byte & 0x8000))
{
uVar7 = BE2LE16(src);
uVar8 = -(uint)bVar1;
if (bVar1 == 0)
{
uVar8 = (uVar7 & 0xffff) << (uVar8 & 0x1f);
}
else
{
uVar8 = (uVar7 & 0xffff) >> ((~uVar8 & 0x1f) + 1);
}
uVar8 = uVar8 + (int)(short)(uint16_t)bVar3;
iVar9 = i - (uVar7 & ((1 << (bVar1 & 0x1f)) + 0xFFFF) & 0xffff);
src += 2;
while (iVar9 < 0)
{
iVar9++;
dst[i] = 0;
uVar8--;
i++;
}
pbVar10 = dst + iVar9;
while ((uVar8 & 0xffff) != 0)
{
uVar8--;
bVar2 = *pbVar10;
pbVar10++;
dst[i] = bVar2;
i++;
}
}
else
{
dst[i++] = *src++;
}
}
while (i < len);
return i;
}
uint32_t mrg_algo1(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
uint8_t bVar1;
uint8_t bVar2;
uint8_t bVar3;
uint32_t uVar7;
int n;
uint32_t i;
uint32_t uVar10;
int iVar11;
uint8_t *pbVar12;
uVar10 = 0x7F80;
bVar1 = dictonary[(param_4 << 1) + 8];
bVar3 = dictonary[(param_4 << 1) + 9];
n = 0;
do
{
uVar10 = uVar10 << 1;
if ((uVar10 & 0xFFFF) == 0xFF00)
{
bVar2 = *src;
src++;
uVar10 = 0xFF | (uint)bVar2 << 8;
}
if (!(uVar10 & 0x8000))
{
bVar2 = *src;
iVar11 = n - ((uint)bVar2 & (int)(short)((short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF));
uVar7 = -(uint)bVar1;
if (bVar1 == 0)
{
uVar7 = (uint)bVar2 << (uVar7 & 0x1f);
}
else
{
uVar7 = (uint)(bVar2 >> ((~uVar7 & 0x1f) + 1));
}
uVar7 = uVar7 + (int)(short)(uint16_t)bVar3;
i = n;
while (iVar11 < 0)
{
iVar11++;
dst[i] = 0;
uVar7--;
i++;
}
pbVar12 = dst + iVar11;
while ((uVar7 & 0xffff) != 0)
{
uVar7--;
bVar2 = *pbVar12;
pbVar12++;
dst[i] = bVar2;
i++;
}
}
else
{
i = n + 1;
dst[n] = *src;
}
src++;
n = i;
}
while (i < len);
return i;
}
uint32_t mrg_algo2(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
uint8_t bVar1;
uint32_t uVar3;
uint32_t uVar4;
uint32_t uVar5;
uint32_t i;
uint32_t local_30;
uint32_t local_2c;
uint16_t local_28;
short local_24;
bVar1 = dictonary[(param_4 << 1) + 12];
uVar5 = 0x7F80;
local_24 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
local_28 = dictonary[(param_4 << 1) + 13];
local_2c = 0;
i = 0;
do
{
uVar5 = uVar5 << 1;
if ((uVar5 & 0xffff) == 0xFF00)
{
uVar5 = FUN_8c01a480(src, &local_2c);
uVar5 = 0xFF | (uVar5 & 0xff) << 8;
}
if (!(uVar5 & 0x8000))
{
uVar3 = FUN_8c01a480(src, &local_2c);
uVar3 = uVar3 & 0xff;
uVar4 = -(uint)bVar1;
if (bVar1 == 0)
{
uVar4 = uVar3 << (uVar4 & 0x1f);
}
else
{
uVar4 = uVar3 >> ((~uVar4 & 0x1f) + 1);
}
uVar4 = uVar4 + local_28;
local_30 = i - (uVar3 & (int)local_24);
while ((int)local_30 < 0)
{
FUN_8c01a4c0(0, dst, &i);
uVar4--;
local_30++;
}
while ((uVar4 & 0xffff) != 0)
{
uVar3 = FUN_8c01a45a(dst, &local_30);
FUN_8c01a4c0(uVar3, dst, &i);
uVar4--;
}
}
else
{
uVar3 = FUN_8c01a45a(src, &local_2c);
FUN_8c01a4c0(uVar3, dst, &i);
}
}
while (i < len * 2);
i++;
if ((int)(i + 1) < 0)
{
i++;
}
return i >> 1;
}
uint32_t mrg_algo3(uint8_t *dst, uint8_t *src, uint32_t len, int param_4)
{
uint8_t bVar1;
uint32_t uVar2;
uint32_t uVar3;
uint32_t uVar4;
uint32_t i;
uint32_t local_30;
uint32_t local_2c;
short local_28;
uint16_t local_24;
uVar4 = 0x7F80;
bVar1 = dictonary[(param_4 << 1) + 16];
local_28 = (short)(1 << ((uint)bVar1 & 0x1f)) + 0xFFFF;
local_24 = dictonary[(param_4 << 1) + 17];
local_2c = 0;
i = 0;
do
{
uVar4 = uVar4 << 1;
if ((uVar4 & 0xFFFF) == 0xFF00)
{
uVar4 = FUN_8c01a480(src, &local_2c);
uVar4 = 0xFF | (uVar4 & 0xFF) << 8;
}
if (!(uVar4 & 0x8000))
{
uVar2 = FUN_8c01a45a(src, &local_2c);
uVar3 = FUN_8c01a480(src, &local_2c);
uVar3 = ((uVar2 & 0xFF) << 8) | (uVar3 & 0xFF);
uVar2 = -(uint)bVar1;
if (bVar1 == 0)
{
uVar2 = uVar3 << (uVar2 & 0x1F);
}
else
{
uVar2 = uVar3 >> ((~uVar2 & 0x1F) + 1);
}
uVar2 = uVar2 + (int)(short)local_24;
local_30 = i - (uVar3 & (int)local_28);
while ((int)local_30 < 0)
{
FUN_8c01a4c0(0, dst, &i);
uVar2--;
local_30++;
}
while ((uVar2 & 0xFFFF) != 0)
{
uVar3 = FUN_8c01a45a(dst, &local_30);
FUN_8c01a4c0(uVar3, dst, &i);
uVar2--;
}
}
else
{
uVar2 = FUN_8c01a45a(src, &local_2c);
FUN_8c01a4c0(uVar2, dst, &i);
}
}
while (i < len * 2);
i++;
if ((int)(i + 1) < 0)
{
i++;
}
return i >> 1;
}
int decompress_mrg(uint8_t *dst, uint8_t *src)
{
uint32_t encrypt_algo = (src[0] & 0x70) >> 4;
if (!(src[0] & 0x80))
{
memset(dst, 0, BE2LE32(&src[4]));
switch (encrypt_algo)
{
case 0:
return (int) mrg_algo0(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
break;
case 1:
return (int) mrg_algo1(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
break;
case 2:
return (int) mrg_algo2(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
break;
case 3:
return (int) mrg_algo3(dst, &src[8], BE2LE32(&src[4]), src[0] & 0x0F);
break;
}
}
else
{
memset(dst, 0, BE2LE32(src) & 0xFFFFFF);
switch (encrypt_algo)
{
case 0:
return (int) mrg_algo0(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
break;
case 1:
return (int) mrg_algo1(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
break;
case 2:
return (int) mrg_algo2(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
break;
case 3:
return (int) mrg_algo3(dst, &src[4], BE2LE32(src) & 0xFFFFFF, src[0] & 0x0F);
break;
}
}
return -1;
}
typedef struct
{
uint32_t offset;
uint32_t size;
} vFILE_t;
typedef struct
{
uint32_t f_cnt;
vFILE_t vFile[1024];
} mrg_s;
off_t fsize(const char *filename)
{
struct stat st;
if (stat(filename, &st) == 0)
{
return st.st_size;
}
return -1;
}
int main(int argc, char *argv[])
{
FILE *fo, *fi;
int i, i_sz, o_sz;
uint8_t *in_buf, *out_buf;
mrg_s *iMRG = NULL;
char name[256];
uint32_t tmp_sz;
if (argc != 2)
{
printf("no input file\n");
return 1;
}
if ((i_sz = fsize(argv[1])) == -1 || !(fi = fopen(argv[1], "rb")))
{
printf("ERROR: can't open %s\n", argv[1]);
return 1;
}
if (!(in_buf = calloc(i_sz, 1)))
{
printf("ERROR: can't allocate %d bytes\n", i_sz);
fclose(fi);
return 1;
}
if (!(out_buf = calloc(i_sz, 1)))
{
printf("ERROR: can't allocate %d bytes\n", i_sz);
fclose(fi);
return 1;
}
fread(in_buf, 1, i_sz, fi);
fclose(fi);
iMRG = (mrg_s *) in_buf;
for (i = 0; i < iMRG->f_cnt; i++)
{
tmp_sz = !(in_buf[iMRG->vFile[i].offset] & 0x80) ? BE2LE32(&in_buf[iMRG->vFile[i].offset+4]) :
(BE2LE32(&in_buf[iMRG->vFile[i].offset]) & 0xFFFFFF);
out_buf = realloc(out_buf, tmp_sz);
if ((o_sz = decompress_mrg(out_buf, &in_buf[iMRG->vFile[i].offset])) == -1)
{
printf("ERROR: can't decrypt file %d of %u\n", i, iMRG->f_cnt);
continue;
}
uint32_t offset = !(strncmp((char *) out_buf, "PVRX", 4)) ? 0x24 : 0;
if (offset == 0x24 || (!offset && !(strncmp((char *) out_buf, "GBIX", 4))))
{
sprintf(name, "%s_%d.pvr", argv[1], i);
}
else
{
sprintf(name, "%s_%d.bin", argv[1], i);
}
if (!(fo = fopen(name, "wb")))
{
printf("ERROR: can't open for write %s\n", name);
continue;
}
fwrite(out_buf + offset, 1, o_sz - offset, fo);
fclose(fo);
}
free(in_buf);
free(out_buf);
return 0;
}