On Sat, May 7, 2022, 3:01 AM Undiscussed Horrific Abuse, One Victim of Many <gmkarl@gmail.com> wrote:
I'm not near this system and phone at this time, but that doesn't mean I can't keep learning about it.
Here's the deployment script for the bootrom phase from the amonet kamakiri source:
#!/usr/bin/env python3
import sys import time
from common import Device from logger import log from load_payload import load_payload from functions import *
import usb.core import usb.util
import ctypes
import traceback
import struct import os
def main(dev):
load_payload(dev)
This uses a hack to get the 0xf00dd00d payload running on the device, roughly by uploading the stages and jumping to their addresses. The first stage involves some register and usb twiddling, and is size-limited; it may be an exploit, unsure. if len(sys.argv) == 2 and sys.argv[1] == "fixgpt":
dev.emmc_switch(0) log("Flashing GPT") flash_binary(dev, "../bin/gpt-mantis.bin", 0, 34 * 0x200)
This likely replaces the partition table if requested. I don't see the gpt-mantis.bin file in the repository yet. That size of 0x34 x 0x200 ... I've seen that before I think?
# 1) Sanity check GPT log("Check GPT") switch_user(dev)
This switches the device to partition 0 and verifies two expected bytes in that partition.
# 1.1) Parse gpt gpt = parse_gpt(dev)
def parse_gpt(dev): data = dev.emmc_read(0x400 // 0x200) + dev.emmc_read(0x600 // 0x200) + dev.emmc_read(0x800 // 0x200) + dev.emmc_read(0xA00 // 0x200) num = len(data) // 0x80 parts = dict() for x in range(num): part = data[x * 0x80:(x + 1) * 0x80] part_name = part[0x38:].decode("utf-16le").rstrip("\x00") part_start = struct.unpack("<Q", part[0x20:0x28])[0] part_end = struct.unpack("<Q", part[0x28:0x30])[0] parts[part_name] = (part_start, part_end - part_start + 1) return parts I'm guessing that partition 0 is either the partition table or the entire flash, and that the above code manually parses a GPT partition table (into a python dict of offset size pairs). log("gpt_parsed = {}".format(gpt))
if "lk" not in gpt or "tee1" not in gpt or "boot" not in gpt or "recovery" not in gpt: raise RuntimeError("bad gpt")
# 2) Sanity check boot0 log("Check boot0") switch_boot0(dev)
This switches to partition 1 and verifies that it starts with either "EMMC_BOOT" or nul bytes.
# 3) Sanity check rpmb log("Check rpmb") rpmb = dev.rpmb_read() if rpmb[0:4] != b"AMZN": thread = UserInputThread(msg = "rpmb looks broken; if this is expected (i.e. you're retrying the exploit) press enter, otherwise terminate with Ctrl+C") thread.start() while not thread.done: dev.kick_watchdog() time.sleep(1)
I'm not sure what rpmb is, immediately.
# Clear preloader so, we get into bootrom without shorting, should the script stall (we flash preloader as last step) # 4) Downgrade preloader log("Clear preloader header") switch_boot0(dev) flash_data(dev, b"EMMC_BOOT" + b"\x00" * ((0x200 * 4) - 9), 0)
Places null bytes in partition 1.
# 5) Zero out rpmb to enable downgrade log("Downgrade rpmb") dev.rpmb_write(b"\x00" * 0x100)
Whatever the rpmb is, this zeros it. log("Recheck rpmb")
rpmb = dev.rpmb_read() if rpmb != b"\x00" * 0x100: dev.reboot() raise RuntimeError("downgrade failure, giving up") log("rpmb downgrade ok") dev.kick_watchdog()
# 6) Downgrade tz log("Flash tz") switch_user(dev) flash_binary(dev, "../bin/tz.img", gpt["tee1"][0], gpt["tee1"][1] * 0x200)
Okay, it sounds like partition 0 is not the partition table, but rather partition "tz" .... I don't yet understand why it seems to read as if the GPT table was parsed 0x400 bytes after the start of the tz partition. Could the GPT table be located at the end or inside of a partition? Ohhhh I see -- gpt["tee1"] stores the offset of the tee1 partition. The partitions are flashed relative to the start of the emmc.
# 7) Downgrade lk log("Flash lk") switch_user(dev) flash_binary(dev, "../bin/lk.bin", gpt["lk"][0], gpt["lk"][1] * 0x200)
So this code replaces two partitions with binary images. Maybe user-provided old ones, unsure. # 6) Install lk-payload
log("Flash lk-payload") switch_boot0(dev) flash_binary(dev, "../lk-payload/build/payload.bin", 1024)
And here's the next payload, contents not reviewed yet. It's interesting that this is flashed at offset 1024 rather than the offset of the actual lk partition. I think is bytes rather than 0x200 sectors, not sure. ...
# 8) Flash microloader log("Inject microloader") switch_user(dev) boot_hdr1 = dev.emmc_read(gpt["boot"][0]) + dev.emmc_read(gpt["boot"][0] + 1) boot_hdr2 = dev.emmc_read(gpt["boot"][0] + 2) + dev.emmc_read(gpt["boot"][0] + 3) flash_binary(dev, "../bin/microloader.bin", gpt["boot"][0], 2 * 0x200) if boot_hdr2[0:8] != b"ANDROID!": flash_data(dev, boot_hdr1, gpt["boot"][0] + 2, 2 * 0x200)
log("Force fastboot") force_fastboot(dev, gpt)
# 9) Install preloader log("Flash preloader") switch_boot0(dev) flash_binary(dev, "../bin/preloader.img", 0)
# 9.1) Wait some time so data is flushed to EMMC time.sleep(5)
# Reboot (to fastboot or recovery) log("Reboot") dev.reboot()
if __name__ == "__main__":
check_modemmanager()
dev = Device() dev.find_device()
main(dev)