Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 98 additions & 5 deletions decrypt_rootfs.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from miasm.core.locationdb import LocationDB
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine
Expand Down Expand Up @@ -32,9 +33,9 @@ class crypto_ctx(ctypes.Structure):
_fields_ = [
("padding", ctypes.c_uint8 * 174),
("null", ctypes.c_uint8),
("rootfs_hash", ctypes.c_uint8 * 32),
("u", crypto_ctx_ctr_u),
("aes_key", ctypes.c_uint8 * 32),
("rootfs_hash", ctypes.c_uint8 * 32),
]


Expand All @@ -45,6 +46,46 @@ def print_logo():
print("https://randorisec.fr\n\n\n".center(max_width))


def resolve_register(expr):
if expr.is_id():
return expr.name

if expr.is_slice() and expr.arg.is_id():
base = expr.arg.name.upper()
start = expr.start
stop = expr.stop
size = stop - start

reg_aliases = {
# format: (base, start, size): alias
("RAX", 0, 8): "AL",
("RAX", 0, 16): "AX",
("RAX", 0, 32): "EAX",
("RAX", 0, 64): "RAX",

("RBX", 0, 8): "BL",
("RBX", 0, 16): "BX",
("RBX", 0, 32): "EBX",
("RBX", 0, 64): "RBX",

("RDX", 0, 8): "DL",
("RDX", 0, 16): "DX",
("RDX", 0, 32): "EDX",
("RDX", 0, 64): "RDX",

("RCX", 0, 8): "CL",
("RCX", 0, 16): "CX",
("RCX", 0, 32): "ECX",
("RCX", 0, 64): "RCX",

# Extend as needed
}

return reg_aliases.get((base, start, size), f"{base}[{start}:{stop}]")

return None


def locate_fgt_verify_initrd(file_flatkc):
output = subprocess.check_output(
f"""
Expand Down Expand Up @@ -96,6 +137,47 @@ def derivate_chacha20_params(seed):
return key, iv


def extract_chacha20_params(reg1, reg2):
machine = Machine(container.arch)
mdis = machine.dis_engine(container.bin_stream, loc_db=loc_db)
asmcfg = mdis.dis_multiblock(fgt_verify_initrd_addr)
all_srcs = []
for block in asmcfg.blocks:
if "sha256_update" not in block.to_string():
continue

reg1_val, reg2_val = 0, 0
for instr in block.lines:
if instr.name == "MOV":
dst, src = instr.get_args_expr()

if (resolve_register(dst) == reg1) and src.is_int():
reg1_val = src.arg

if (resolve_register(dst) == reg2) and src.is_int():
reg2_val = src.arg

all_srcs.append((reg1_val, reg2_val))
if (len(all_srcs)) == 4:
break

if (len(all_srcs)) != 4:
# Failed to find all components
return None, None

sha = sha256()
sha.update(container.executable.get_virt().get(all_srcs[0][0], all_srcs[0][0] + all_srcs[0][1]))
sha.update(container.executable.get_virt().get(all_srcs[1][0], all_srcs[1][0] + all_srcs[1][1]))
key = sha.digest()

sha = sha256()
sha.update(container.executable.get_virt().get(all_srcs[2][0], all_srcs[2][0] + all_srcs[2][1]))
sha.update(container.executable.get_virt().get(all_srcs[3][0], all_srcs[3][0] + all_srcs[3][1]))
iv = sha.digest()[:16]

return key, iv


def decrypt_rsapubkey(rsapubkey_data, key, iv):
chacha = ChaCha20.new(key=key, nonce=iv[4:])
counter = int.from_bytes(iv[:4], "little")
Expand All @@ -113,6 +195,9 @@ def decrypt_rootfs_sig(rootfs_sig, decoded_key):

num_bytes = (res.bit_length() + 7) // 8
assert num_bytes == 255, "signature broken"

logging.debug(f"sig: {binascii.hexlify(res.to_bytes(num_bytes, "big")).upper()}")

sig_struct = crypto_ctx()
ctypes.memmove(ctypes.byref(sig_struct), res.to_bytes(num_bytes, "big"), num_bytes)
return sig_struct
Expand Down Expand Up @@ -178,17 +263,25 @@ def decrypt_rootfs(file_rootfs_dec, rootfs_enc):
fgt_verify_initrd_addr = locate_fgt_verify_initrd(options.flatkc)
loc_db = LocationDB()
container = Container.from_stream(open(options.flatkc, "rb"), loc_db)
seed_addr = get_seed()
seed_data = container.executable.get_virt().get(seed_addr, seed_addr + 32)
logging.debug(f"SEED: {binascii.hexlify(seed_data).upper()}")
# seed_addr = get_seed()
# seed_data = container.executable.get_virt().get(seed_addr, seed_addr + 32)
# logging.debug(f"SEED: {binascii.hexlify(seed_data).upper()}")

rsapubkey_addr = get_rsapubkey_addr()
rsapubkey_data = container.executable.get_virt().get(
rsapubkey_addr, rsapubkey_addr + 270
)
logging.debug(f"RSAPUBKEY: {binascii.hexlify(rsapubkey_data).upper()}")

key, iv = derivate_chacha20_params(seed_data)
# key, iv = derivate_chacha20_params(seed_data)
key, iv = extract_chacha20_params("RSI", "EDX")
if key == None or iv == None:
logging.error("Failed to extract key or iv")
sys.exit(1)

logging.debug(f"key: {binascii.hexlify(key).upper()}")
logging.debug(f"iv: {binascii.hexlify(iv).upper()}")

decoded_key, _ = decoder.decode(
decrypt_rsapubkey(rsapubkey_data, key, iv), asn1Spec=rfc3279.RSAPublicKey()
)
Expand Down