(PSP) Monster Hunter Freedom Unite DATA.BIN extract

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
BadhornStadnent
Posts: 7
Joined: Sat May 28, 2016 10:19 pm

(PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by BadhornStadnent »

I need some help with extracting DATA.BIN from monster hunter freedom unite (PSP), I've tried other ways but just wasn't successful.

Something that could help would be appreciated.
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by aluigi »

Please provide DATA.BIN.
If it's very big you can upload the 2 files generated with this script:
http://aluigi.org/bms/filecutter.bms
BadhornStadnent
Posts: 7
Joined: Sat May 28, 2016 10:19 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by BadhornStadnent »

Sure, here is it is.

http://puu.sh/qmzby.zip
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by aluigi »

Completely encrypted. Can't help.
Ekey
Posts: 1383
Joined: Sat Aug 09, 2014 2:34 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by Ekey »

*Edited*

Seems it's :
https://github.com/codestation/mhtools/ ... ypter.java
https://github.com/codestation/mhtools/ ... aKeys.java

and
https://github.com/svanheulen/mhef/blob ... hef/psp.py

=======================

Code: Select all

void fun_884ea1c(struct s0* Buffer, int32_t Size) {
    struct s0* s4_6;
    unsigned char* s3_7;
    unsigned char* s2_8;
    unsigned char* s1_9;
    int32_t i;
    uint32_t v0_11;
    int32_t Secret = 0;

    s4_6 = Buffer;
    s3_7 = &Buffer->f1;
    s2_8 = &Buffer->f2;
    s1_9 = &Buffer->f3;
    if (Size > 0) {
        i = 0;
        while (1) {
            s4_6->f0 = static_cast<unsigned char>(static_cast<uint32_t>(*reinterpret_cast<unsigned char*>(m_Key + s4_6->f0)));
            *s3_7 = static_cast<unsigned char>(static_cast<uint32_t>(*reinterpret_cast<unsigned char*>(m_Key + *s3_7)));
            *s2_8 = static_cast<unsigned char>(static_cast<uint32_t>(*reinterpret_cast<unsigned char*>(m_Key + *s2_8)));
            *s1_9 = static_cast<unsigned char>(static_cast<uint32_t>(*reinterpret_cast<unsigned char*>(m_Key + *s1_9)));
            v0_11 = fun_884ecac(Secret);
            i = i + 4;
            s3_7 = s3_7 + 4;
            s4_6->f0 = reinterpret_cast<unsigned char>(s4_6->f0 ^ v0_11);
            s2_8 = s2_8 + 4;
            ++s4_6;
            if (i >= Size)
                break;
            s1_9 = s1_9 + 4;
        }
    }
    return;
}


=======================

Converted :)

Code: Select all

