about summary refs log tree commit diff
path: root/unicorn_mode/samples/c
diff options
context:
space:
mode:
Diffstat (limited to 'unicorn_mode/samples/c')
-rw-r--r--unicorn_mode/samples/c/a.outbin17184 -> 0 bytes
-rw-r--r--unicorn_mode/samples/c/harness.c81
-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_64bin0 -> 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, &current_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