This commit is contained in:
Eljakim Herrewijnen 2024-08-17 20:35:52 +02:00
parent 8cb5f2e151
commit 2d0557c5c7
19 changed files with 206 additions and 31 deletions

View File

@ -11,15 +11,48 @@ TODO document normal samsung boot chain
Exploitation
============
After exploitation the goal is to fully boot the device.
After exploitation the goal is to fully boot the device. The following part describes the current boot chain
Current boot chain:
.. important::
.. figure:: images/boot_chain.drawio.svg
This is under development and will still change.
BL1
---
The first stage is downloading BL1, authenticating it and patching it after authentication.
This is done by overwriting the USB return address pointer and jumping back to the debugger.
In the debugger we can authenticate BL1, patch it and boot it. An overview of this process is shown below:
Booting an authenticated and patched BL1:
.. figure:: images/boot_chain_bl1.drawio.svg
:align: center
Boot chain
.. note::
git commit 8cb5f2e1 fully boots, you can use this commit to patch bl1 only.
Next up is BL31, which is loaded by BL1.
BL31
----
``BL31`` is the secure monitor. The monitor uses memory that is also being used by the debugger, so we will have to relocate it to keep code exeuction.
.. figure:: images/bl31_debugger_memory_example.png
:align: center
Example of BL31 using debugger memory.
BL31 also configures the VBAR_EL3 and MMU so the memory mapping will probably change after this stage.
It would be nice to patch BL31 before it is being executed. However the current exploit boot flow does not allow this because the ROM function downloads the next stage.
Notes
-----
As done by Frederic, the bootrom can be dumped using his provided scripts, and can the be split into different boots:
.. code-block:: bash
@ -256,6 +289,7 @@ bl1 interacts with several pheriperals, from the DTB these are:
clock-names = "gate_rtc";
};
Probably the only thing it does is set some clocks and prepare for BL31
BL31
----

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,16 @@
========
Emulator
========
What is interesting about the ROM is that it starts by checking MPIDR_EL1 register and doing a conditional branch to 0x20e0000.
.. code-block:: ghidra
undefined w0:1 <RETURN>
Reset XREF[1]: Entry Point(*)
00000000 bb 00 38 d5 mrs x27,mpidr_el1
00000004 7b 0f 78 92 and x27,x27,#0xf00
00000008 7f 03 00 f1 cmp x27,#0x0
0000000c 41 00 00 54 b.ne LAB_00000014
00000010 fc 7f 83 14 b LAB_020e0000

View File

@ -1,9 +0,0 @@
#Ghidra Lock File
#Thu Aug 15 13:43:49 CEST 2024
OS\ Name=Linux
OS\ Version=6.5.0-44-generic
Username=eljakim
Hostname=levith
<META>\ Supports\ File\ Channel\ Locking=Channel Lock
OS\ Architecture=amd64
Timestamp=8/15/24, 1\:43 PM

View File

View File

@ -4,7 +4,7 @@
<STATE NAME="EXCLUSIVE" TYPE="boolean" VALUE="false" />
<STATE NAME="CHECKOUT_VERSION" TYPE="int" VALUE="-1" />
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="Program" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="PARENT" TYPE="string" VALUE="/s7/dump" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="7f011889d240069673442230" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="LOCAL_CHECKOUT_VERSION" TYPE="int" VALUE="-1" />

View File

@ -1,9 +1,7 @@
VERSION=1
/
00000006:8890_bootrom.bin:7f0119bc3142241939494339
0000000a:8890_bootrom.bin.1:7f011a6853998629050259
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
00000008:8890_bootrom_old_bl1:7f011822f30596451841878
0000000a:8890_bootrom_bl31_loaded:7f011a6853998629050259
/dump
00000009:reloc_debugger.elf:7f0119bd531451643843511
/mib3
@ -13,5 +11,8 @@ VERSION=1
00000003:bl31.bin:7f011ab837995028720085
00000004:sboot.bin.3.bin:7f011872b8163836628792
00000005:sboot.bin.4.bin:7f011842b8231996037592
/s7/dump
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
00000008:8890_bootrom_old_bl1:7f011822f30596451841878
NEXT-ID:b
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -1,9 +1,7 @@
VERSION=1
/
00000006:8890_bootrom.bin:7f0119bc3142241939494339
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
0000000a:8890_bootrom_bl31_loaded:7f011a6853998629050259
00000008:8890_bootrom_old_bl1:7f011822f30596451841878
/dump
00000009:reloc_debugger.elf:7f0119bd531451643843511
/mib3
@ -13,5 +11,8 @@ VERSION=1
00000003:bl31.bin:7f011ab837995028720085
00000004:sboot.bin.3.bin:7f011872b8163836628792
00000005:sboot.bin.4.bin:7f011842b8231996037592
/s7/dump
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
00000008:8890_bootrom_old_bl1:7f011822f30596451841878
NEXT-ID:b
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -4,7 +4,8 @@ VERSION=1
00000004:udf_7f011842b8231996037592:7f01190f112184430945139
00000003:udf_7f011872b8163836628792:7f011a9478217161533597
00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045
00000006:udf_7f0119bd531451643843511:7f011a1c131523520933550
00000005:udf_7f011a0d5252765509589854:7f0118e15255467845445248
00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603
NEXT-ID:6
NEXT-ID:7
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -6,6 +6,7 @@ VERSION=1
00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045
00000006:udf_7f0119bd531451643843511:7f011a1c131523520933550
00000005:udf_7f011a0d5252765509589854:7f0118e15255467845445248
00000007:udf_7f011a6853998629050259:7f011a98934430536471611
00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603
NEXT-ID:7
NEXT-ID:8
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -1,2 +1,2 @@
IADD:00000006:/udf_7f0119bd531451643843511
IDSET:/udf_7f0119bd531451643843511:7f011a1c131523520933550
IADD:00000007:/udf_7f011a6853998629050259
IDSET:/udf_7f011a6853998629050259:7f011a98934430536471611

15
source/emulator/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Exynos Emultor",
"type": "debugpy",
"request": "launch",
"program": "emulator.py",
"console": "integratedTerminal"
}
]
}

View File

@ -0,0 +1,36 @@
from ghidra_assistant.utils.utils import *
from ghidra_assistant.utils.archs.arm64.arm64_emulator import ARM64UC_Emulator
from unicorn.arm64_const import *
from unicorn.unicorn_const import *
class ExynosEmulator(ARM64UC_Emulator):
def __init__(self, rom_path):
super().__init__()
self.rom_path = rom_path
self.setup()
def setup(self):
self.setup_memory()
self.setup_registers()
def setup_memory(self):
#ROM
self.uc.mem_map(0x0, 128 * KB, UC_PROT_READ | UC_PROT_EXEC)
self.uc.mem_write(0x0, open(self.rom_path, "rb").read())
pass
def setup_registers(self):
self.pc = 0x0
self.uc.reg_write(UC_ARM64_REG_PC, self.pc)
def run(self):
try:
self.uc.emu_start(self.pc, self.pc + 1)
pass
except Exception as e:
self.print_ctx(print)
pass
if __name__ == '__main__':
emulator = ExynosEmulator("../S7/rom.bin")
emulator.run()

View File

