.. _boot-chain-label: ======= Booting ======= After exploitation the goal is to fully boot the device. Current boot chain: .. figure:: images/boot_chain.drawio.svg :align: center Boot chain As done by Frederic, the bootrom can be dumped using his provided scripts, and can the be split into different boots: .. code-block:: bash ./exynos-usbdl e payloads/Exynos8890_dump_bootrom.bin dumped_sboot.bin scripts/split-sboot-8890.sh dumped_sboot.bin This results in the following files: .. list-table:: bootrom stages :header-rows: 1 * - File - Strings output - Likely boot stage? * - sboot.bin.1.bin - Exynos BL1 - BL1 * - sboot.bin.2.bin - BL31 %s - BL31 * - sboot.bin.3.bin - Unsure. Contains strings like: TOP_DIV_ACLK_MFC_600 and APOLLO_DIV_APOLLO_RUN_MONITOR - BL2? * - sboot.bin.4.bin - Contains more textual information, and references to post BL2 boot, and android information - Kernel boot/BL33? debugger ======== After the initial loading of the debugger, the state reported is: .. code:: bash root | DEBUG | X0 : 0x0 | X1 : 0xffffffff | X2 : 0x20215d8 | X3 : 0x2021894 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 | X7 : 0x136c0008 | X8 : 0x2069000 | X9 : 0x0 | X10 : 0x2070000 | X11 : 0x0 | X12 : 0x0 | X13 : 0x0 | X14 : 0xf | X15 : 0x206d000 | X16 : 0x9 | X17 : 0x0 | X18 : 0x1 | X19 : 0x2000 | X20 : 0x2069000 | X21 : 0x0 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 | X28 : 0x0 | X29 : 0x2020f00 | LR/X30 : 0x20219b8 | SP/X31 : 0x2020ef0 With the original bl1 .. code:: bash root | DEBUG | X0 : 0x0 | X1 : 0x1 | X2 : 0x20215d8 | X3 : 0x2021894 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 | X7 : 0x136c0008 | X8 : 0x2069000 | X9 : 0x0 | X10 : 0x2070000 | X11 : 0x0 | X12 : 0x0 | X13 : 0x0 | X14 : 0xf | X15 : 0x20c4000 | X16 : 0x9 | X17 : 0x0 | X18 : 0x1 | X19 : 0x2000 | X20 : 0x2069000 | X21 : 0x0 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 | X28 : 0x0 | X29 : 0x2020f00 | LR/X30 : 0x20c0000 | SP/X31 : 0x2020ef0 With a modified bl1 .. code:: bash root | DEBUG | X0 : 0x0 | X1 : 0x1 | X2 : 0x20215d8 | X3 : 0x2021894 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 | X7 : 0x136c0008 | X8 : 0x2069000 | X9 : 0x0 | X10 : 0x2070000 | X11 : 0x0 | X12 : 0x0 | X13 : 0x0 | X14 : 0xf | X15 : 0x20c4000 | X16 : 0x9 | X17 : 0x0 | X18 : 0x1 | X19 : 0x2000 | X20 : 0x2069000 | X21 : 0x0 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 | X28 : 0x0 | X29 : 0x2020f00 | LR/X30 : 0x20c0000 | SP/X31 : 0x2020ef0 I relocated the debugger to ``0x20c0000`` to prevent overwriting it. .. code-block:: python self.cd.arch_dbg.state.auto_sync = False self.cd.arch_dbg.state.auto_sync_special = False self.cd.arch_dbg.state.print_ctx() def relocate_debugger(): # Seems to be cleared upon cache clearing?? debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/reloc_debugger.bin", "rb").read() self.cd.memwrite_region(0x020c0000, debugger_reloc) self.usb_write(b"FLSH") # Flush cache self.cd.restore_stack_and_jump(0x020c0000) assert self.usb_read(0x200) == b"GiAs", "Failed to relocate debugger" self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000) relocate_debugger() bl1 === BL1 needs to be authenticated. Loads at address ``0x02024000`` and contains some form of header (ramdump). There seems to be a samsung header format, where the first 4 bytes define the entry point of the binary. In this case this entry is ``+0x10`` so we jump to ``0x02024010``. .. code-block:: python # Try loading bl1 bl1 = open("../S7/bl1.bin", "rb").read() self.cd.memwrite_region(0x02021800, bl1) # self.usb_write(b"FLSH") AUTH_BL1 = 0x00012848 def auth_bl1(lr=0x2069000): # Load the firmware self.cd.arch_dbg.state.W0 = 1 self.cd.arch_dbg.state.X1 = 1 self.cd.arch_dbg.state.LR = lr #jump back to debugger when finished self.cd.restore_stack_and_jump(AUTH_BL1) assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger" assert self.cd.arch_dbg.state.X0 == 0, "auth_bl1 returned with error!" auth_bl1(0x020c0000) After authentication the bootROM jumps to it, we can execute this function with the debugger. .. code-block:: python self.cd.memwrite_region(0x02020f60, p32(0x020c0000)) BOOT_BL1 = 0x00019310 def jump_bl1(lr): self.cd.arch_dbg.state.LR = lr self.cd.restore_stack_and_jump(BOOT_BL1) jump_bl1(0x020c0000) jump_fwbl1() BL1 is laoded at the download buffer and self copies to ``0x02024000`` and resumes execution there(``0x02024010``). However, this does not result in a jump back to the debugger. But the ROM still receives data from the host TODO TODO TODO The reason for this is the following code in bl1: .. code-block:: c iVar3 = FUN_02024320(); if (iVar3 == 1) { (*(code *)(ulong)uRam0000000002020108)(0,1); } This code uses a predefined ROM function(I was looking for it) and jumps back to that function when it's done. This function is at address ``0x020200e8``, looking in our IMEM dump we can see where in the ROM this points to: .. code-block:: c DAT_02020108 XREF[2]: FUN_00001708:000018b4(W), FUN_02021970:02021a40(R) 02020108 90 57 00 00 undefined4 00005790h Replacing this function with our debugger makes us jump back: .. code-block:: python # Overwrite jump back self.cd.memwrite_region(0x02020108, p32(0x2069000)) self.cd.memwrite_region(0x020200e8, p32(0x2069000)) def jump_bl1(): self.cd.arch_dbg.state.LR = 0x2069000 self.cd.restore_stack_and_jump(0x02024010) # self.cd.restore_stack_and_jump(0x02021810) bl1 = open("../S7/bl1.bin", "rb").read() self.cd.memwrite_region(0x02024000, bl1) self.usb_write(b"FLSH") # auth_bl1() jump_bl1() assert self.usb_read(0x200) == b"GiAs", "not jumped back to debugger?" self.cd.arch_dbg.state.print_ctx() root | DEBUG | X0 : 0xc00000 | X1 : 0x2069000 | X2 : 0x0 | X3 : 0x2023114 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 | X7 : 0x136c0008 | X8 : 0x2069000 | X9 : 0x0 | X10 : 0x2070000 | X11 : 0x0 | X12 : 0x0 | X13 : 0x0 | X14 : 0xf | X15 : 0x206d000 | X16 : 0x9 | X17 : 0x0 | X18 : 0x1 | X19 : 0x20200e8 | X20 : 0x0 | X21 : 0x80000000 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 | X28 : 0x0 | X29 : 0x2020ed8 | LR/X30 : 0x202419c | SP/X31 : 0x2020ec0 However this does not fully run bl1, so we will have to dig a bit deeper to see the puropose and when to jump back to the debugger. Authentication of BL1 seems to be done at ``0x0012848``. With return value '0' expected when this function is executed, to execute other functions. .. figure:: images/bl1_auth_references.png :align: center BL1 authentication. purpose ------- bl1 interacts with several pheriperals, from the DTB these are: .. code-block:: dtsi /* FSYS0 */ pinctrl_5: pinctrl@10E60000 { compatible = "samsung,exynos8890-pinctrl"; reg = <0x0 0x10E60000 0x1000>; interrupts = <0 212 0>; }; /* FSYS1 */ pinctrl_6: pinctrl@15690000 { compatible = "samsung,exynos8890-pinctrl"; reg = <0x0 0x15690000 0x1000>; interrupts = <0 202 0>; }; /* PERIC1 */ pinctrl_9: pinctrl@14CC0000 { compatible = "samsung,exynos8890-pinctrl"; reg = <0x0 0x14CC0000 0x1000>; interrupts = <0 460 0>; }; pmu_system_controller: system-controller@105C0000 { compatible = "samsung,exynos8890-pmu", "syscon"; reg = <0x0 0x105C0000 0x10000>; }; rtc@10070000 { compatible = "samsung,s3c6410-rtc"; reg = <0x0 0x10070000 0x100>; interrupts = <0 73 0>, <0 74 0>; clocks = <&clock 157>; clock-names = "gate_rtc"; }; BL31 ---- Setups EL3 stuff, probably in preperation of loading trustzone