unsigned char m_Encrypted_Table[256] =
{
    0xCB, 0x96, 0x85, 0xA6, 0x5F, 0x3E, 0xAB, 0x03, 0x50, 0xB7, 0x9C, 0x5C, 0xB2, 0x40, 0xEF, 0xF6,
    0xFF, 0x61, 0x15, 0x29, 0xA2, 0xF1, 0xEC, 0x52, 0x35, 0x28, 0xD9, 0x68, 0x24, 0x36, 0xC4, 0x74,
    0x26, 0xE2, 0xD5, 0x8C, 0x47, 0x4D, 0x2C, 0xFA, 0x86, 0x66, 0xC1, 0x4F, 0x0B, 0x81, 0x5B, 0x1B,
    0xC0, 0x0A, 0xFD, 0x17, 0xA4, 0xA9, 0x6D, 0x63, 0xAD, 0xF3, 0xF4, 0x6E, 0x8D, 0x89, 0x14, 0xDD,
    0x59, 0x87, 0x4A, 0x30, 0xCE, 0xFE, 0x3F, 0x7E, 0x06, 0x49, 0xA5, 0x04, 0x5E, 0xD0, 0xDE, 0xE8,
    0x0F, 0xD4, 0x13, 0x1F, 0xBA, 0xB9, 0x69, 0x71, 0x3D, 0xE4, 0xDC, 0x58, 0x90, 0x34, 0x3A, 0x3C,
    0xCA, 0x10, 0x76, 0xC7, 0xC8, 0x45, 0x33, 0xC3, 0x92, 0x1D, 0x2B, 0x1C, 0x8F, 0x6F, 0x05, 0x07,
    0x38, 0x57, 0x51, 0xD6, 0xDA, 0x2D, 0xB3, 0xC6, 0x2E, 0x64, 0x32, 0x1E, 0x43, 0xB1, 0x5D, 0xE1,
    0xBB, 0x8E, 0x9D, 0x72, 0x77, 0xF2, 0x27, 0xC9, 0x7F, 0x9E, 0xAA, 0x6A, 0x2F, 0x6C, 0xF9, 0x48,
    0xE7, 0xA0, 0x09, 0x56, 0xB8, 0xBD, 0x20, 0x41, 0xCD, 0x95, 0x80, 0xD7, 0x23, 0x0C, 0x42, 0xE5,
    0xAE, 0x8B, 0x7D, 0xBC, 0x54, 0x39, 0xBF, 0x65, 0x01, 0x88, 0xE0, 0x7B, 0xB6, 0x16, 0x18, 0x4B,
    0xCC, 0x22, 0x5A, 0xB5, 0xEB, 0xFC, 0xF8, 0x9B, 0x4E, 0xE6, 0xA8, 0xBE, 0x67, 0x73, 0x97, 0x94,
    0x00, 0x62, 0xB4, 0xD2, 0x21, 0x25, 0x11, 0x82, 0xDB, 0x93, 0x02, 0x84, 0x7C, 0xD3, 0xB0, 0xA3,
    0x91, 0xA7, 0xF7, 0x55, 0x70, 0x7A, 0x08, 0x75, 0x8A, 0x53, 0x79, 0xFB, 0x9F, 0x46, 0xF5, 0x83,
    0xD8, 0x0E, 0xE9, 0xED, 0x12, 0xD1, 0xDF, 0xF0, 0x37, 0x2A, 0x44, 0x19, 0x9A, 0x31, 0xCF, 0xA1,
    0xAF, 0xE3, 0x3B, 0x1A, 0x4C, 0x78, 0xC2, 0x60, 0xEE, 0x98, 0x6B, 0x0D, 0x99, 0xEA, 0xC5, 0xAC,
};

int dwKey1 = 0x00007F8D;
int dwKey2 = 0x00002345;

void set_key(int dwOffset)
{
   dwKey1 = dwOffset & 0xFFFF;
   if(dwKey1 == 0)
      dwKey1 = 0x7F8D;

   dwKey2 = dwOffset >> 16;
   if(dwKey2 == 0)
      dwKey2 = 0x2345;
}

int xor_by_key(void)
{
   dwKey1 = (dwKey1 * 0x7F8D) % 0xFFF1;
   dwKey2 = (dwKey2 * 0x2345) % 0xFFD9;
   return dwKey1 + (dwKey2 << 16);
}

void iDecrypt(unsigned char *pBuffer, int dwSize)
{
   for(int i = 0; i < dwSize; i += 4){
      pBuffer[0] = m_Encrypted_Table[pBuffer[0]];
      pBuffer[1] = m_Encrypted_Table[pBuffer[1]];
      pBuffer[2] = m_Encrypted_Table[pBuffer[2]];
      pBuffer[3] = m_Encrypted_Table[pBuffer[3]];
      *(int*)pBuffer ^= xor_by_key();
      pBuffer += 4;
   }
}


All data's crypted by offset
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by aluigi »

I see the header till 0x8170 but then?

Code: Select all

set MEMORY_FILE3 compressed "eNo91WegD3QYxfH/NYq6ureSlJTM7GggJOMp2bKyKRIKWckIccolqYRooUTDqhCKLvqSUUZZFRqyicqs++94483vc87L583vtMjY32rl+OGJRMsVu5KJRLPlUSSRGHk0PSWRGBe50N9ZyeQG9I+ZjE4bpS3ZjM44va+t6KxDx7Q4j8453Zt5Nh2dd/ooLXaiC07Z0b+mCfrPLEFZ5k2UNO1QIplMfoJSzH0omzmBspvTKIdJopx+O6PLzHXoclMS5TIzUW5zEl1hjqIrzUMo1dyF8pjb0FVmF0ozj6N0UxRdbe5G15g16FrTH+U1xdF15leUz/yArjcvovzmAXSDaYhuNGVQAePTbzLPo4LmMXSzyUS3mMaokLkS3WpGosKmLSpiCqCi5itUzFyBipv/UAlzPbrNvIdKmg9QKfMkKm0eRWXMXFTW/IXKmb9RedML3W7GowomA1U0edEd5md0p2mN7jIvoLtNPVTJ3I4qm29RFZOF7jE1UFXzLKpmLkPVzYPoXjML1TA50H2mA6ppNqNaZg+qbQ6iOiYNhfke3W+uRQ+YW1Bdsww9aJaieqY7qm+eQg1MddTQ/I4amZ9QY/MwamJeRk3Nneghcw9qZqqh5mY9amHSUUszELUya9HDZh1qbQK1MXegtmY1amdeRe1NQdTBlEYdzU2ok5mAOpve6BGTEz1qLkddTGXU1bRCj5mmqJvZjh43u1F3Uxb1MJ+ingb0hCmHnjRdUC9TEfU2N6M+pjZ6yixEfU171M/8gvqb5WiAeQkNNG+hp01fNMg8jZ4xp9BgUwINMd+goWY4GmbeRs+aD9Fw04MYUZ4Y+QTx3DliVF1i9AFC04nncxMvtCTGfE5kfEmMLUSMq0m8uIkYP4l4aQQxYQfxchHilVTi1VrExP3Ea/OISeOIycOIKV8QrzcnplYhpq0k3uhKvJlCvDWGeHsf8c4QYvpiYkY+YmZ+4t36xHsbiVmFiffbELMXEXOOEB/8S3x4lvjoDeLjRsTcP4h5c4j5K4gF3YiF/YhPphCfvkZ8liAWPUIs/oxYspX4/FZiaTFi2dXE8ueIL34kvpxIrMhGrBxNfDWUyNxGrFpArH6XWPMK8fVsgjPE2hbEuj7EN4OJ9bmIDQOIjWOJTc2Ib58hvrtAbH6H2HI/sfUfYtso4vudxA9XEdsPETuOETuvIXZtIXbvJX78c1zDVOKnSsTPpYg9dYi9NxD7phG/VCB+/Y74bQbx+3xi/2/EH1WJAzcSBxsQhwYRh1cRRzoRR48Tx14njvckTuQh/pxKnDxMnPqa+OvjjHWlI7VqpA/rmLY4ZezonBe/8DEpaYtrXio1L7Zsl1o2t+yXWvbuay/uwcqTnoOpZ5LdV4cXIWPH1DNZGZsztmXuS085WyFlVGaOI1NGrrk4E207dGy/+n/TxBkw"

savepos OFFSET
get SIZE asize
math SIZE - OFFSET
encryption calldll "MEMORY_FILE3 0 cdecl RET OFFSET #INPUT# #INPUT_SIZE#"
log "test.dat" OFFSET SIZE

Curiosity: MEMORY_FILE3 is a just function containing the code posted by Ekey with m_Encrypted_Table generated at runtime to avoid non-stack buffers and calling "set_key(offset); iDecrypt(data, datasz);"
Ekey
Posts: 1383
Joined: Sat Aug 09, 2014 2:34 pm

Re: (PSP) Monster Hunter Freedom Unite DATA.BIN extract

Post by Ekey »

aluigi wrote:I see the header till 0x8170 but then?

Yeah, it's index table.

based of python code we need read 4 bytes, decrypt it, result value * 2048 = index table size > 0x8800. I tryed and in index table last 0x690 bytes is invalid, just junk.

Code: Select all

def decrypt_file(self, data_file, out_file):
        """
        Save a decrypted copy of the given DATA.BIN file.
        Arguments:
        data_file -- Path to an encrypted DATA.BIN file
        out_file -- Path to save the decrypted DATA.BIN file
        """
        with open(data_file, 'rb') as data, open(out_file, 'wb') as out:
            # Decrypt the block address of the first file to determine the size
            # of the table of contents
            toc_size = self.decrypt(data.read(4), 0)
            toc_size = array.array('I', toc_size)[0] * 2048
            file_size = data.seek(0, os.SEEK_END)
            data.seek(0)
            # Decrypt the table of contents
            toc = self.decrypt(data.read(toc_size), 0)
            out.write(toc)
            toc = array.array('I', toc)
            # Find the number of files by getting the index of the table of
            # contents entry pointing to the end of the file
            file_count = toc.index(file_size // 2048)
            # Decrypt each file in the data file
            for i in range(file_count):
                data.seek(toc[i] * 2048)
                out.seek(toc[i] * 2048)
                buff = data.read((toc[i+1] - toc[i]) * 2048)
                # Skip decryption of certain files
                if i in self._exceptions:
                    out.write(buff)
                else:
                    out.write(self.decrypt(buff, toc[i]))


* Edited 2 *

From bin loader - decrypting two times:

First - with size 0x6808
Second - with size 0x1968

Code: Select all

li      $a2, 0x6808
jal     VFS_DECRYPT


Code: Select all

li      $a2, 0x1968
jal     VFS_DECRYPT


0x6808 + 0x1968 = 0x8170

Looks like there is two tables