diff --git a/CMakeLists.txt b/CMakeLists.txt index faf8138..326151a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.10) project(checkm8_tool) -enable_language(C) +enable_language(C ASM) + +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) include_directories(c8_remote/include) include_directories(include) diff --git a/c8_remote/include/bootrom_addr.h b/c8_remote/include/bootrom_addr.h index 678e6ce..9150529 100644 --- a/c8_remote/include/bootrom_addr.h +++ b/c8_remote/include/bootrom_addr.h @@ -36,6 +36,7 @@ /* Misc */ #define ADDR_RANDOM_RET 0x10000b924 +#define ADDR_SYNC_ENTRY 0x1800afc84 #define ADDR_DFU_RETVAL (int *) 0x180088ac8 #define ADDR_DFU_STATUS (unsigned char *) 0x180088ac0 diff --git a/c8_remote/include/checkm8.h b/c8_remote/include/checkm8.h index bce3103..7e69b24 100644 --- a/c8_remote/include/checkm8.h +++ b/c8_remote/include/checkm8.h @@ -36,7 +36,8 @@ struct pwned_device unsigned int idVendor; unsigned int idProduct; - struct payload *installed; + struct payload *inst_pl; + struct data *inst_data; #ifdef WITH_ARDUINO int ard_fd; @@ -47,6 +48,7 @@ struct pwned_device struct pwned_device *exploit_device(); int demote_device(struct pwned_device *dev); +int fix_heap(struct pwned_device *dev); void free_device(struct pwned_device *dev); #endif //CHECKM8_TOOL_CHECKM8_H diff --git a/c8_remote/include/payload.h b/c8_remote/include/payload.h index c07d74c..55fa8c8 100644 --- a/c8_remote/include/payload.h +++ b/c8_remote/include/payload.h @@ -23,12 +23,17 @@ typedef unsigned long long DEV_PTR_T; int install_payload(struct pwned_device *dev, PAYLOAD_T p, LOCATION_T loc); int uninstall_payload(struct pwned_device *dev, PAYLOAD_T p); -struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int response_len, int nargs, ...); -DEV_PTR_T execute_payload_async(struct pwned_device *dev, PAYLOAD_T p, int bufsize, int nargs, ...); +int uninstall_all_payloads(struct pwned_device *dev); DEV_PTR_T get_payload_address(struct pwned_device *dev, PAYLOAD_T p); +struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int response_len, int nargs, ...); +DEV_PTR_T setup_payload_async(struct pwned_device *dev, PAYLOAD_T p, int bufsize, int nargs, ...); +int run_payload_async(struct pwned_device *dev, PAYLOAD_T p); +int kill_payload_async(struct pwned_device *dev, PAYLOAD_T p, DEV_PTR_T buf_addr); + DEV_PTR_T install_data(struct pwned_device *dev, LOCATION_T loc, unsigned char *data, int len); int uninstall_data(struct pwned_device *dev, DEV_PTR_T ptr); +int uninstall_all_data(struct pwned_device *dev); struct dev_cmd_resp *read_gadget(struct pwned_device *dev, DEV_PTR_T addr, int len); struct dev_cmd_resp *write_gadget(struct pwned_device *dev, DEV_PTR_T addr, unsigned char *data, int len); diff --git a/c8_remote/lib/CMakeLists.txt b/c8_remote/lib/CMakeLists.txt index f6c3411..eb375aa 100644 --- a/c8_remote/lib/CMakeLists.txt +++ b/c8_remote/lib/CMakeLists.txt @@ -1,5 +1,3 @@ -project(checkm8_libpayload) - set(PL_NAMES aes_busy aes_sw diff --git a/c8_remote/lib/payload/CMakeLists.txt b/c8_remote/lib/payload/CMakeLists.txt index e3ca1d1..2d09bab 100644 --- a/c8_remote/lib/payload/CMakeLists.txt +++ b/c8_remote/lib/payload/CMakeLists.txt @@ -1,8 +1,6 @@ -project(checkm8_libpayload_sources C ASM) include_directories(${CMAKE_CURRENT_LIST_DIR}/include) - - set(CMAKE_SYSTEM_PROCESSOR arm) + if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") # regular desktop set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc) @@ -20,12 +18,14 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) foreach(NAME ${PL_NAMES}) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.S) - add_executable(payload_${NAME} ${CMAKE_CURRENT_LIST_DIR}/payload_entry.c - ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.c - ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.S) + add_executable(payload_${NAME} ${CMAKE_CURRENT_LIST_DIR}/payload_entry.S + ${CMAKE_CURRENT_LIST_DIR}/payload_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.S) else() - add_executable(payload_${NAME} ${CMAKE_CURRENT_LIST_DIR}/payload_entry.c - ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.c) + add_executable(payload_${NAME} ${CMAKE_CURRENT_LIST_DIR}/payload_entry.S + ${CMAKE_CURRENT_LIST_DIR}/payload_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/${NAME}.c) endif() add_custom_command(TARGET payload_${NAME} POST_BUILD diff --git a/c8_remote/lib/payload/payload_entry.S b/c8_remote/lib/payload/payload_entry.S new file mode 100644 index 0000000..8b56f58 --- /dev/null +++ b/c8_remote/lib/payload/payload_entry.S @@ -0,0 +1,17 @@ +.extern entry_sync +.extern entry_async +.extern load_sync_entry + +.global _start +.section .text +_start: + mov x10, x30 + bl load_sync_entry + mov x30, x10 + + # if we came from the synchronous entry point, branch to entry_sync + cmp x9, x10 + b.eq entry_sync + + # else branch to the payload's async entry points + b entry_async diff --git a/c8_remote/lib/payload/payload_entry.c b/c8_remote/lib/payload/payload_entry.c index 09d6e2d..cd9c2f1 100644 --- a/c8_remote/lib/payload/payload_entry.c +++ b/c8_remote/lib/payload/payload_entry.c @@ -1,28 +1,13 @@ #include "dev_util.h" +#include "bootrom_addr.h" -extern uint64_t entry_sync(uint64_t *args); -extern uint64_t entry_async(uint64_t *base); - -TEXT_SECTION -uint64_t _start(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, - uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) +PAYLOAD_SECTION +void load_sync_entry() { - uint64_t entry, args[8]; - __asm__ volatile ("mov %0, x30" : "=r" (entry)); + uint64_t addr = ADDR_SYNC_ENTRY; + __asm__ volatile("mov x9, %0" :: "i" (addr & 0xFFFFu)); + __asm__ volatile("movk x9, %0, LSL #16" :: "i" ((addr & 0xFFFF0000u) >> 16u)); + __asm__ volatile("movk x9, %0, LSL #32" :: "i" ((addr & 0xFFFF00000000u) >> 32u)); + __asm__ volatile("movk x9, %0, LSL #48" :: "i" ((addr & 0xFFFF000000000000u) >> 48u)); - if(entry == 0xbea /* todo: correct entry */) - { - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - args[3] = arg3; - args[4] = arg4; - args[5] = arg5; - args[6] = arg6; - args[7] = arg7; - - return entry_sync(args); - } - else - return entry_async((uint64_t *) arg0); } \ No newline at end of file diff --git a/c8_remote/lib/payload/src/aes_busy.c b/c8_remote/lib/payload/src/aes_busy.c index 2d63661..fc354d3 100644 --- a/c8_remote/lib/payload/src/aes_busy.c +++ b/c8_remote/lib/payload/src/aes_busy.c @@ -1,16 +1,11 @@ #include "bootrom_func.h" PAYLOAD_SECTION -uint64_t entry_sync(uint64_t *args) +void entry_sync(uint8_t *src, uint8_t *dst, uint8_t *key, int32_t rep) { int i, j; unsigned char src_data[16]; - unsigned char *src = (unsigned char *) args[0]; - unsigned char *dst = (unsigned char *) args[1]; - unsigned char *key = (unsigned char *) args[2]; - int rep = (int) args[3]; - for(j = 0; j < 16; j++) { src_data[j] = src[j]; @@ -21,12 +16,7 @@ uint64_t entry_sync(uint64_t *args) if(i % 2 == 0) hardware_aes(16, src_data, dst, 16, 0, key, 0); else hardware_aes(16, dst, src_data, 16, 0, key, 0); } - - return 0; } PAYLOAD_SECTION -uint64_t entry_async(uint64_t *base) -{ - return 0; -} \ No newline at end of file +void entry_async(uint64_t *base){} \ No newline at end of file diff --git a/c8_remote/lib/payload/src/aes_sw.c b/c8_remote/lib/payload/src/aes_sw.c index eda50e5..1636122 100644 --- a/c8_remote/lib/payload/src/aes_sw.c +++ b/c8_remote/lib/payload/src/aes_sw.c @@ -141,18 +141,12 @@ void aes128_encrypt_ecb(unsigned char *msg, unsigned int msg_len, unsigned char } PAYLOAD_SECTION -uint64_t entry_sync(uint64_t *args) +uint64_t entry_sync(unsigned char *msg, unsigned int msg_len, unsigned char key[16], + unsigned char sbox[16][16], unsigned char rc_lookup[11], + unsigned char mul2[256], unsigned char mul3[256]) { unsigned long long start = 0, end = 0; - unsigned char *msg = (unsigned char *) args[0]; - unsigned int msg_len = (unsigned int) args[1]; - unsigned char *key = (unsigned char *) args[2]; - unsigned char *sbox = (unsigned char *) args[3]; - unsigned char *rc_lookup = (unsigned char *) args[4]; - unsigned char *mul2 = (unsigned char *) args[5]; - unsigned char *mul3 = (unsigned char *) args[6]; - __asm__ volatile ("mrs %0, cntpct_el0" : "=r" (start)); aes128_encrypt_ecb(msg, msg_len, key, sbox, rc_lookup, mul2, mul3); __asm__ volatile ("mrs %0, cntpct_el0" : "=r" (end)); @@ -167,7 +161,7 @@ uint64_t entry_sync(uint64_t *args) } PAYLOAD_SECTION -uint64_t entry_async(uint64_t *base) +void entry_async(uint64_t *base) { unsigned long long start = 0, end = 0; diff --git a/c8_remote/lib/payload/src/exit_usb_task.c b/c8_remote/lib/payload/src/exit_usb_task.c index 59f19f3..fd45580 100644 --- a/c8_remote/lib/payload/src/exit_usb_task.c +++ b/c8_remote/lib/payload/src/exit_usb_task.c @@ -39,7 +39,7 @@ void fix_heap() check_all_chksums(); } -extern uint64_t entry_sync(uint64_t *args) +void entry_sync(unsigned long long *self) { fix_heap(); @@ -47,10 +47,7 @@ extern uint64_t entry_sync(uint64_t *args) *(ADDR_DFU_STATUS) = 1; event_notify(ADDR_DFU_EVENT); - return 0; + dev_free(self); } -extern uint64_t entry_async(uint64_t *base) -{ - return 0; -} \ No newline at end of file +void entry_async(uint64_t *base){} \ No newline at end of file diff --git a/c8_remote/lib/payload/src/floppysleep.c b/c8_remote/lib/payload/src/floppysleep.c index 2b19e9c..02f83fe 100644 --- a/c8_remote/lib/payload/src/floppysleep.c +++ b/c8_remote/lib/payload/src/floppysleep.c @@ -39,13 +39,13 @@ uint64_t floppysleep_iteration(float *init) } PAYLOAD_SECTION -uint64_t entry_sync(uint64_t *args) +uint64_t entry_sync(float *init_ptr) { - return floppysleep_iteration((float *) args[0]); + return floppysleep_iteration(init_ptr); } PAYLOAD_SECTION -uint64_t entry_async(uint64_t *args) +void entry_async(uint64_t *args) { float *init_ptr = (float *) args[0]; args[0] = 0; @@ -54,7 +54,7 @@ uint64_t entry_async(uint64_t *args) { floppysleep_iteration(init_ptr); + if(args[0] % 1000000 == 0) task_resched(); args[0]++; - if(args[0] % 100000 == 0) task_resched(); } } diff --git a/c8_remote/lib/payload/src/sync.c b/c8_remote/lib/payload/src/sync.c index 21c120e..d826ab7 100644 --- a/c8_remote/lib/payload/src/sync.c +++ b/c8_remote/lib/payload/src/sync.c @@ -1,18 +1,13 @@ #include "dev_util.h" PAYLOAD_SECTION -extern uint64_t entry_sync(uint64_t *args) +void entry_sync() { __asm__("dmb sy"); __asm__("ic iallu"); __asm__("dsb sy"); __asm__("isb"); - - return 0; } PAYLOAD_SECTION -extern uint64_t entry_async(uint64_t *base) -{ - return 0; -} \ No newline at end of file +void entry_async(){} \ No newline at end of file diff --git a/c8_remote/main.c b/c8_remote/main.c index 52997f4..335d004 100644 --- a/c8_remote/main.c +++ b/c8_remote/main.c @@ -44,62 +44,108 @@ void checkm8_debug_block(const char *format, ...) #endif } -int floppysleep(struct pwned_device *dev) +void floppysleep(struct pwned_device *dev) { struct dev_cmd_resp *resp; if(IS_CHECKM8_FAIL(open_device_session(dev))) { printf("failed to open device session\n"); - return -1; + return; } if(IS_CHECKM8_FAIL(install_payload(dev, PAYLOAD_SYNC, SRAM))) { printf("failed to install sync payload\n"); - return -1; + return; } if(IS_CHECKM8_FAIL(install_payload(dev, PAYLOAD_FLOPPYSLEEP, SRAM))) { printf("failed to install task sleep payload\n"); - return -1; + return; } float init_a = -7.504355E-39f; - unsigned long long init_a_ptr = install_data(dev, SRAM, (unsigned char *) &init_a, sizeof(float)); + DEV_PTR_T init_a_ptr = install_data(dev, SRAM, (unsigned char *) &init_a, sizeof(float)); if(init_a_ptr == DEV_PTR_NULL) { printf("failed to write initial data\n"); - return -1; + return; } resp = execute_payload(dev, PAYLOAD_SYNC, 0, 0); if(IS_CHECKM8_FAIL(resp->ret)) { printf("failed to execute bootstrap\n"); - return -1; + return; } free_dev_cmd_resp(resp); - while(1) + resp = execute_payload(dev, PAYLOAD_FLOPPYSLEEP, 0, 1, init_a_ptr); + if(IS_CHECKM8_FAIL(resp->ret)) { - resp = execute_payload(dev, PAYLOAD_FLOPPYSLEEP, 0, 1, init_a_ptr); - if(IS_CHECKM8_FAIL(resp->ret)) - { - printf("failed to execute flopsleep payload\n"); - return -1; - } - - printf("retval is %08lli\n", resp->retval); - free_dev_cmd_resp(resp); - - usleep(2000000); + printf("failed to execute flopsleep payload\n"); + return; } + printf("retval is %08lli\n", resp->retval); + free_dev_cmd_resp(resp); close_device_session(dev); - free_device(dev); +} + +void floppysleep_async(struct pwned_device *dev) +{ + float init_a = -7.504355E-39f; + DEV_PTR_T init_a_ptr, async_buf_ptr; + struct dev_cmd_resp *resp; + + if(IS_CHECKM8_FAIL(open_device_session(dev))) + { + printf("failed to open device session\n"); + return; + } + + if(IS_CHECKM8_FAIL(install_payload(dev, PAYLOAD_SYNC, SRAM))) + { + printf("failed to install sync payload\n"); + return; + } + + if(IS_CHECKM8_FAIL(install_payload(dev, PAYLOAD_FLOPPYSLEEP, SRAM))) + { + printf("failed to install task sleep payload\n"); + return; + } + + init_a_ptr = install_data(dev, SRAM, (unsigned char *) &init_a, sizeof(float)); + if(init_a_ptr == DEV_PTR_NULL) + { + printf("failed to write initial data\n"); + return; + } + + resp = execute_payload(dev, PAYLOAD_SYNC, 0, 0); + if(IS_CHECKM8_FAIL(resp->ret)) + { + printf("failed to execute bootstrap\n"); + return; + } + + free_dev_cmd_resp(resp); + + async_buf_ptr = setup_payload_async(dev, PAYLOAD_FLOPPYSLEEP, 32, 1, init_a_ptr); + run_payload_async(dev, PAYLOAD_FLOPPYSLEEP); + close_device_session(dev); + + printf("async buf pointer is %llX\n", async_buf_ptr); + +// sleep(10); +// +// open_device_session(dev); +// resp = read_gadget(dev, async_buf_ptr, 8); +// close_device_session(dev); } void aes_sw(struct pwned_device *dev) @@ -235,6 +281,13 @@ void aes_sw(struct pwned_device *dev) return; } + resp = execute_payload(dev, PAYLOAD_SYNC, 0, 0); + if(IS_CHECKM8_FAIL(resp->ret)) + { + printf("failed to execute sync payload\n"); + return; + } + for(i = 0; i < 100; i++) { resp = execute_payload(dev, PAYLOAD_AES_SW, 0, 7, @@ -339,12 +392,14 @@ int main() return -1; } + fix_heap(dev); demote_device(dev); + floppysleep_async(dev); - // usb_task_exit(dev); - - floppysleep(dev); - free_device(dev); +// open_device_session(dev); +// uninstall_all_payloads(dev); +// uninstall_all_data(dev); +// free_device(dev); } diff --git a/c8_remote/src/exploit.c b/c8_remote/src/exploit.c index 494c5d7..de3e195 100644 --- a/c8_remote/src/exploit.c +++ b/c8_remote/src/exploit.c @@ -7,6 +7,7 @@ #include "usb_helpers.h" #include "command.h" +#include "bootrom_addr.h" static unsigned char data_0xA_0xC0_buf[192] = { @@ -294,6 +295,13 @@ int demote_device(struct pwned_device *dev) { checkm8_debug_indent("demote_device(dev = %p)\n", dev); unsigned int oldval, newval; + int retval; + + if(IS_CHECKM8_FAIL(open_device_session(dev))) + { + checkm8_debug_indent("\tfailed to open a device session\n"); + return CHECKM8_FAIL_XFER; + } struct dev_cmd_resp *resp = dev_read_memory(dev, DEMOTE_REG, 4); if(IS_CHECKM8_FAIL(resp->ret)) @@ -305,46 +313,116 @@ int demote_device(struct pwned_device *dev) oldval = *((unsigned int *) resp->data); free_dev_cmd_resp(resp); - if(oldval & 1u) + if(!(oldval & 1u)) { - oldval &= 0xFFFFFFFE; + checkm8_debug_block("\tdevice already demoted\n"); + if(IS_CHECKM8_FAIL(close_device_session(dev))) + { + checkm8_debug_indent("\tfailed to close device session\n"); + return CHECKM8_FAIL_XFER; + } - checkm8_debug_indent("\tattempting to demote device\n"); - resp = dev_write_memory(dev, DEMOTE_REG, (unsigned char *) &oldval, 4); + return CHECKM8_SUCCESS; + } + + oldval &= 0xFFFFFFFE; + + checkm8_debug_indent("\tattempting to demote device\n"); + resp = dev_write_memory(dev, DEMOTE_REG, (unsigned char *) &oldval, 4); + if(IS_CHECKM8_FAIL(resp->ret)) + { + checkm8_debug_block("\tfailed to write to demotion reg\n"); free_dev_cmd_resp(resp); - if(IS_CHECKM8_FAIL(resp->ret)) + + if(IS_CHECKM8_FAIL(close_device_session(dev))) { - checkm8_debug_block("\tfailed to write to demotion reg\n"); - return CHECKM8_FAIL_INVARGS; + checkm8_debug_indent("\tfailed to close device session\n"); + return CHECKM8_FAIL_XFER; } - // verify - resp = dev_read_memory(dev, DEMOTE_REG, 4); - if(IS_CHECKM8_FAIL(resp->ret)) - { - free_dev_cmd_resp(resp); - checkm8_debug_block("\tfailed to verify demotion reg\n"); - return CHECKM8_FAIL_INVARGS; - } + return CHECKM8_FAIL_INVARGS; + } + free_dev_cmd_resp(resp); - newval = *((unsigned int *) resp->data); + // verify + resp = dev_read_memory(dev, DEMOTE_REG, 4); + if(IS_CHECKM8_FAIL(resp->ret)) + { free_dev_cmd_resp(resp); - if(oldval == newval) + checkm8_debug_block("\tfailed to verify demotion reg\n"); + + if(IS_CHECKM8_FAIL(close_device_session(dev))) { - checkm8_debug_block("\tdemotion success!\n"); - return CHECKM8_SUCCESS; - } - else - { - checkm8_debug_block("\tdemotion register did not change!\n"); - return CHECKM8_FAIL_INVARGS; + checkm8_debug_indent("\tfailed to close device session\n"); + return CHECKM8_FAIL_XFER; } + + return CHECKM8_FAIL_INVARGS; + } + + newval = *((unsigned int *) resp->data); + free_dev_cmd_resp(resp); + + if(oldval == newval) + { + checkm8_debug_block("\tdemotion success!\n"); + retval = CHECKM8_SUCCESS; } else { - checkm8_debug_block("\tdevice already demoted\n"); - return CHECKM8_SUCCESS; + checkm8_debug_block("\tdemotion register did not change!\n"); + retval = CHECKM8_FAIL_INVARGS; } + + if(IS_CHECKM8_FAIL(close_device_session(dev))) + { + checkm8_debug_indent("\tfailed to close device session\n"); + return CHECKM8_FAIL_XFER; + } + + return retval; +} + +int fix_heap(struct pwned_device *dev) +{ + checkm8_debug_indent("fix_heap(dev = %p)\n", dev); + int close; + + #if CHECKM8_PLATFORM == 8010 + unsigned long long block1_data[4] = {0x80 / 0x40, ((0x840u / 0x40) << 2u), 0x80, 0}; + unsigned long long block2_data[4] = {0x80 / 0x40, ((0x80u / 0x40) << 2u), 0x80, 0}; + unsigned long long block3_data[4] = {0x80 / 0x40, ((0x80u / 0x40) << 2u), 0x80, 0}; + + unsigned long long calc1_args[5] = {ADDR_CALC_CHKSUM, 0x1801b9180, 0x1801b91a0, 32, 0x180080640}; + unsigned long long calc2_args[5] = {ADDR_CALC_CHKSUM, 0x1801b9200, 0x1801b9220, 32, 0x180080640}; + unsigned long long calc3_args[5] = {ADDR_CALC_CHKSUM, 0x1801b9280, 0x1801b92a0, 32, 0x180080640}; + + if(is_device_session_open(dev)) close = 0; + else + { + close = 1; + if(IS_CHECKM8_FAIL(open_device_session(dev))) + { + checkm8_debug_indent("\tfailed to open a device session\n"); + return CHECKM8_FAIL_XFER; + } + } + + dev_write_memory(dev, 0x1801b91a0, (unsigned char *) block1_data, 64); + dev_write_memory(dev, 0x1801b9220, (unsigned char *) block2_data, 64); + dev_write_memory(dev, 0x1801b92a0, (unsigned char *) block3_data, 64); + + dev_exec(dev, 0, 5, calc1_args); + dev_exec(dev, 0, 5, calc2_args); + dev_exec(dev, 0, 5, calc3_args); + + if(close) close_device_session(dev); + +#else +#error "Can't fix heap for unknown platform" +#endif + + return CHECKM8_SUCCESS; } void free_device(struct pwned_device *dev) diff --git a/c8_remote/src/payload.c b/c8_remote/src/payload.c index ee7c526..6bbeacf 100644 --- a/c8_remote/src/payload.c +++ b/c8_remote/src/payload.c @@ -17,10 +17,21 @@ struct payload int len; DEV_PTR_T install_base; + DEV_PTR_T async_base; + struct payload *next; struct payload *prev; }; +struct data +{ + DEV_PTR_T addr; + int len; + + struct data *next; + struct data *prev; +}; + struct payload *get_payload(PAYLOAD_T p) { struct payload *res; @@ -66,43 +77,17 @@ struct payload *get_payload(PAYLOAD_T p) res->len = len; res->data = pl; res->install_base = DEV_PTR_NULL; + res->async_base = DEV_PTR_NULL; res->next = NULL; res->prev = NULL; return res; } -void free_payload(struct payload *p) -{ - free(p); -} - -DEV_PTR_T get_address(struct pwned_device *dev, LOCATION_T l, int len) -{ - checkm8_debug_indent("get_address(dev = %p, loc = %i, len = %i)\n", dev, l, len); - DEV_PTR_T retval; - unsigned long long malloc_args[2] = {ADDR_DEV_MALLOC, (unsigned long long) len}; - - struct dev_cmd_resp *resp = dev_exec(dev, 0, 2, malloc_args); - if(IS_CHECKM8_FAIL(resp->ret)) - { - free_dev_cmd_resp(resp); - checkm8_debug_indent("\tfailed to malloc an address\n"); - return DEV_PTR_NULL; - } - - retval = resp->retval; - free_dev_cmd_resp(resp); - - checkm8_debug_indent("\tgot address %llX\n", retval); - return retval; -} - - struct payload *dev_retrieve_payload(struct pwned_device *dev, PAYLOAD_T p) { struct payload *curr; - for(curr = dev->installed; curr != NULL; curr = curr->next) + for(curr = dev->inst_pl; curr != NULL; curr = curr->next) { if(curr->type == p) return curr; } @@ -113,14 +98,14 @@ struct payload *dev_retrieve_payload(struct pwned_device *dev, PAYLOAD_T p) int dev_link_payload(struct pwned_device *dev, struct payload *pl) { struct payload *curr; - if(dev->installed == NULL) + if(dev->inst_pl == NULL) { - dev->installed = pl; + dev->inst_pl = pl; return CHECKM8_SUCCESS; } else { - for(curr = dev->installed; curr->next != NULL; curr = curr->next); + for(curr = dev->inst_pl; curr->next != NULL; curr = curr->next); curr->next = pl; pl->prev = curr; @@ -128,11 +113,11 @@ int dev_link_payload(struct pwned_device *dev, struct payload *pl) } } -int *dev_unlink_payload(struct pwned_device *dev, struct payload *pl) +int dev_unlink_payload(struct pwned_device *dev, struct payload *pl) { - if(dev->installed == pl) + if(dev->inst_pl == pl) { - dev->installed = pl->next; + dev->inst_pl = pl->next; return CHECKM8_SUCCESS; } else @@ -145,6 +130,108 @@ int *dev_unlink_payload(struct pwned_device *dev, struct payload *pl) } } +struct data *dev_retrieve_data(struct pwned_device *dev, DEV_PTR_T addr) +{ + struct data *curr; + for(curr = dev->inst_data; curr != NULL; curr = curr->next) + { + if(curr->addr == addr) return curr; + } + + return NULL; +} + +int dev_link_data(struct pwned_device *dev, struct data *data) +{ + struct data *curr; + if(dev->inst_data == NULL) + { + dev->inst_data = data; + return CHECKM8_SUCCESS; + } + else + { + for(curr = dev->inst_data; curr->next != NULL; curr = curr->next); + + curr->next = data; + data->prev = curr; + return CHECKM8_SUCCESS; + } +} + +int dev_unlink_data(struct pwned_device *dev, struct data *data) +{ + if(dev->inst_data == data) + { + dev->inst_data = data->next; + return CHECKM8_SUCCESS; + } + else + { + data->prev->next = data->next; + if(data->next != NULL) + data->next->prev = data->prev; + + return CHECKM8_SUCCESS; + } +} + +DEV_PTR_T get_address(struct pwned_device *dev, LOCATION_T l, int len) +{ + checkm8_debug_indent("get_address(dev = %p, loc = %i, len = %i)\n", dev, l, len); + DEV_PTR_T retval; + unsigned long long malloc_args[2] = {ADDR_DEV_MALLOC, (unsigned long long) len}; + struct data *new_entry; + + struct dev_cmd_resp *resp = dev_exec(dev, 0, 2, malloc_args); + if(IS_CHECKM8_FAIL(resp->ret)) + { + free_dev_cmd_resp(resp); + checkm8_debug_indent("\tfailed to malloc an address\n"); + return DEV_PTR_NULL; + } + + retval = resp->retval; + free_dev_cmd_resp(resp); + + new_entry = malloc(sizeof(struct data)); + new_entry->addr = retval; + new_entry->len = len; + new_entry->prev = NULL; + new_entry->next = NULL; + dev_link_data(dev, new_entry); + + checkm8_debug_indent("\tgot address %llX\n", retval); + return retval; +} + +int free_address(struct pwned_device *dev, LOCATION_T l, DEV_PTR_T ptr) +{ + struct dev_cmd_resp *resp; + struct data *entry; + unsigned long long free_args[2] = {ADDR_DEV_FREE, ptr}; + + entry = dev_retrieve_data(dev, ptr); + if(entry == NULL) + { + checkm8_debug_indent("\tthis pointer was not allocated through the payload interface, not freeing\n"); + return CHECKM8_FAIL_NOINST; + } + + resp = dev_exec(dev, 0, 2, free_args); + if(IS_CHECKM8_FAIL(resp->ret)) + { + free_dev_cmd_resp(resp); + checkm8_debug_indent("\tfailed to free allocated payload memory\n"); + return CHECKM8_FAIL_XFER; + } + + free_dev_cmd_resp(resp); + dev_unlink_data(dev, entry); + free(entry); + + return CHECKM8_SUCCESS; +} int install_payload(struct pwned_device *dev, PAYLOAD_T p, LOCATION_T loc) { @@ -178,8 +265,6 @@ int install_payload(struct pwned_device *dev, PAYLOAD_T p, LOCATION_T loc) int uninstall_payload(struct pwned_device *dev, PAYLOAD_T p) { checkm8_debug_indent("uninstall payload(dev = %p, p = %i)\n", dev, p); - unsigned long long free_args[2]; - struct dev_cmd_resp *resp; struct payload *pl = dev_retrieve_payload(dev, p); if(pl == NULL) @@ -188,19 +273,31 @@ int uninstall_payload(struct pwned_device *dev, PAYLOAD_T p) return CHECKM8_FAIL_INVARGS; } - free_args[0] = ADDR_DEV_FREE; - free_args[1] = pl->install_base; - - resp = dev_exec(dev, 0, 2, free_args); - if(IS_CHECKM8_FAIL(resp->ret)) + if(IS_CHECKM8_FAIL(free_address(dev, SRAM, pl->install_base))) { - free_dev_cmd_resp(resp); - checkm8_debug_indent("\tfailed to free allocated payload memory\n"); + checkm8_debug_indent("\tfailed to free memory used by payload!\n"); return CHECKM8_FAIL_XFER; } dev_unlink_payload(dev, pl); - free_payload(pl); + free(pl); + return CHECKM8_SUCCESS; +} + +int uninstall_all_payloads(struct pwned_device *dev) +{ + checkm8_debug_indent("uninstall_all_payloads(dev = %p)\n"); + int ret; + while(dev->inst_pl != NULL) + { + ret = uninstall_payload(dev, dev->inst_pl->type); + if(IS_CHECKM8_FAIL(ret)) + { + checkm8_debug_indent("\terror while uninstalling\n"); + return ret; + } + } + return CHECKM8_SUCCESS; } @@ -217,47 +314,6 @@ DEV_PTR_T get_payload_address(struct pwned_device *dev, PAYLOAD_T p) } } - -DEV_PTR_T install_data(struct pwned_device *dev, LOCATION_T loc, unsigned char *data, int len) -{ - checkm8_debug_indent("install_data(dev = %p, loc = %i, data = %p, len = %i)\n", dev, loc, data, len); - struct dev_cmd_resp *resp; - DEV_PTR_T addr = get_address(dev, loc, len); - - if(addr == -1) - { - checkm8_debug_indent("\tfailed to get an address\n"); - return DEV_PTR_NULL; - } - - checkm8_debug_indent("\twriting data to address %X\n", addr); - resp = dev_write_memory(dev, addr, data, len); - if(IS_CHECKM8_FAIL(resp->ret)) - { - checkm8_debug_indent("\tfailed to write data\n"); - return -1; - } - - free_dev_cmd_resp(resp); - return addr; -} - -int uninstall_data(struct pwned_device *dev, DEV_PTR_T addr) -{ - checkm8_debug_indent("uninstall_data(dev = %p, addr = %X)\n", dev, addr); - struct dev_cmd_resp *resp; - unsigned long long free_args[2] = {ADDR_DEV_FREE, addr}; - - resp = dev_exec(dev, 0, 2, free_args); - if(IS_CHECKM8_FAIL(resp->ret)) - { - checkm8_debug_indent("failed to free memory at %x\n", addr); - return CHECKM8_FAIL_XFER; - } - - return CHECKM8_SUCCESS; -} - struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int response_len, int nargs, ...) { checkm8_debug_indent("execute_payload(dev = %p, p = %i, response_len = %i, nargs = %i, ...)\n", @@ -290,13 +346,15 @@ struct dev_cmd_resp *execute_payload(struct pwned_device *dev, PAYLOAD_T p, int return dev_exec(dev, response_len, nargs + 1, args); } -unsigned long long execute_payload_async(struct pwned_device *dev, PAYLOAD_T p, int bufsize, int nargs, ...) +unsigned long long setup_payload_async(struct pwned_device *dev, PAYLOAD_T p, int bufsize, int nargs, ...) { - checkm8_debug_indent("execute_payload_async(dev = %p, p = %i, bufsize = %i, nargs = %i, ...)\n", + checkm8_debug_indent("setup_payload_async(dev = %p, p = %i, bufsize = %i, nargs = %i, ...)\n", dev, p, bufsize, bufsize, nargs); int i; struct dev_cmd_resp *resp; struct payload *pl; + DEV_PTR_T buf_addr; + unsigned long long buf_args[nargs], task_args[5]; if((pl = dev_retrieve_payload(dev, p)) == NULL) { @@ -304,13 +362,184 @@ unsigned long long execute_payload_async(struct pwned_device *dev, PAYLOAD_T p, return DEV_PTR_NULL; } + checkm8_debug_indent("\tadjusting buffer size (if necessary)\n"); if(bufsize < nargs * sizeof(unsigned long long)) { checkm8_debug_indent("\texpanding buffer to fit (at least) provided arguments\n"); bufsize = nargs * sizeof(unsigned long long); } - + buf_addr = get_address(dev, SRAM, bufsize); + if(buf_addr == DEV_PTR_NULL) + { + checkm8_debug_indent("\tfailed to get a shared buffer for the payload\n"); + return DEV_PTR_NULL; + } + + va_list arg_list; + va_start(arg_list, nargs); + for(i = 0; i < nargs; i++) + { + buf_args[i] = va_arg(arg_list, unsigned long long); + checkm8_debug_indent("\textracted arg %lx\n", buf_args[i]); + } + va_end(arg_list); + + resp = dev_write_memory(dev, buf_addr, (unsigned char *) buf_args, nargs * sizeof(unsigned long long)); + if(IS_CHECKM8_FAIL(resp->ret)) + { + checkm8_debug_indent("\tfailed to write args to shared buffer\n"); + if(IS_CHECKM8_FAIL(free_address(dev, SRAM, buf_addr))) + { + checkm8_debug_indent("\talso failed to free buffer (something is really wrong)\n"); + } + + free_dev_cmd_resp(resp); + return DEV_PTR_NULL; + } + + task_args[0] = ADDR_TASK_NEW; + task_args[1] = 0x10001943b; // todo: name pointer + task_args[2] = pl->install_base; + task_args[3] = buf_addr; + task_args[4] = 0x4000; + + resp = dev_exec(dev, 0, 5, task_args); + if(IS_CHECKM8_FAIL(resp->ret)) + { + checkm8_debug_indent("\tfailed to create a new task\n"); + if(IS_CHECKM8_FAIL(free_address(dev, SRAM, buf_addr))) + { + checkm8_debug_indent("\talso failed to free buffer (something is really wrong)\n"); + } + + free_dev_cmd_resp(resp); + return DEV_PTR_NULL; + } + + pl->async_base = resp->retval; + free_dev_cmd_resp(resp); + return buf_addr; +} + +int run_payload_async(struct pwned_device *dev, PAYLOAD_T p) +{ + checkm8_debug_indent("run_payload_async(dev = %p, payload = %i)\n", dev, p); + struct payload *pl; + struct dev_cmd_resp *resp; + unsigned long long args[2]; + int retval; + + if((pl = dev_retrieve_payload(dev, p)) == NULL) + { + checkm8_debug_indent("\tpayload is not installed!\n"); + return CHECKM8_FAIL_NOINST; + } + + if(pl->async_base == DEV_PTR_NULL) + { + checkm8_debug_indent("\tasync payload is not set up correctly!\n"); + return CHECKM8_FAIL_NOINST; + } + + args[0] = ADDR_TASK_RUN; + args[1] = pl->async_base; + + resp = dev_exec(dev, 0, 2, args); + retval = resp->ret; + free_dev_cmd_resp(resp); + + return retval; +} + +int kill_payload_async(struct pwned_device *dev, PAYLOAD_T p, DEV_PTR_T buf_addr) +{ + checkm8_debug_indent("kill_payload_async(dev = %p, p = %i, buf_addr = %llx)\n", dev, p, buf_addr); + struct payload *pl; + struct dev_cmd_resp *resp; + unsigned long long args[2]; + + if((pl = dev_retrieve_payload(dev, p)) == NULL) + { + checkm8_debug_indent("\tpayload is not installed\n"); + return CHECKM8_FAIL_NOINST; + } + + if(pl->async_base == DEV_PTR_NULL) + { + checkm8_debug_indent("\tasync payload is not set up correctly\n"); + return CHECKM8_FAIL_NOINST; + } + + args[0] = ADDR_TASK_FREE; + args[1] = pl->async_base; + + resp = dev_exec(dev, 0, 2, args); + pl->async_base = DEV_PTR_NULL; + + if(IS_CHECKM8_FAIL(resp->ret)) + { + checkm8_debug_indent("\tfailed to kill payload\n"); + free_dev_cmd_resp(resp); + return CHECKM8_FAIL_XFER; + } + + free_dev_cmd_resp(resp); + if(IS_CHECKM8_FAIL(free_address(dev, SRAM, buf_addr))) + { + checkm8_debug_indent("\tfailed to free shared buffer\n"); + return CHECKM8_FAIL_XFER; + } + + return CHECKM8_SUCCESS; +} + +DEV_PTR_T install_data(struct pwned_device *dev, LOCATION_T loc, unsigned char *data, int len) +{ + checkm8_debug_indent("install_data(dev = %p, loc = %i, data = %p, len = %i)\n", dev, loc, data, len); + struct dev_cmd_resp *resp; + DEV_PTR_T addr = get_address(dev, loc, len); + + if(addr == -1) + { + checkm8_debug_indent("\tfailed to get an address\n"); + return DEV_PTR_NULL; + } + + checkm8_debug_indent("\twriting data to address %X\n", addr); + resp = dev_write_memory(dev, addr, data, len); + if(IS_CHECKM8_FAIL(resp->ret)) + { + checkm8_debug_indent("\tfailed to write data\n"); + return -1; + } + + free_dev_cmd_resp(resp); + return addr; +} + +int uninstall_data(struct pwned_device *dev, DEV_PTR_T addr) +{ + checkm8_debug_indent("uninstall_data(dev = %p, addr = %X)\n", dev, addr); + return free_address(dev, SRAM, addr); +} + +int uninstall_all_data(struct pwned_device *dev) +{ + checkm8_debug_indent("uninstall_all_data(dev = %p)\n", dev); + int retval; + + while(dev->inst_data != NULL) + { + retval = uninstall_data(dev, dev->inst_data->addr); + if(IS_CHECKM8_FAIL(retval)) + { + checkm8_debug_indent("\terror while uninstalling data\n"); + return retval; + } + } + + return CHECKM8_SUCCESS; } struct dev_cmd_resp *read_gadget(struct pwned_device *dev, DEV_PTR_T addr, int len) diff --git a/c8_remote/src/usb_helpers.c b/c8_remote/src/usb_helpers.c index 06e7027..fb70697 100644 --- a/c8_remote/src/usb_helpers.c +++ b/c8_remote/src/usb_helpers.c @@ -517,6 +517,12 @@ int ctrl_transfer(struct pwned_device *dev, // get the size of this chunk size = 0; ard_read(dev, (unsigned char *) &size, 2); + if(size > ARD_BUF_SIZE) + { + checkm8_debug_indent("\treceived bad chunk size %i\n", size); + return CHECKM8_FAIL_XFER; + } + checkm8_debug_indent("\treceiving data chunk of size %i\n", size); ard_read(dev, (unsigned char *) &data[amount], size); diff --git a/include/checkm8_config.h b/include/checkm8_config.h index 83d8ca9..56033f0 100644 --- a/include/checkm8_config.h +++ b/include/checkm8_config.h @@ -3,7 +3,7 @@ #define CHECKM8_LOGGING -//#define WITH_ARDUINO +#define WITH_ARDUINO #define ARDUINO_DEV "/dev/ttyACM0" #define ARDUINO_BAUD 115200