diff options
Diffstat (limited to 'unicorn_mode/samples/c')
-rw-r--r-- | unicorn_mode/samples/c/a.out | bin | 17184 -> 0 bytes | |||
-rw-r--r-- | unicorn_mode/samples/c/harness.c | 81 | ||||
-rw-r--r-- | unicorn_mode/samples/c/persistent_target.c (renamed from unicorn_mode/samples/c/simple_target.c) | 27 | ||||
-rw-r--r-- | unicorn_mode/samples/c/persistent_target_x86_64 | bin | 0 -> 16544 bytes |
4 files changed, 74 insertions, 34 deletions
diff --git a/unicorn_mode/samples/c/a.out b/unicorn_mode/samples/c/a.out deleted file mode 100644 index 176c25e1..00000000 --- a/unicorn_mode/samples/c/a.out +++ /dev/null Binary files differdiff --git a/unicorn_mode/samples/c/harness.c b/unicorn_mode/samples/c/harness.c index a987b8e1..31416ae2 100644 --- a/unicorn_mode/samples/c/harness.c +++ b/unicorn_mode/samples/c/harness.c @@ -28,35 +28,56 @@ #include <unicorn/unicorn.h> // Path to the file containing the binary to emulate -#define BINARY_FILE ("simple_target_x86_64") +#define BINARY_FILE ("persistent_target_x86_64") // Memory map for the code to be tested // Arbitrary address where code to test will be loaded -#define BASE_ADDRESS (0x100000) -#define CODE_ADDRESS (0x101119) -#define END_ADDRESS (0x1011d7) +static const int64_t BASE_ADDRESS = 0x100000; +static const int64_t CODE_ADDRESS = 0x101139; +static const int64_t END_ADDRESS = 0x10120d; // Address of the stack (Some random address again) -#define STACK_ADDRESS (((int64_t) 0x01) << 58) +static const int64_t STACK_ADDRESS = (((int64_t) 0x01) << 58); // Size of the stack (arbitrarily chosen, just make it big enough) -#define STACK_SIZE (0x10000) +static const int64_t STACK_SIZE = 0x10000; // Location where the input will be placed (make sure the emulated program knows this somehow, too ;) ) -#define INPUT_LOCATION (0x10000) +static const int64_t INPUT_LOCATION = 0x10000; // Inside the location, we have an ofset in our special case -#define INPUT_OFFSET (0x16) +static const int64_t INPUT_OFFSET = 0x16; // Maximum allowable size of mutated data from AFL -#define INPUT_SIZE_MAX (0x10000) +static const int64_t INPUT_SIZE_MAX = 0x10000; // Alignment for unicorn mappings (seems to be needed) -#define ALIGNMENT ((uint64_t) 0x1000) +static const int64_t ALIGNMENT = 0x1000; + +// In our special case, we emulate main(), so argc is needed. +static const uint64_t EMULATED_ARGC = 2; + +// The return from our fake strlen +static size_t current_input_len = 0; static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } +/* +The sample uses strlen, since we don't have a loader or libc, we'll fake it. +We know the strlen will return the lenght of argv[1] that we just planted. +It will be a lot faster than an actual strlen for this specific purpose. +*/ +static void hook_strlen(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + //Hook + //116b: e8 c0 fe ff ff call 1030 <strlen@plt> + // We place the return at RAX + //printf("Strlen hook at addr 0x%lx (size: 0x%x), result: %ld\n", address, size, current_input_len); + uc_reg_write(uc, UC_X86_REG_RAX, ¤t_input_len); + // We skip the actual call by updating RIP + uint64_t next_addr = address + size; + uc_reg_write(uc, UC_X86_REG_RIP, &next_addr); +} + /* Unicorn page needs to be 0x1000 aligned, apparently */ static uint64_t pad(uint64_t size) { if (size % ALIGNMENT == 0) return size; @@ -99,11 +120,25 @@ static bool place_input_callback( void *data ){ // printf("Placing input with len %ld to %x\n", input_len, DATA_ADDRESS); - if (input_len >= INPUT_SIZE_MAX - INPUT_OFFSET) { - // Test input too long, ignore this testcase + if (input_len < 1 || input_len >= INPUT_SIZE_MAX - INPUT_OFFSET) { + // Test input too short or too long, ignore this testcase return false; } + + // For persistent mode, we have to set up stack and memory each time. + uc_reg_write(uc, UC_X86_REG_RIP, &CODE_ADDRESS); // Set the instruction pointer back + // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly) + uc_reg_write(uc, UC_X86_REG_RSI, &INPUT_LOCATION); // argv + uc_reg_write(uc, UC_X86_REG_RDI, &EMULATED_ARGC); // argc == 2 + + // We need a valid c string, make sure it never goes out of bounds. + input[input_len-1] = '\0'; + // Write the testcase to unicorn. uc_mem_write(uc, INPUT_LOCATION + INPUT_OFFSET, input, input_len); + + // store input_len for the faux strlen hook + current_input_len = input_len; + return true; } @@ -187,12 +222,7 @@ int main(int argc, char **argv, char **envp) { uc_mem_write(uc, 0x10008, "\x16\x00\x01", 3); // little endian of 0x10016, see above - // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly) - uint64_t input_location = INPUT_LOCATION; - uc_reg_write(uc, UC_X86_REG_RSI, &input_location); // argv - uint64_t emulated_argc = 2; - uc_reg_write(uc, UC_X86_REG_RDI, &emulated_argc); // argc == 2 - + // If we want tracing output, set the callbacks here if (tracing) { // tracing all basic blocks with customized callback @@ -200,6 +230,11 @@ int main(int argc, char **argv, char **envp) { uc_hook_add(uc, &hooks[1], UC_HOOK_CODE, hook_code, NULL, BASE_ADDRESS, BASE_ADDRESS + len - 1); } + // Add our strlen hook (for this specific testcase only) + int strlen_hook_pos = BASE_ADDRESS + 0x116b; + uc_hook strlen_hook; + uc_hook_add(uc, &strlen_hook, UC_HOOK_CODE, hook_strlen, NULL, strlen_hook_pos, strlen_hook_pos); + printf("Starting to fuzz :)\n"); fflush(stdout); @@ -211,9 +246,9 @@ int main(int argc, char **argv, char **envp) { &end_address, // Where to exit (this is an array) 1, // Count of end addresses NULL, // Optional calback to run after each exec - false, - 1, // For persistent mode: How many rounds to run - NULL + false, // true, if the optional callback should be run also for non-crashes + 100, // For persistent mode: How many rounds to run + NULL // additional data pointer ); switch(afl_ret) { case UC_AFL_RET_ERROR: diff --git a/unicorn_mode/samples/c/simple_target.c b/unicorn_mode/samples/c/persistent_target.c index dbf10911..5b866f86 100644 --- a/unicorn_mode/samples/c/simple_target.c +++ b/unicorn_mode/samples/c/persistent_target.c @@ -10,25 +10,30 @@ * Written by Nathan Voss <njvoss99@gmail.com> * Adapted by Lukas Seidel <seidel.1@campus.tu-berlin.de> */ +#include <stdint.h> +#include <string.h> int main(int argc, char** argv) { - if(argc < 2){ - return -1; - } + if (argc < 2) return -1; char *data_buf = argv[1]; + uint64_t data_len = strlen(data_buf); + if (data_len < 20) return -2; - if (data_buf[20] != 0) { - // Cause an 'invalid read' crash if data[0..3] == '\x01\x02\x03\x04' - unsigned char invalid_read = *(unsigned char *) 0x00000000; - } else if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) { + for (; data_len --> 0 ;) { + if (data_len >= 18) continue; + if (data_len > 2 && data_len < 18) { + ((char *)data_len)[(uint64_t)data_buf] = data_buf[data_len + 1]; + } else if (data_buf[9] == 0x90 && data_buf[10] != 0x00 && data_buf[11] == 0x90) { + // Cause a crash if data[10] is not zero, but [9] and [11] are zero + unsigned char invalid_read = *(unsigned char *) 0x00000000; + } + } + if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) { // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2] unsigned char invalid_read = *(unsigned char *) 0x00000000; - } else if (data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) { - // Cause a crash if data[10] is not zero, but [9] and [11] are zero - unsigned char invalid_read = *(unsigned char *) 0x00000000; - } + } return 0; } diff --git a/unicorn_mode/samples/c/persistent_target_x86_64 b/unicorn_mode/samples/c/persistent_target_x86_64 new file mode 100644 index 00000000..22e04357 --- /dev/null +++ b/unicorn_mode/samples/c/persistent_target_x86_64 Binary files differ |