@ -385,6 +385,23 @@ class ExynosDevice():
assert self.usb_read(0x200) == b"GiAs", "Failed to relocate debugger"
self.cd.relocate_debugger(0x020c7000, 0x020c0000, 0x020c4000)
def relocate_debugger_2(self):
# Seems to be cleared upon cache clearing??
if os.getenv("USER") == "eljakim":
debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/reloc_debugger.bin", "rb").read()
else:
try:
debugger_reloc = open("../../dump/reloc_debugger.bin", "rb").read()
except Exception as e:
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
sys.exit(0)
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)
def dumb_interact(self, dump_imems=False):
'''
@ -612,15 +629,43 @@ class ExynosDevice():
# ==== BL31 ====
assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger"
self.cd.memwrite_region(0x020200dc, p32(hijacked_fun)) # To continue booting next stages
self.cd.restore_stack_and_jump(hijacked_fun)
self.cd.memwrite_region(self.cd.arch_dbg.state.X0, open("../S7/g930f_latest/g930f_sboot.bin.2.bin", "rb").read())
lr = self.cd.arch_dbg.state.LR
self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
self.cd.restore_stack_and_jump(hijacked_fun) # will jump back to debugger after downloading the next stage
time.sleep(2)
self.connect_device()
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.2.bin", "rb").read())
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.2.bin", "rb").read()[:0x10])
time.sleep(2)
self.usb_read(0x200) # GiAs
# lr = self.cd.arch_dbg.state.LR
self.cd.memwrite_region(0x020200dc, p32(hijacked_fun))
GADGET_RET0 = 0x00000d58
self.cd.memwrite_region(0x020200e4, p32(GADGET_RET0))
# ====== PATCHES TO BL31 here! ======
# TODO fix not checking signatures
# self.cd.memwrite_region(0x02031008, b"ELH")
# self.cd.memwrite_region(0x02024774, self.cd.arch_dbg.sc.mov_0_w0_ins + self.cd.arch_dbg.sc.ret_ins)
# self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
# self.cd.arch_dbg.state.X0 = 0x020347f0
# self.cd.arch_dbg.state.X1 = 0
# self.cd.restore_stack_and_jump(0x02030464)
self.cd.restore_stack_and_jump(lr)
time.sleep(2)
self.connect_device()
time.sleep(1)
# self.usb_read(0x200) # GiAs
# self.cd.restore_stack_and_jump(hijacked_fun)
# ==== Stage 3 BL2 ====
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.3.bin", "rb").read())
@ -629,9 +674,17 @@ class ExynosDevice():
# ==== Stage 4 ====
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.4.bin", "rb").read())
stage4 = open("../S7/g930f_latest/g930f_sboot.bin.4.bin", "rb").read()
# Patching
# stage4_len = len(stage4)
# patch_len = len(b"USB RECOVERY MODE")
# patch = b"ELHER HERE" + (b"\x00" * (patch_len - len(b"ELHER HERE")))
# patch_offset = stage4.find(b"USB RECOVERY MODE")
# stage4 = stage4[:patch_offset] + patch + stage4[patch_len + patch_offset:]
# assert len(stage4) == stage4_len, "Invalid stage4 length"
self.send_normal_stage(stage4)
time.sleep(2)
self.connect_device()
pass

View File

@ -25,8 +25,8 @@ int mystrlen(char *data) {
#define recv_buffer 0x020c6200
#define data_received 0x020c6000
#else
#define recv_buffer 0x206fe00 //0x02021800 + 0x3000
#define data_received 0x206fd00
#define recv_buffer 0x206f000 //0x02021800 + 0x3000
#define data_received 0x206f100
#endif
void recv_data_cb(uint32_t endpoint, uint32_t len){

View File

@ -0,0 +1,14 @@
MEMORY {
ROM (rwx): ORIGIN = 0x020c0000, LENGTH = 0x1000
}
SECTIONS
{
. = 0x020c0000;
.text . : {
*(.text*)
*(.data*)
*(.rodata*)
} >ROM
}

View File

@ -0,0 +1,12 @@
debugger_storage = 0x020c4000;
debugger_stack = 0x020c2000;
debugger_entry = 0x020c0000;
maybe_usb_setup_read = 0x00006f88;
dwc3_ep0_start_trans = 0x0000791c;
usb_event_handler = 0x00007bac;
get_endpoint_recv_buffer = 0x00007a7c;
exynos_sleep = 0x000027c8;
g_recv_buffer = 0x020c6200;
g_data_received = 0x020c6000;