Skip to content

Instantly share code, notes, and snippets.

@WorldSEnder
Last active October 11, 2018 23:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WorldSEnder/c5051dff45d9f2d20da316d383f2c8ba to your computer and use it in GitHub Desktop.
Save WorldSEnder/c5051dff45d9f2d20da316d383f2c8ba to your computer and use it in GitHub Desktop.
Decrypts your Monster Hunter world save data
import sys, errno, io
import struct
import base64
import blowfish
key = base64.b64decode(b'eGllWmpvZSNQMjEzNC0zem1hZ2hncHFvZTB6OCQzYXplcQ==')
cipher = blowfish.Cipher(key, byte_order="little")
if sys.version_info[0] == 3:
stdin = sys.stdin.buffer
stdout = sys.stdout.buffer
else:
stdin = sys.stdin
stdout = sys.stdout
CHUNK_SIZE = 2048
def iter_chunks():
while True:
buf = stdin.read(CHUNK_SIZE)
if not buf: break
yield buf
def decrypt_chunks(chunk_iter):
for chunk in chunk_iter:
yield b"".join(cipher.decrypt_ecb(chunk))
# just a bit of pretty printing don't kill me for it
def wrap_in_bar(buffer_it):
# don't print any progress bar if we are not in a tty setting
if not sys.stderr.isatty():
return buffer_it
try:
from progress.bar import Bar
from progress.spinner import Spinner
except ImportError:
# or if progress is not available
return buffer_it
# try to detect the file size. This should be same (~9MiB) but who knows
# what you are doing with it :)
if stdin.seekable():
pos = stdin.tell()
end = stdin.seek(0, io.SEEK_END)
if end != pos:
repos = stdin.seek(0, io.SEEK_SET)
assert pos == repos, "couldn't seek back to the initial position in the stream"
bar = Bar("Processing", file=sys.stderr, max = (end - pos + CHUNK_SIZE - 1) // CHUNK_SIZE)
return bar.iter(buffer_it)
else:
return Spinner("Processing", file=sys.stderr).iter(buffer_it)
if __name__ == "__main__":
if stdin.isatty():
print("Usage: python3 {} < SAVEDATA1000 > SAVEDATA1000.extracted.bin".format(sys.argv[0]), file=sys.stderr)
exit(1)
buffer_it = wrap_in_bar(iter_chunks())
for buf in decrypt_chunks(buffer_it):
try:
stdout.write(buf)
except IOError as e:
if e.errno == errno.EPIPE:
break
# This suppresses a warning python would print if stdout is attached
# to a pipe instead of a file.
# see: https://stackoverflow.com/questions/26692284/
sys.stderr.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment