diff options
19 files changed, 502 insertions, 30 deletions
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 219be822..2ef2c4e7 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1940,17 +1940,17 @@ void check_binary(u8* fname) { } - if ((qemu_mode || unicorn_mode) && + if ((qemu_mode) && memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST "This program appears to be instrumented with afl-gcc, but is being " "run in\n" - " QEMU or Unicorn mode (-Q or -U). This is probably not what you " + " QEMU mode (-Q). This is probably not what you " "want -\n" " this setup will be slow and offer no practical benefits.\n"); - FATAL("Instrumentation found in -Q or -U mode"); + FATAL("Instrumentation found in -Q mode"); } 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/persistent_target.c b/unicorn_mode/samples/c/persistent_target.c new file mode 100644 index 00000000..5b866f86 --- /dev/null +++ b/unicorn_mode/samples/c/persistent_target.c @@ -0,0 +1,39 @@ +/* + * Sample target file to test afl-unicorn fuzzing capabilities. + * This is a very trivial example that will crash pretty easily + * in several different exciting ways. + * + * Input is assumed to come from a buffer located at DATA_ADDRESS + * (0x00300000), so make sure that your Unicorn emulation of this + * puts user data there. + * + * 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; + + char *data_buf = argv[1]; + uint64_t data_len = strlen(data_buf); + if (data_len < 20) return -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; + } + + 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 differdiff --git a/unicorn_mode/samples/persistent/.gitignore b/unicorn_mode/samples/persistent/.gitignore new file mode 100644 index 00000000..3e446132 --- /dev/null +++ b/unicorn_mode/samples/persistent/.gitignore @@ -0,0 +1,3 @@ +harness +harness-debug +out diff --git a/unicorn_mode/samples/persistent/COMPILE.md b/unicorn_mode/samples/persistent/COMPILE.md new file mode 100644 index 00000000..781f15c0 --- /dev/null +++ b/unicorn_mode/samples/persistent/COMPILE.md @@ -0,0 +1,24 @@ +# C Sample + +This shows a simple persistent harness for unicornafl in C +In contrast to the normal c harness, this harness manually resets the unicorn state on each new input. +Thanks to this, we can rerun the testcase in unicorn multiple times, without the need to fork again. + +## Compiling sample.c + +The target can be built using the `make` command. +Just make sure you have built unicorn support first: +```bash +cd /path/to/afl/unicorn_mode +./build_unicorn_support.sh +``` + +## Compiling persistent_target.c + +You don't need to compile persistent_target.c since a X86_64 binary version is +pre-built and shipped in this sample folder. This file documents how the binary +was built in case you want to rebuild it or recompile it for any reason. + +The pre-built binary (persistent_target_x86_64.bin) was built using -g -O0 in gcc. + +We then load the binary we execute the main function directly. diff --git a/unicorn_mode/samples/persistent/Makefile b/unicorn_mode/samples/persistent/Makefile new file mode 100644 index 00000000..fe100490 --- /dev/null +++ b/unicorn_mode/samples/persistent/Makefile @@ -0,0 +1,42 @@ +# UnicornAFL Usage +# Original Unicorn Example Makefile by Nguyen Anh Quynh <aquynh@gmail.com>, 2015 +# Adapted for AFL++ by domenukk <domenukk@gmail.com>, 2020 + +UNAME_S := $(shell uname -s) + +LIBDIR = ../../unicornafl +BIN_EXT = +AR_EXT = a + +# Verbose output? +V ?= 0 + +CFLAGS += -Wall -Werror -I../../unicornafl/include + +LDFLAGS += -L$(LIBDIR) -lpthread -lm +ifeq ($(UNAME_S), Linux) +LDFLAGS += -lrt +endif + +ifneq ($(CROSS),) +CC = $(CROSS)gcc +endif + +.PHONY: all clean + +all: harness + +clean: + rm -rf *.o harness harness-debug + +harness.o: harness.c ../../unicornafl/include/unicorn/*.h + ${CC} ${CFLAGS} -O3 -c $< + +harness-debug.o: harness.c ../../unicornafl/include/unicorn/*.h + ${CC} ${CFLAGS} -g -c $< -o $@ + +harness: harness.o + ${CC} -L${LIBDIR} $< ../../unicornafl/libunicornafl.a $(LDFLAGS) -o $@ + +debug: harness-debug.o + ${CC} -L${LIBDIR} $< ../../unicornafl/libunicornafl.a $(LDFLAGS) -o harness-debug diff --git a/unicorn_mode/samples/persistent/harness.c b/unicorn_mode/samples/persistent/harness.c new file mode 100644 index 00000000..d8ebffbc --- /dev/null +++ b/unicorn_mode/samples/persistent/harness.c @@ -0,0 +1,269 @@ +/* + Persistent test harness for AFL++'s unicornafl c mode. + + This loads the persistent_target.bin binary (precompiled as X86_64 code) into + Unicorn's memory map for emulation, places the specified input into + the argv buffer (handed in as first parameter), and executes 'main()'. + Any crashes during emulation will automatically be handled by the afl-fuzz() function. + + Run under AFL as follows: + + $ cd <afl_path>/unicorn_mode/samples/persistent/ + $ make + $ ../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@ + + (Re)run a simgle input with block tracing using: + + $ ./harness -t [inputfile] +*/ + +// This is not your everyday Unicorn. +#define UNICORN_AFL + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include <unicorn/unicorn.h> + +// Path to the file containing the binary to emulate +#define BINARY_FILE ("persistent_target_x86_64") + +// Memory map for the code to be tested +// Arbitrary address where code to test will be loaded +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) +static const int64_t STACK_ADDRESS = (((int64_t) 0x01) << 58); +// Size of the stack (arbitrarily chosen, just make it big enough) +static const int64_t STACK_SIZE = 0x10000; +// Location where the input will be placed (make sure the emulated program knows this somehow, too ;) ) +static const int64_t INPUT_LOCATION = 0x10000; +// Inside the location, we have an ofset in our special case +static const int64_t INPUT_OFFSET = 0x16; +// Maximum allowable size of mutated data from AFL +static const int64_t INPUT_SIZE_MAX = 0x10000; +// Alignment for unicorn mappings (seems to be needed) +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) { + 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 + uc_reg_write(uc, UC_X86_REG_RAX, ¤t_input_len); + // We skip the actual call by updating RIP + //printf("Strlen hook at addr 0x%lx (size: 0x%x), result: %ld\n", address, size, current_input_len); + 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; + return ((size / ALIGNMENT) + 1) * ALIGNMENT; +} + +/* returns the filesize in bytes, -1 or error. */ +static off_t afl_mmap_file(char *filename, char **buf_ptr) { + + off_t ret = -1; + + int fd = open(filename, O_RDONLY); + + struct stat st = {0}; + if (fstat(fd, &st)) goto exit; + + off_t in_len = st.st_size; + if (in_len == -1) { + /* This can only ever happen on 32 bit if the file is exactly 4gb. */ + fprintf(stderr, "Filesize of %s too large", filename); + goto exit; + } + + *buf_ptr = mmap(0, in_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (*buf_ptr != MAP_FAILED) ret = in_len; + +exit: + close(fd); + return ret; + +} + +/* Place the input at the right spot inside unicorn */ +static bool place_input_callback( + uc_engine *uc, + char *input, + size_t input_len, + uint32_t persistent_round, + void *data +){ + // printf("Placing input with len %ld to %x\n", input_len, DATA_ADDRESS); + 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; +} + +static void mem_map_checked(uc_engine *uc, uint64_t addr, size_t size, uint32_t mode) { + size = pad(size); + //printf("SIZE %lx, align: %lx\n", size, ALIGNMENT); + uc_err err = uc_mem_map(uc, addr, size, mode); + if (err != UC_ERR_OK) { + printf("Error mapping %ld bytes at 0x%lx: %s (mode: %d)\n", size, addr, uc_strerror(err), mode); + exit(1); + } +} + +int main(int argc, char **argv, char **envp) { + if (argc == 1) { + printf("Test harness for simple_target.bin. Usage: harness [-t] <inputfile>\n"); + exit(1); + } + bool tracing = false; + char *filename = argv[1]; + if (argc > 2 && !strcmp(argv[1], "-t")) { + tracing = true; + filename = argv[2]; + } + + uc_engine *uc; + uc_err err; + uc_hook hooks[2]; + char *file_contents; + + // Initialize emulator in X86_64 mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return -1; + } + + printf("Loading data input from %s\n", BINARY_FILE); + off_t len = afl_mmap_file(BINARY_FILE, &file_contents); + if (len < 0) { + perror("Could not read binary to emulate"); + return -2; + } + if (len == 0) { + fprintf(stderr, "File at '%s' is empty\n", BINARY_FILE); + return -3; + } + + // Map memory. + mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL); + printf("Len: %lx", len); + fflush(stdout); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, BASE_ADDRESS, file_contents, len) != UC_ERR_OK) { + printf("Error writing to CODE"); + } + + // Release copied contents + munmap(file_contents, len); + + // Set the program counter to the start of the code + uint64_t start_address = CODE_ADDRESS; // address of entry point of main() + uint64_t end_address = END_ADDRESS; // Address of last instruction in main() + uc_reg_write(uc, UC_X86_REG_RIP, &start_address); // address of entry point of main() + + // Setup the Stack + mem_map_checked(uc, STACK_ADDRESS - STACK_SIZE, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); + uint64_t stack_val = STACK_ADDRESS; + printf("%ld", stack_val); + uc_reg_write(uc, UC_X86_REG_RSP, &stack_val); + + // reserve some space for our input data + mem_map_checked(uc, INPUT_LOCATION, INPUT_SIZE_MAX, UC_PROT_READ); + + // build a "dummy" argv with lenth 2 at 0x10000: + // 0x10000 argv[0] NULL + // 0x10008 argv[1] (char *)0x10016 --. points to the next offset. + // 0x10016 argv[1][0], ... <-^ contains the acutal input data. (INPUT_LOCATION + INPUT_OFFSET) + + uc_mem_write(uc, 0x10008, "\x16\x00\x01", 3); // little endian of 0x10016, see above + + + // If we want tracing output, set the callbacks here + if (tracing) { + // tracing all basic blocks with customized callback + uc_hook_add(uc, &hooks[0], UC_HOOK_BLOCK, hook_block, NULL, 1, 0); + 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); + + // let's gooo + uc_afl_ret afl_ret = uc_afl_fuzz( + uc, // The unicorn instance we prepared + filename, // Filename of the input to process. In AFL this is usually the '@@' placeholder, outside it's any input file. + place_input_callback, // Callback that places the input (automatically loaded from the file at filename) in the unicorninstance + &end_address, // Where to exit (this is an array) + 1, // Count of end addresses + NULL, // Optional calback to run after each exec + false, // true, if the optional callback should be run also for non-crashes + 1000, // For persistent mode: How many rounds to run + NULL // additional data pointer + ); + switch(afl_ret) { + case UC_AFL_RET_ERROR: + printf("Error starting to fuzz"); + return -3; + break; + case UC_AFL_RET_NO_AFL: + printf("No AFL attached - We are done with a single run."); + break; + default: + break; + } + return 0; +} diff --git a/unicorn_mode/samples/persistent/persistent_target.c b/unicorn_mode/samples/persistent/persistent_target.c new file mode 100644 index 00000000..5b866f86 --- /dev/null +++ b/unicorn_mode/samples/persistent/persistent_target.c @@ -0,0 +1,39 @@ +/* + * Sample target file to test afl-unicorn fuzzing capabilities. + * This is a very trivial example that will crash pretty easily + * in several different exciting ways. + * + * Input is assumed to come from a buffer located at DATA_ADDRESS + * (0x00300000), so make sure that your Unicorn emulation of this + * puts user data there. + * + * 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; + + char *data_buf = argv[1]; + uint64_t data_len = strlen(data_buf); + if (data_len < 20) return -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; + } + + return 0; +} diff --git a/unicorn_mode/samples/persistent/persistent_target_x86_64 b/unicorn_mode/samples/persistent/persistent_target_x86_64 new file mode 100644 index 00000000..22e04357 --- /dev/null +++ b/unicorn_mode/samples/persistent/persistent_target_x86_64 Binary files differdiff --git a/unicorn_mode/samples/persistent/sample_all.sh b/unicorn_mode/samples/persistent/sample_all.sh new file mode 100644 index 00000000..01daf365 --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_all.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +[ -z "${UNAME}" ] && UNAME=$(uname) + +DIR=`dirname $0` + +if [ "$UNAME" = Darwin ]; then + export DYLD_LIBRARY_PATH=../../unicorn +else + export LD_LIBRARY_PATH=../../unicorn +fi + + + +if [ ! test -e $DIR/harness]; then + echo "[!] harness not found in $DIR" + exit 1 +fi \ No newline at end of file diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample1.bin b/unicorn_mode/samples/persistent/sample_inputs/sample1.bin new file mode 100644 index 00000000..85df5078 --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_inputs/sample1.bin @@ -0,0 +1 @@ +abcd \ No newline at end of file diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample2.bin b/unicorn_mode/samples/persistent/sample_inputs/sample2.bin new file mode 100644 index 00000000..f76dd238 --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_inputs/sample2.bin Binary files differdiff --git a/unicorn_mode/samples/persistent/sample_inputs/sample3.bin b/unicorn_mode/samples/persistent/sample_inputs/sample3.bin new file mode 100644 index 00000000..6b2aaa76 --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_inputs/sample3.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample4.bin b/unicorn_mode/samples/persistent/sample_inputs/sample4.bin new file mode 100644 index 00000000..71bd63e6 --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_inputs/sample4.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample5.bin b/unicorn_mode/samples/persistent/sample_inputs/sample5.bin new file mode 100644 index 00000000..aed2973e --- /dev/null +++ b/unicorn_mode/samples/persistent/sample_inputs/sample5.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/unicorn_mode/samples/c/simple_target.c b/unicorn_mode/samples/persistent/simple_target_noncrashing.c index dbf10911..00764473 100644 --- a/unicorn_mode/samples/c/simple_target.c +++ b/unicorn_mode/samples/persistent/simple_target_noncrashing.c @@ -19,12 +19,11 @@ int main(int argc, char** argv) { char *data_buf = argv[1]; + if len(data_buf < 20) { 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; + printf("Not crashing"); } else 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; + printf("Also not crashing with databuf[0] == %c", data_buf[0]) } 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; diff --git a/unicorn_mode/samples/persistent/simple_target_x86_64 b/unicorn_mode/samples/persistent/simple_target_x86_64 new file mode 100644 index 00000000..560264fd --- /dev/null +++ b/unicorn_mode/samples/persistent/simple_target_x86_64 Binary files differ |