extract some archive file [exm2lib, mdf]

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
bam_bam
Posts: 31
Joined: Thu Apr 21, 2016 1:06 pm

extract some archive file [exm2lib, mdf]

Post by bam_bam »

I know that already exist a tool for this archive file.
but Is it possible to make a QuickBMS script?
and I've been trying to get some images from psb files.
Image tools also exist, but it doesn't work in my case.
Can anybody help me?
A title is Kenka Banchou Otome. Thank you for reading.

archive file :: https://www.dropbox.com/s/tv0jgdokp6rw3sv
extract tool :: http://asmodean.reverse.net/pages/exm2lib.html
image file :: https://www.dropbox.com/s/9e0u8j2g5laiu9h
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: extract some archive file

Post by aluigi »

*updated*
work-in-progress script:

Code: Select all

quickbmsver "0.8.0"

set MEMORY_FILE10 binary "
/* Period parameters */ 
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */

static unsigned long mt[N]; /* the array for the state vector  */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */

void mt_xor_state(unsigned char* buff, unsigned long len)
{
  unsigned long* words = (unsigned long*) buff;
  unsigned long  word_count = len / 4;
  unsigned long  i;

  if (word_count > N)
  {
    word_count = N;
  }

  for (i = 0; i < word_count; i++)
  {
    mt[i] ^= words[i];
  }
}

/* initializes mt[N] with a seed */
void init_genrand(unsigned long s)
{
    mt[0]= s & 0xffffffffUL;
    for (mti=1; mti<N; mti++) {
        mt[mti] =
      (1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
        /* In the previous versions, MSBs of the seed affect   */
        /* only MSBs of the array mt[].                        */
        /* 2002/01/09 modified by Makoto Matsumoto             */
        mt[mti] &= 0xffffffffUL;
        /* for >32 bit machines */
    }
}

/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void init_by_array(unsigned long init_key[], int key_length)
{
    int i, j, k;
    init_genrand(19650218UL);
    i=1; j=0;
    k = (N>key_length ? N : key_length);
    for (; k; k--) {
        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
          + init_key[j] + j; /* non linear */
        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
        i++; j++;
        if (i>=N) { mt[0] = mt[N-1]; i=1; }
        if (j>=key_length) j=0;
    }
    for (k=N-1; k; k--) {
        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
          - i; /* non linear */
        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
        i++;
        if (i>=N) { mt[0] = mt[N-1]; i=1; }
    }

    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}

/* generates a random number on [0,0xffffffff]-interval */
unsigned long genrand_int32(void)
{
    unsigned long y;
    static unsigned long mag01[2]={0x0UL, MATRIX_A};
    /* mag01[x] = x * MATRIX_A  for x=0,1 */

    if (mti >= N) { /* generate N words at one time */
        int kk;

        if (mti == N+1)   /* if init_genrand() has not been called, */
            init_genrand(5489UL); /* a default initial seed is used */

        for (kk=0;kk<N-M;kk++) {
            y = ((mt[kk+1] ^ mt[kk]) & LOWER_MASK) ^ mt[kk];
            mt[kk] = mt[kk+M] ^  mag01[y & 1] ^ (y >> 1);
        }
        for (;kk<N-1;kk++) {
            y = ((mt[kk+1] ^ mt[kk]) & LOWER_MASK) ^ mt[kk];
            mt[kk] = mt[kk+(M-N)] ^  mag01[y & 1] ^ (y >> 1);
        }
        y = (mt[N-1]&UPPER_MASK)|((mt[0]&LOWER_MASK) >> 1);
        mt[N-1] = mt[M-1] ^ y ^ mag01[mt[kk+1] & 0x1UL];

        mti = 0;
    }
 
    y = mt[mti++];

    /* Tempering */
    y ^= (y>>11);
    y ^= (y & 0xff3a58ad) << 7;
    y ^= (y & 0xffffdf8c) <<15;
    y ^= (y >> 18);

    return y;
}
"

getdstring SIGN 4   # mdf, mfl, mxb
get XSIZE long
savepos OFFSET
get SIZE asize
math SIZE - OFFSET

/*
  { "Dunamis 15 (XBOX360)", "4nDSd4sa2v", 0x54 },
  { "IS〈インフィニット・ストラトス〉2 イグニッション・ハーツ (PS3)", "9362abe723sfe", 0x83 },
*/
set GAME_SEED binary "9362abe723sfe"
math key_len = 0x83

get NAME filename
string NAME l NAME
string TMP p "%s%s" GAME_SEED NAME
print "SEED %TMP%"
encryption md5 TMP
encryption "" ""
print "MD5 %QUICKBMS_HEXHASH%"
calldll MEMORY_FILE10 "init_by_array" "tcc" RET QUICKBMS_HASH 4
set KEY binary ""
for i = 0 < key_len
    calldll MEMORY_FILE10 "genrand_int32" "tcc" RET
    putvarchr KEY i RET long
next i + 4
print "KEY %KEY|X%"
encryption xor KEY "" 0 key_len

if SIGN == "mxb"
    comtype xmemdecompress
    # THIS IS WRONG, not implemented yet
elif SIGN == "mdf"
    comtype zlib
else
    comtype copy
endif
clog "dump.dat" OFFSET SIZE XSIZE


Just curious, why dod you need a quickbms script if already exists a complete tool?

*edit* the code is not the same used by the tool, that's why it fails... oh what surprise
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: extract some archive file

Post by aluigi »

Exactly as I guessed, it's a customized algorithm and so was pretty obvious that the original code didn't work.
Obviously the customized part was NOT available in the source code (typical of asmodean).

I think I have correctly customized everything as you can test with the updated script above.

The dump.dat generated from font_info.psb.m is correct, don't know if the same code must be applied also to font_body.bin because the output is wrong.

Anyway that's enough for me.

P.S.: a python code I found by searching the contants http://www.pujia8.com/topic/5739/