Skip to content

Instantly share code, notes, and snippets.

@friedkeenan
Last active July 27, 2019 15:13
Show Gist options
  • Save friedkeenan/5587cf85894ecc29717e325b24f185d2 to your computer and use it in GitHub Desktop.
Save friedkeenan/5587cf85894ecc29717e325b24f185d2 to your computer and use it in GitHub Desktop.
Decrypts NROs from Mercury that have the encrypted flag set
#!/usr/bin/env python3
# Reverse engineering sure is easy when you have source code to reference
import struct
import argparse
import sys
from Crypto.Cipher import AES
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument("input", help="The input encrypted NRO", type=Path)
parser.add_argument("-o", "--output", help="The output decrypted NRO", default=".", type=Path)
args = parser.parse_args()
if args.output == Path("."):
args.output = Path(args.input.stem + ".dec.nro")
with args.input.open("rb") as f:
enc_buf = f.read()
if not struct.unpack_from("<I", enc_buf, 0x1c)[0] & 1:
print("This NRO doesn't have the encrypted flag set!")
sys.exit(1)
key = enc_buf[0x40:0x50]
mod_offset = struct.unpack_from("<I", enc_buf, 4)[0]
nro_size = struct.unpack_from("<I", enc_buf, 0x18)[0]
decipher = AES.new(key, AES.MODE_ECB)
dec_buf = bytearray(enc_buf[:mod_offset] + decipher.decrypt(enc_buf[mod_offset:nro_size]) + enc_buf[nro_size:])
struct.pack_into("<I", dec_buf, 0x1c, 0)
with args.output.open("wb") as f:
f.write(dec_buf)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment