Boots BL1 correctly by setting some things (twin)
This commit is contained in:
parent
4bbb11908f
commit
7a80b9f5a9
@ -40,11 +40,15 @@ This results in the following files:
|
|||||||
- Contains more textual information, and references to post BL2 boot, and android information
|
- Contains more textual information, and references to post BL2 boot, and android information
|
||||||
- Kernel boot/BL33?
|
- Kernel boot/BL33?
|
||||||
|
|
||||||
|
After loading the stage1 (entry.S - Frederic's exploit), we're allowed to send custom payloads to the device. The first payload that is then sent, is the debugger.
|
||||||
|
|
||||||
debugger
|
debugger
|
||||||
========
|
========
|
||||||
After the initial loading of the debugger, the state reported is:
|
The initial debugger is written to ``0x2069000``, with debugger_stack and _storage at ``0x0206b000`` and ``0x0206d000`` respectively.
|
||||||
|
|
||||||
.. code:: bash
|
After the initial loading of the debugger, the processor state reported is (using ghidra assistant):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
root | DEBUG |
|
root | DEBUG |
|
||||||
X0 : 0x0 | X1 : 0xffffffff | X2 : 0x20215d8 | X3 : 0x2021894 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 |
|
X0 : 0x0 | X1 : 0xffffffff | X2 : 0x20215d8 | X3 : 0x2021894 | X4 : 0x4 | X5 : 0x0 | X6 : 0x0 |
|
||||||
@ -53,31 +57,9 @@ After the initial loading of the debugger, the state reported is:
|
|||||||
X21 : 0x0 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 |
|
X21 : 0x0 | X22 : 0x0 | X23 : 0x0 | X24 : 0x0 | X25 : 0x0 | X26 : 0x0 | X27 : 0x1 |
|
||||||
X28 : 0x0 | X29 : 0x2020f00 | LR/X30 : 0x20219b8 | SP/X31 : 0x2020ef0
|
X28 : 0x0 | X29 : 0x2020f00 | LR/X30 : 0x20219b8 | SP/X31 : 0x2020ef0
|
||||||
|
|
||||||
With the original bl1
|
LR/X30 being the line register. This is the address the processor will jump to when the function is done (important to keep track off).
|
||||||
|
|
||||||
.. code:: bash
|
After a cache flush, the debugger seems to be cleared as well, so the debugger is relocated to ``0x20c0000``, with _stack and _storage now at ``0x20c2000`` and ``0x20c4000`` respectively. This is done by running:
|
||||||
|
|
||||||
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
|
.. code-block:: python
|
||||||
|
|
||||||
@ -95,15 +77,20 @@ I relocated the debugger to ``0x20c0000`` to prevent overwriting it.
|
|||||||
self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000)
|
self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000)
|
||||||
relocate_debugger()
|
relocate_debugger()
|
||||||
|
|
||||||
|
The processor state reported then is:
|
||||||
|
|
||||||
|
.. code-block:: 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
|
||||||
|
|
||||||
bl1
|
bl1
|
||||||
===
|
===
|
||||||
BL1 needs to be authenticated.
|
BL1 needs to be authenticated. BL1 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``. Authentication seems to be done at ``0x00012848``. Initially we thought that 0x0 indicated a verified boot state (as is plausible when reading the decompiled code in Ghidra). But after modifying BL1 in the header and contents, this value did not change.
|
||||||
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
|
.. code-block:: python
|
||||||
|
|
||||||
@ -123,7 +110,21 @@ In this case this entry is ``+0x10`` so we jump to ``0x02024010``.
|
|||||||
|
|
||||||
auth_bl1(0x020c0000)
|
auth_bl1(0x020c0000)
|
||||||
|
|
||||||
After authentication the bootROM jumps to it, we can execute this function with the debugger.
|
.. figure:: images/bl1_auth_references.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
BL1 authentication
|
||||||
|
|
||||||
|
At this point, we assumed that the authentication was succesful, and the bootROM would jump back to the debugger after loading, but this was not the case. After running this function, we were able to send a single packet, but never received a response. Indicating that the function we were executing never returned on us.
|
||||||
|
|
||||||
|
If authentication at auth_bl1 is succesful, the returns a value from a function at ``1230c``. This function does some things, but eventually jumps to a function at:
|
||||||
|
|
||||||
|
.. figure:: images/bl1_auth_follow-up_1230c.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
BL1 authentication
|
||||||
|
|
||||||
|
After authentication the bootROM jumps to this function at, we can execute this function with the debugger.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -137,10 +138,12 @@ After authentication the bootROM jumps to it, we can execute this function with
|
|||||||
|
|
||||||
jump_fwbl1()
|
jump_fwbl1()
|
||||||
|
|
||||||
BL1 is laoded at the download buffer and self copies to ``0x02024000`` and resumes execution there(``0x02024010``).
|
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
|
However, this does not result in a jump back to the debugger. But the ROM still receives data from the host
|
||||||
|
|
||||||
|
! one payload allowed to be sent by the bootrom.
|
||||||
|
|
||||||
TODO TODO TODO
|
TODO TODO TODO
|
||||||
The reason for this is the following code in bl1:
|
The reason for this is the following code in bl1:
|
||||||
|
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
documentation/source/BootROM_8890/images/bl1_auth_references.png
Normal file
BIN
documentation/source/BootROM_8890/images/bl1_auth_references.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
@ -28,27 +28,6 @@ Frederic has also written a payload to extract the sboot.bin file from a connect
|
|||||||
|
|
||||||
$ strings -n4 sboot.bin.1.bin
|
$ strings -n4 sboot.bin.1.bin
|
||||||
|
|
||||||
was
|
|
||||||
|
|
||||||
.. 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?
|
|
||||||
|
|
||||||
Memory Layout
|
Memory Layout
|
||||||
-------------
|
-------------
|
||||||
TODO make memory layout of ROM, IMEM and some devices @JONHE
|
TODO make memory layout of ROM, IMEM and some devices @JONHE
|
||||||
|
@ -313,30 +313,36 @@ class ExynosDevice():
|
|||||||
_initial_run_debugger()
|
_initial_run_debugger()
|
||||||
_setup_debugger()
|
_setup_debugger()
|
||||||
|
|
||||||
def dumb_interact(self):
|
def dumb_interact(self, dump_imems=False):
|
||||||
'''
|
'''
|
||||||
Room for playing around with the debugger
|
Room for playing around with the debugger
|
||||||
'''
|
'''
|
||||||
self.cd.arch_dbg.state.auto_sync = False
|
self.cd.arch_dbg.state.auto_sync = False
|
||||||
self.cd.arch_dbg.state.auto_sync_special = False
|
self.cd.arch_dbg.state.auto_sync_special = False
|
||||||
|
logger.debug('State after setting up initial debugger')
|
||||||
self.cd.arch_dbg.state.print_ctx()
|
self.cd.arch_dbg.state.print_ctx()
|
||||||
|
|
||||||
def relocate_debugger():
|
def relocate_debugger():
|
||||||
# Seems to be cleared upon cache clearing??
|
# Seems to be cleared upon cache clearing??
|
||||||
if os.getenv("USER") == "eljakim":
|
if os.getenv("USER") == "eljakim":
|
||||||
debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/debugger.bin", "rb").read()
|
debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/reloc_debugger.bin", "rb").read()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
debugger_reloc = open("../../dump/debugger.bin", "rb").read()
|
debugger_reloc = open("../../dump/reloc_debugger.bin", "rb").read()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
|
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
self.cd.memwrite_region(0x020c0000, debugger_reloc)
|
self.cd.memwrite_region(0x020c0000, debugger_reloc)
|
||||||
self.usb_write(b"FLSH") # Flush cache
|
self.usb_write(b"FLSH") # Flush cache
|
||||||
self.cd.restore_stack_and_jump(0x020c0000)
|
self.cd.restore_stack_and_jump(0x020c0000)
|
||||||
assert self.usb_read(0x200) == b"GiAs", "Failed to relocate debugger"
|
assert self.usb_read(0x200) == b"GiAs", "Failed to relocate debugger"
|
||||||
self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000)
|
self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000)
|
||||||
|
|
||||||
relocate_debugger()
|
relocate_debugger()
|
||||||
|
|
||||||
|
logger.debug('State after relocating debugger')
|
||||||
|
self.cd.arch_dbg.state.print_ctx()
|
||||||
|
|
||||||
def memdump_imem():
|
def memdump_imem():
|
||||||
dumped = b""
|
dumped = b""
|
||||||
@ -349,8 +355,13 @@ class ExynosDevice():
|
|||||||
|
|
||||||
# Try loading bl1
|
# Try loading bl1
|
||||||
bl1 = open("../S7/bl1.bin", "rb").read()
|
bl1 = open("../S7/bl1.bin", "rb").read()
|
||||||
self.cd.memwrite_region(0x02021800, bl1)
|
|
||||||
# self.usb_write(b"FLSH")
|
# If wanting to modify the binary
|
||||||
|
# bl1 = bl1[:0x1C23] + b'\xaa' + bl1[0x1C24:]
|
||||||
|
|
||||||
|
self.cd.memwrite_region(0x02021800, bl1)
|
||||||
|
|
||||||
|
imem1 = memdump_imem()
|
||||||
AUTH_BL1 = 0x00012848
|
AUTH_BL1 = 0x00012848
|
||||||
def auth_bl1(lr=0x2069000):
|
def auth_bl1(lr=0x2069000):
|
||||||
# Load the firmware
|
# Load the firmware
|
||||||
@ -362,18 +373,39 @@ class ExynosDevice():
|
|||||||
assert self.cd.arch_dbg.state.X0 == 0, "auth_bl1 returned with error!"
|
assert self.cd.arch_dbg.state.X0 == 0, "auth_bl1 returned with error!"
|
||||||
|
|
||||||
auth_bl1(0x020c0000)
|
auth_bl1(0x020c0000)
|
||||||
# dump2 = memdump_imem()
|
|
||||||
|
# Dump memory
|
||||||
|
# imem2 = memdump_imem()
|
||||||
|
# with open("/tmp/imem1_bad.bin", "wb") as f:
|
||||||
|
# f.write(imem1)
|
||||||
|
# with open("/tmp/imem2_bad.bin", "wb") as f:
|
||||||
|
# f.write(imem2)
|
||||||
|
|
||||||
# Works until here TODO hijack future control flow
|
# Works until here TODO hijack future control flow
|
||||||
# self.cd.memwrite_region(0x02020108, p32(0x020c0000)) # Hijack some weird function, original 0x00005790
|
# self.cd.memwrite_region(0x02020108, p32(0x020c0000)) # Hijack some weird function, original 0x00005790
|
||||||
self.cd.memwrite_region(0x02020f60, p32(0x020c0000))
|
self.cd.memwrite_region(0x020200e8, p32(0x020c0000)) # Overwrite line register to jump back to debugger, at function
|
||||||
|
self.cd.memwrite_region(0x020200dc, p32(0x020c0000))
|
||||||
|
|
||||||
|
def hijack_brom_weird():
|
||||||
|
print(f"LR = {hex(self.cd.arch_dbg.state.LR - 4)} X0 = {hex(self.cd.arch_dbg.state.X0)}")
|
||||||
|
self.cd.restore_stack_and_jump(0x00000314)
|
||||||
|
|
||||||
BOOT_BL1 = 0x00019310
|
BOOT_BL1 = 0x00019310
|
||||||
def jump_bl1(lr):
|
def jump_bl1(lr):
|
||||||
self.cd.arch_dbg.state.LR = lr
|
self.cd.arch_dbg.state.LR = lr
|
||||||
self.cd.restore_stack_and_jump(BOOT_BL1)
|
self.cd.restore_stack_and_jump(BOOT_BL1)
|
||||||
|
|
||||||
jump_bl1(0x020c0000)
|
jump_bl1(0x020c0000)
|
||||||
pass
|
while True:
|
||||||
|
try:
|
||||||
|
resp = self.usb_read(0x200)
|
||||||
|
if self.cd.arch_dbg.state.LR == 0x02022948:
|
||||||
|
break # ROM will load next stage over USB
|
||||||
|
hijack_brom_weird()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# TODO load bl31
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -432,8 +464,8 @@ class ExynosDevice():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
arg = argparse.ArgumentParser("Exynos exploit")
|
arg = argparse.ArgumentParser("Exynos exploit")
|
||||||
arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False)
|
arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False)
|
||||||
args = arg.parse_args()
|
|
||||||
|
|
||||||
|
args = arg.parse_args()
|
||||||
exynos = ExynosDevice()
|
exynos = ExynosDevice()
|
||||||
|
|
||||||
if args.debug:
|
if args.debug:
|
||||||
|
Loading…
Reference in New Issue
Block a user