Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Disgaea PC / Disgaea 2 PC save game decompression
- # De-XORs and decompresses save files from these games.
- # Leaves headers intact, so actual save data starts at offset 0x44.
- #
- # Saves decompressed with this script can be repacked as well with
- # pseudo-compression to allow loading modified save files.
- #
- # Written by HenryEx
- # version 2
- #
- # script for QuickBMS http://quickbms.aluigi.org
- ################################################
- # set up virtual memory file for save data
- print "Preparing..."
- get FILENAME filename 0
- get FILESIZE asize 0
- if FILESIZE < 0x44
- print "[!] Error: File too small! Exiting..."
- CleanExit
- endif
- log MEMORY_FILE 0 0 # MEMORY_FILE is the working copy for de-/encryption
- log MEMORY_FILE2 0 0 # MEMORY_FILE2 will be the target for de-/recompression
- putvarchr MEMORY_FILE 0x100000 0
- putvarchr MEMORY_FILE2 0x100000 0
- log MEMORY_FILE 0 0 # reset MF1
- log MEMORY_FILE2 0 0 # reset MF2
- getDString HEADSTART 0x20
- get XORKEY long
- get XORUNK1 short
- get XORUNK2 short
- get XORCHUNKS long # num of XOR'd integers in file
- get FSIZE_COMP_A long # savedata size with YKCMP header minus padding (for XOR ints)
- SavePos FSTART 0
- getDString MAGIC 8 0 # check for YKCMP_V1 string if already de-crypted / -compressed
- if MAGIC = "YKCMP_V1"
- ################################################
- # Pseudo re-compress save
- print "File seems to be a decompressed save, will attempt to pseudo re-compress and encrypt it."
- get ARCHIVE_VERSION long 0
- if ARCHIVE_VERSION != 4
- print "[!] Unexpected archive version: %ARCHIVE_VERSION%! Exiting..."
- CleanExit
- endif
- get FSIZE_COMP_B long 0 # comp. filesize without 0x30 decryption header, minus padding
- get FSIZE_TARGET long 0 # target filesize without all headers after decomp.
- SavePos FSTART 0
- # set up compression stuff and prepare MF2
- print "Setting up file in memory..."
- putct "YKCMP_V1" string -1 MEMORY_FILE2
- put ARCHIVE_VERSION long MEMORY_FILE2
- put FSIZE_COMP_B long MEMORY_FILE2 # place holder, needs to be updated after recompression
- math FSIZE_TARGET = FILESIZE
- math FSIZE_TARGET - 0x44
- put FSIZE_TARGET long MEMORY_FILE2
- set FBYTES long FSIZE_TARGET
- math POS = FSTART # starting position to read bytes from, should be 0x44
- # start pseudo compressing into MF2
- print "Pseudo re-compressing save data..."
- append # append mode ON
- for FBYTES = FBYTES != 0 # loop while num of bytes to process is not 0
- if FBYTES > 0x7F
- set READLEN byte 0x7F
- math FBYTES - 0x7F
- else
- set READLEN byte FBYTES
- math FBYTES = 0
- endif
- put READLEN byte MEMORY_FILE2 # put byte length to straight copy
- log MEMORY_FILE2 POS READLEN 0 # append [READLEN] bytes to MF2
- math POS + READLEN # increment read offset
- next
- append # append mode OFF
- get FSIZE_COMP_B asize MEMORY_FILE2
- math FSIZE_COMP_A = FSIZE_COMP_B
- putvarchr MEMORY_FILE2 0xC FSIZE_COMP_B long # update header value
- ################################################
- # Encrypt save file in MF1
- print "Setting up encryption..."
- xmath PAD "4 - ( FSIZE_COMP_A % 4 )" # num of bytes for padding
- if PAD > 0
- for i = 0 < PAD
- put 0 byte MEMORY_FILE2 # pad file with 0 for 32-bit alignment
- next i
- endif
- xmath FSIZE "FSIZE_COMP_A + PAD"
- xmath XORCHUNKS "FSIZE / 4"
- # print "Padding needed: %PAD%. Padded filesize is %FSIZE%. Xor chunks: %XORCHUNKS%."
- # Set up MF1
- putDString HEADSTART 0x20 MEMORY_FILE
- put XORKEY long MEMORY_FILE
- put XORUNK1 short MEMORY_FILE
- put XORUNK2 short MEMORY_FILE
- put XORCHUNKS long MEMORY_FILE
- put FSIZE_COMP_A long MEMORY_FILE
- SavePos FSTART MEMORY_FILE
- append # append mode ON
- log MEMORY_FILE 0 FSIZE MEMORY_FILE2 # put recomp. save after encryption header
- append # append mode OFF
- print "Encrypting File..."
- # XOR save file with key
- for i = 0 < XORCHUNKS
- xmath POS "(i * 4) + FSTART" # get current file position
- getvarchr DATA MEMORY_FILE POS long
- math DATA u^ XORKEY
- putvarchr MEMORY_FILE POS DATA long
- next i
- get ENDSIZE asize MEMORY_FILE
- ################################################
- # Save file to disk
- string FILENAME $ "save" # last occurrence + searched string
- print "Exporting re-compressed save to %FILENAME%"
- log FILENAME 0 ENDSIZE MEMORY_FILE
- CleanExit
- else
- ################################################
- # Decrypt save
- print "Decrypting File..."
- # XOR save file with key
- log MEMORY_FILE 0 FILESIZE 0
- for i = 0 < XORCHUNKS
- xmath POS "(i * 4) + FSTART" # get current file position
- getvarchr DATA MEMORY_FILE POS long
- math DATA u^ XORKEY
- putvarchr MEMORY_FILE POS DATA long
- next i
- goto FSTART MEMORY_FILE
- getDString MAGIC 8 MEMORY_FILE
- if MAGIC != "YKCMP_V1"
- print "[!] Unexpected magic string: %MAGIC%! Decryption might have failed. Exiting..."
- CleanExit
- endif
- ################################################
- # Decompress save
- print "Begin Decompression..."
- get ARCHIVE_VERSION long MEMORY_FILE
- if ARCHIVE_VERSION != 4
- print "[!] Unexpected archive version: %ARCHIVE_VERSION%! Exiting..."
- CleanExit
- endif
- get FSIZE_COMP_B long MEMORY_FILE # comp. filesize without 0x30 decryption header, minus padding
- get FSIZE_TARGET long MEMORY_FILE # target filesize without all headers after decomp.
- SavePos FSTART 0
- # set up decompression and prepare MF2
- print "Setting up file in memory..."
- putDString HEADSTART 0x20 MEMORY_FILE2
- put XORKEY long MEMORY_FILE2
- put XORUNK1 short MEMORY_FILE2
- put XORUNK2 short MEMORY_FILE2
- put XORCHUNKS long MEMORY_FILE2
- put FSIZE_COMP_A long MEMORY_FILE2
- putct "YKCMP_V1" string -1 MEMORY_FILE2
- put ARCHIVE_VERSION long MEMORY_FILE2
- put FSIZE_COMP_B long MEMORY_FILE2
- put FSIZE_TARGET long MEMORY_FILE2
- set FBYTES long FSIZE_COMP_B
- math FBYTES + 0x30 # num. of compressed bytes + XOR & YKCMP header
- math POS = FSTART # offset after the YKCMP_V1 header (save data start) for MF2
- # start decompressing into MF2
- print "Decompressing save data..."
- for i = 68 < FBYTES # i works as byte offset, start at offset 0x44
- goto i MEMORY_FILE
- get A_BYTE byte MEMORY_FILE
- if A_BYTE >= 0xE0 # read data like XX XY YY
- get B_BYTE byte MEMORY_FILE
- get C_BYTE byte MEMORY_FILE
- set READLEN long A_BYTE
- math READLEN & 0x1F # remove 0xE0 from X
- math READLEN < 4
- xmath READLEN "READLEN + (B_BYTE > 4)"
- math READLEN + 3
- set SEEKBACK long B_BYTE
- math SEEKBACK & 0x0F
- math SEEKBACK < 8
- math SEEKBACK + C_BYTE
- math SEEKBACK + 1
- # print "Offset %i|h4%: byte %A_BYTE|2h% is >= 0xE0! Next bytes %B_BYTE|2h% %C_BYTE|2h%. Look back by %SEEKBACK% and copy %READLEN% bytes to %POS|6h%!"
- math i + 2 # advance counter of processed bytes
- elif A_BYTE >= 0xC0 # read data like XX YY
- get B_BYTE byte MEMORY_FILE
- math READLEN = A_BYTE
- math READLEN & 0x3F # remove 0xC0 from X
- math READLEN + 2
- math SEEKBACK = B_BYTE
- math SEEKBACK + 1
- # print "Offset %i|h4%: byte %A_BYTE|2h% is >= 0xC0! Next byte %B_BYTE|2h%. Look back by %SEEKBACK% and copy %READLEN% bytes to %POS|6h%!"
- math i + 1 # advance counter of processed bytes
- elif A_BYTE >= 0x80 # read data like XY
- math READLEN = A_BYTE
- math READLEN > 4
- math READLEN & 3 # remove 0x80 from X
- math READLEN + 1
- math SEEKBACK = A_BYTE
- math SEEKBACK & 0x0F
- math SEEKBACK + 1
- # print "Offset %i|h4%: byte %A_BYTE|2h% is >= 0x80! Look back by %SEEKBACK% and copy %READLEN% bytes to %POS|6h%!"
- else # byte is < 0x80, straight copy next bytes MF1 -> MF2
- # print "Offset %i|h4%: byte %A_BYTE|2h% is < 0x80! Straight copy %A_BYTE% bytes to %POS|6h%!"
- for j = 0 < A_BYTE
- math i + 1
- getvarchr DATA MEMORY_FILE1 i byte
- put DATA byte MEMORY_FILE2
- next j
- endif
- if A_BYTE >= 0x80 # Copy bytes within MF2 via lookback
- math POS - SEEKBACK
- for j = 0 < READLEN
- getvarchr DATA MEMORY_FILE2 POS byte
- put DATA byte MEMORY_FILE2
- math POS + 1
- next j
- endif
- get POS asize MEMORY_FILE2
- next i
- # check if filesize matches?
- math ENDSIZE = POS
- math POS - 68
- if FSIZE_TARGET != POS
- print "WARNING! Target filesize doesn't match real filesize!"
- endif
- ################################################
- # Save file to disk
- string FILENAME P= "dec_%FILENAME%"
- print "Exporting decompressed save to %FILENAME%"
- log FILENAME 0 ENDSIZE MEMORY_FILE2
- CleanExit
- endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement