Diablo II mpq

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Diablo II mpq

Post by AlphaTwentyThree »

I know there are MPQ editors and extractors BUT they all decode the included adpcm files into raw PCM. Which is not what I'm after. I'm searching for a way to simply decompress the MPQ archive and extract the raw contents.
Here's an example: https://mega.nz/#!2tVjzSKC!7GBu5nX1r5Cl ... 4R7xJGBlQ0
Would be a blast to finally get my hands on the REAL files rather than the pseudo files!
Thanks for your help!
Delutto
Posts: 561
Joined: Tue Oct 13, 2015 1:26 pm

Re: Diablo II mpq

Post by Delutto »

Since you are a script maker, here is the format structure: http://www.zezula.net/en/mpq/mpqformat.html
AnonBaiter
Posts: 1125
Joined: Tue Feb 02, 2016 2:35 am

Re: Diablo II mpq

Post by AnonBaiter »

i'm not sure how you'd expect him to write a script based on that format

if anything else though i'll just leave this here
https://github.com/ladislav-zezula/StormLib
Delutto
Posts: 561
Joined: Tue Oct 13, 2015 1:26 pm

Re: Diablo II mpq

Post by Delutto »

AnonBaiter wrote:i'm not sure how you'd expect him to write a script based on that format
Why not? As you can see in this thread, I don't believe he will have any difficulty...
About StormLib, the home site of this lib is the one I pointed: http://www.zezula.net
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Diablo II mpq

Post by AlphaTwentyThree »

Well, the problem with that file is that it's compressed or encrypted, I hope the first. I haven't been able to find the decompression type, so I'm asking for help here. The first link doesn't say anything about a compression, so I'm at a loss here...
Delutto
Posts: 561
Joined: Tue Oct 13, 2015 1:26 pm

Re: Diablo II mpq

Post by Delutto »

AlphaTwentyThree wrote:Well, the problem with that file is that it's compressed or encrypted, I hope the first. I haven't been able to find the decompression type, so I'm asking for help here. The first link doesn't say anything about a compression, so I'm at a loss here...
Quick look at your file, we can see that it is an MPQ format version 1, so there's no HET and BET table, only the HashTable and BlockTable, both are encrypted, look in Fundamentals for informations about hash theory, after decrypted you'll able to read the Flags that determined if the blocks/data are encrypted or compressed and what compression method is used.
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Diablo II mpq

Post by AlphaTwentyThree »

Delutto wrote:
AlphaTwentyThree wrote:Well, the problem with that file is that it's compressed or encrypted, I hope the first. I haven't been able to find the decompression type, so I'm asking for help here. The first link doesn't say anything about a compression, so I'm at a loss here...
Quick look at your file, we can see that it is an MPQ format version 1, so there's no HET and BET table, only the HashTable and BlockTable, both are encrypted, look in Fundamentals for informations about hash theory, after decrypted you'll able to read the Flags that determined if the blocks/data are encrypted or compressed and what compression method is used.

Wow, well... that really surpasses my experience to be honest. I'd be glad if somebody could do this for me. Sorry for sounding lazy but it just doesn't seem worthwile to get into all that theory just to be able to get these files. :( So.... pretty please? ;)
AnonBaiter
Posts: 1125
Joined: Tue Feb 02, 2016 2:35 am

Re: Diablo II mpq

Post by AnonBaiter »

heh

Code: Select all

callfunction mpq_encryption_table_01 1

goto 0

get mpq_01 long
if mpq_01 == 0x1a51504d
   callfunction parse_mpq 1
elif mpq_01 == 0x1b51504d
   #callfunction parse_mpq 1
   print "user data detected"
   cleanexit
else
   print "wrong mpq file"
   cleanexit
endif

startfunction parse_mpq
   get mpq_02 long
   get mpq_03 long
   get mpq_04 short
   get mpq_05 short
   get mpq_06 long
   get mpq_07 long
   get mpq_08 long
   get mpq_09 long

   goto mpq_06
   set stringy_stig string "(block table)"
   callfunction mpq_hashing_algorithm 1
   math key = var_4
   math length = mpq_08
   callfunction mpq_encryption_table_02 1
   goto mpq_07
   set stringy_stig string "(hash table)"
   callfunction mpq_hashing_algorithm 1
   math key = var_4
   math length = mpq_08
   callfunction mpq_encryption_table_02 1
endfunction

startfunction mpq_encryption_table_01
   math var_8 = 0x100001
   math var_4 = 0
   math var_C = 0
   math vc_02 = 0
   for i = var_4 < 0x100
      for var_C = var_4 < 5
         math load_01 = 0
         math load_02 = 0
         xmath var_8 "(var_8 * 0x7D + 3) % 0x2AAAAB"
         xmath load_01 "(var_8 & 0xFFFF) << 0x10"
         xmath var_8 "(var_8 * 0x7D + 3) % 0x2AAAAB"
         xmath load_02 "(var_8 & 0xFFFF)"
         xmath buffer "load_01 | load_02"
         putarray 1 vc_02 buffer
         math vc_02 += 0x100
      next var_C
      math vc_02 -= 0x500
      math vc_02 + 1
   next i
endfunction

startfunction mpq_encryption_table_02
   math var_4 = 0xEEEEEEEE
   math buffer_02 = 0
   math length >> 2
   for vi = 0 < length
      xmath key_02 "0x400 + (key & 0xff)"
      getarray buffer_01 1 key_02
      xmath temp_01 "buffer_01 + key_02"
      math var_4 + temp_01
      get data_block long
      xmath data_block "data_block ^ (key + var_4)"
      math buffer_02 = data_block
      xmath key_02 "(((key ~ key) << 0x15) + 0x11111111) | (key >> 0x0B)"
      xmath var_4 "buffer_02 + var_4 + (var_4 << 5) + 3"
   next vi
endfunction

startfunction mpq_hashing_algorithm
   strlen stringy_chars stringy_stig
   math var_4 = 0x7FED7FED
   math var_8 = 0xEEEEEEEE
   for c = 0 < stringy_chars
      getvarchr character_byte stringy_stig c byte
      math var_14 = 0
      xmath var_14 "var_14 + character_byte"
      getarray buffer 1 var_14
      xmath var_4 "buffer ^ (var_4 + var_8)"
      xmath var_8 "character_byte + var_4 + var_8 + (var_8 << 5) + 3"
   next c
endfunction
mind you, i had to cross-check StormLib's code with the most ancient EXE file that read some MPQ file for this
however, as a consequence of this the script youre seeing above is practically unusable in every possible way so kudos for anyone who tries to make this shit work!