Skip to content

Instantly share code, notes, and snippets.

@jessy-lua
Created October 15, 2021 06:27
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jessy-lua/d080b7bf499d72d2911f9bb15d9f2fc5 to your computer and use it in GitHub Desktop.
Save jessy-lua/d080b7bf499d72d2911f9bb15d9f2fc5 to your computer and use it in GitHub Desktop.
New World oodle preset for QuickBMS
# ZIP files example 0.4.11
# more info: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
# note that with some archives like those created by Stuff-it on MacOSX is
# not possible to use this script because they are wrongly built, practically
# they set the comp_size and uncomp_size fields of the "Local file header" at
# 0 and they set them only in the relative "Central directory structure" which
# means that it's necesary to read this one first for extracting the files
# contained in the local header... senseless and stupid
# script for QuickBMS http://quickbms.aluigi.org
# put the password here, it supports both ZipCrypto and AES
set ZIP_PASSWORD string ""
quickbmsver "0.7.4"
get EXE_SIGN long
goto 0
if EXE_SIGN == 0x00905a4d
get EXT extension
if EXT == "exe" || EXT == "dll"
findloc OFFSET string "PK\x03\x04"
goto OFFSET
endif
elif EXE_SIGN == 0x02014b50
findloc OFFSET binary "\x50\x4b\x03\x04"
goto OFFSET
endif
savepos OFFSET
set ZIP_SIGN short 0x0403
goto OFFSET
getdstring ZIP_CENTRAL_SEARCH 6 # PK_sign + sign + ver
goto OFFSET
get DUMMY short
get ZIP_SIGN short
math ALTERNATIVE_MODE = 0 # in reality this is the real correct mode to read the ZIP archives
math FIRST_FILE = 1
goto OFFSET
get zip_filesize asize
for offset = offset < zip_filesize
#idstring "PK\x03\x04"
get PK_sign short # so it works also with modified ZIP files!
get sign short
if sign == ZIP_SIGN # Local file header
get ver short
get flag short
get method short
get modtime short
get moddate short
get zip_crc long
get comp_size long
get uncomp_size long
get name_len short
get extra_len short
getdstring name name_len
getdstring extra extra_len
savepos offset
if FIRST_FILE != 0
math FIRST_FILE = 0
if flag & 8
if zip_crc == 0
if comp_size == 0
#if uncomp_size == 0 # needs to be commented out
goto -0x16
get PK_sign short
idstring "\x05\x06"
get disk_num short
get disk_start short
get central_entries short
get central_entries short
get central_size long
get central_offset long
get comm_len short # let's think it's zero
getdstring comment comm_len
math ALTERNATIVE_MODE = 1
math ALTERNATIVE_OFFSET = central_offset
math ALTERNATIVE_comp_size = 0
math ALTERNATIVE_uncomp_size = 0
math ALTERNATIVE_zip_crc = 0
set NAME string "/" # skip this file
math uncomp_size = 0 # skip this file
#endif
endif
endif
endif
endif
if ALTERNATIVE_MODE != 0
math comp_size = ALTERNATIVE_comp_size
math uncomp_size = ALTERNATIVE_uncomp_size
math zip_crc = ALTERNATIVE_zip_crc
endif
# zip64
if extra_len >= 20
getvarchr extra_id extra 0 short
if extra_id == 0x0001
if comp_size == 0xffffffff
getvarchr uncomp_size 4 longlong
getvarchr comp_size 12 longlong
endif
endif
endif
# possible lame tricks used by games
if comp_size & 0x80000000 # < 0
if comp_size u> zip_filesize
math comp_size ^= 0xffffffff
math uncomp_size ^= 0xffffffff
endif
endif
if name_len & 0x80000000 # < 0
math name_len ^= 0xffffffff
endif
if extra_len & 0x80000000 # < 0
math extra_len ^= 0xffffffff
endif
if flag & 1
if ZIP_PASSWORD == ""
print "the file is encrypted, you must set ZIP_PASSWORD in the script!"
#cleanexit
endif
math method_backup = method
if method == 99
getvarchr AES_EXTRA1 extra 0 short # Extra field header ID (0x9901)
getvarchr AES_EXTRA2 extra 2 short # Data size (currently 7, but subject to possible increase in the future)
getvarchr AES_EXTRA3 extra 4 short # Integer version number specific to the zip vendor
getvarchr AES_EXTRA4 extra 6 short # 2-character vendor ID
getvarchr AES_EXTRA5 extra 8 byte # Integer mode value indicating AES encryption strength
getvarchr AES_EXTRA6 extra 9 short # The actual compression method used to compress the file
math method = AES_EXTRA6
if AES_EXTRA5 == 0x01
math AES_KEY_SIZE = 8
set AES_ALGO string "ZIP_AES128"
elif AES_EXTRA5 == 0x02
math AES_KEY_SIZE = 12
set AES_ALGO string "ZIP_AES192"
elif AES_EXTRA5 == 0x03
math AES_KEY_SIZE = 16
set AES_ALGO string "ZIP_AES256"
else
print "Error: invalid AES_EXTRA5 %AES_EXTRA5%"
cleanexit
endif
getdstring AES_SALT AES_KEY_SIZE
xmath offset "offset + (AES_KEY_SIZE + 2)"
xmath comp_size "comp_size - (AES_KEY_SIZE + 2 + 10)"
strlen ZIP_PASSWORD_LEN ZIP_PASSWORD
encryption AES_ALGO ZIP_PASSWORD AES_SALT 0 ZIP_PASSWORD_LEN # long story short, set the password length or use "Set binary"
else
encryption zipcrypto ZIP_PASSWORD 1
endif
endif
if method == 0
Log name offset comp_size # was uncomp_size before AES
else
if method == 8
ComType deflate
elif method == 1
ComType shrink
elif method == 2
ComType reduce1
elif method == 3
ComType reduce2
elif method == 4
ComType reduce3
elif method == 5
ComType reduce4
elif method == 6
ComType pkware # ???
elif method == 9
ComType deflate64
elif method == 10
ComType pkware # ???
elif method == 12
ComType bzip2
elif method == 13
ComType XMemDecompress
elif method == 14
ComType lzmaefs
elif method == 15
ComType oodle
elif method == 18
ComType terse # ???
elif method == 21
ComType XMemDecompress
elif method == 28
ComType lz4f
elif method == 34
ComType brotli
elif method == 64
ComType darksector
elif method == 95
comtype LZMA2_EFS0
getdstring XZ_MAGIC 6
get XZ_FLAGS0 byte
get XZ_FLAGS byte
get XZ_CRC32 long
xmath DUMMY "1 << ((((XZ_FLAGS & 0xf) - 1) / 3) + 2)"
getdstring DUMMY DUMMY
savepos tmp
xmath comp_size "comp_size - (tmp - offset)"
math offset = tmp
elif method == 96 # compressed jpeg
ComType copy
math uncomp_size = comp_size
string name + ".jpg"
elif method == 97 # wavpack
ComType copy
math uncomp_size = comp_size
string name + ".wv"
elif method == 98
ComType ppmd
elif method == 99
ComType lzfse
else
print "unsupported compression method %method%"
cleanexit
endif
CLog name offset comp_size uncomp_size
endif
if flag & 1
encryption "" ""
if method_backup == 99
math offset += 10
endif
endif
math offset += comp_size
goto offset
if ALTERNATIVE_MODE != 0
goto ALTERNATIVE_OFFSET
endif
elif sign == 0x0806 # Archive extra data record
get extra_len long
getdstring extra extra_len
elif sign == 0x0201 # Central directory structure
get ver_made short
get ver_need short
get flag short
get method short
get modtime short
get moddate short
get zip_crc long
get comp_size long
get uncomp_size long
get name_len short
get extra_len short
get comm_len short
get disknum short
get int_attr short
get ext_attr long
get rel_offset long
getdstring name name_len
getdstring extra extra_len
getdstring comment comm_len
if ALTERNATIVE_MODE != 0
math ALTERNATIVE_comp_size = comp_size
math ALTERNATIVE_uncomp_size = uncomp_size
math ALTERNATIVE_zip_crc = zip_crc
savepos ALTERNATIVE_OFFSET
goto rel_offset
endif
elif sign == 0x0505 # Digital Signature
get sign_len long
getdstring sign sign_len
elif sign == 0x0606 # Zip64 end of central directory record
get dir_record longlong
get ver_made short
get ver_need short
get num_disk long
get num_disk2 long
get tot_entries longlong
get tot_entries2 longlong
get central_size longlong
get central_offset longlong
print "Error: zip64 extensible data sector not implemented, contact me"
cleanexit
elif sign == 0x0706 # Zip64 end of central directory locator
get start_central long
get end_central longlong
get disks long
elif sign == 0x0605 # End of central directory record
get disk_num short
get disk_start short
get central_entries short
get central_entries short
get central_size long
get central_offset long
get comm_len short
getdstring comment comm_len
elif sign == 0x0807 # Data Descriptor
get zip_crc long
get comp_size long
get uncomp_size long
elif sign == 0x3030 # disk spanning
# nothing?
else
# A ZIP archive should be read from the end and not sequentially because in some rare cases
# we may have some "gaps" between the various directories, this is a basic way to guess
# the beginning of the next directory
# ZIP_CENTRAL_SEARCH contains zeroes that will not be considered, not a problem
print "...search ZIP signature..."
findloc NEW_OFFSET binary ZIP_CENTRAL_SEARCH ""
if NEW_OFFSET == ""
xmath COVERAGE "offset / (zip_filesize / 100)" # "(offset*100)/zip_filesize" may go in overflow on 32bit
set COVERAGE_OK string "not fully covered, lot of data remaining"
if COVERAGE >= 90
set COVERAGE_OK string "fully covered, probably no remaining data"
endif
print "\nError: unknown ZIP signature %sign|x% at offset %offset|x%\n if the other files have been extracted correctly it's all ok,\n maybe this is just the end of file:\n\n OFFSET %offset|x%\n ZIP SIZE %zip_filesize|x%\n COVERAGE %COVERAGE% / 100 (%COVERAGE_OK%)"
cleanexit
endif
goto NEW_OFFSET
endif
savepos offset
next
@GooDDarK
Copy link

GooDDarK commented Nov 19, 2021

During the Reimport xml file there is an error that the modified file is larger than the original, although this is not true.
The console shows that the original compressed file weighs 1895 bytes, while the new file is only compressed to 2410 bytes and also "Error: zip64 extensible data sector not implemented, contact me".
Bad compression method or what is the problem?

image

@pmqs
Copy link

pmqs commented Nov 9, 2022

@jessy-lua do you happen to remember the source of the compression methods that aren't in either APNOTE or the infozip equivalent.

In particular,

  • 13 ComType XMemDecompress
  • 14 lzmaefs
  • 15 oodle
  • 21 XMemDecompress
  • 28 lz4f
  • 34 brolti
  • 64 darksector

@jessy-lua
Copy link
Author

@jessy-lua do you happen to remember the source of the compression methods that aren't in either APNOTE or the infozip equivalent.

In particular,

  • 13 ComType XMemDecompress
  • 14 lzmaefs
  • 15 oodle
  • 21 XMemDecompress
  • 28 lz4f
  • 34 brolti
  • 64 darksector

I even don't know what this means, sorry 🤷‍♂️

@pmqs
Copy link

pmqs commented Nov 10, 2022

No worries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment