about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--README.txt4
-rw-r--r--afl-dyninst.cpp230
-rwxr-xr-xafl-fuzz-dyninst.sh3
-rw-r--r--libAflDyninst.cpp89
5 files changed, 262 insertions, 68 deletions
diff --git a/CHANGES b/CHANGES
index fb19b41..b5ff722 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@ Changelog
 =========
 
 https://github.com/vanhauser-thc/afl-dyninst
+ - -e option now also understands function names, not only 0x1234 addresses
+ - searches for multiple entrypoints now: main, init, start and _NAME variants
+ - afl-dyninst now works fine with AARCH64 :)
+ - more verbose output, -vv -vvv support
  - fixed some typos
  - renamed afl-fuzz.sh to afl-fuzz-dyninst.sh and make install
    installs now the scripts
diff --git a/README.txt b/README.txt
index 24081a4..7d99e3d 100644
--- a/README.txt
+++ b/README.txt
@@ -69,12 +69,14 @@ This options is mainly to hunt down bugs in dyninst.
 
 Switch -D installs the afl fork server and forced exit functions but no
 basic block instrumentation. That would serve no purpose - unless there is
-another interesting tool coming up ... :)
+another interesting tool coming up: afl-pin (already available at
+https://github.com/vanhauser-thc/afl-pin) and afl-dynamorio (wip)
 
 
 Compiling:
 ----------
 
+0. Clone, compile and install dyninst: https://github.com/dyninst/dyninst/
 1. Edit the Makefile and set DYNINST_ROOT and AFL_ROOT to appropriate paths. 
 2. make
 3. make install
diff --git a/afl-dyninst.cpp b/afl-dyninst.cpp
index 5ba3d3c..b908b24 100644
--- a/afl-dyninst.cpp
+++ b/afl-dyninst.cpp
@@ -1,14 +1,19 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
 #include <cstdlib>
 #include <iostream>
 #include <vector>
 #include <string>
-#include <stdlib.h>
 #include <sstream>
 #include <climits>
-using namespace std;
-
-// Command line parsing
-#include <getopt.h>
 
 // DyninstAPI includes
 #include "BPatch.h"
@@ -16,14 +21,18 @@ using namespace std;
 #include "BPatch_flowGraph.h"
 #include "BPatch_function.h"
 #include "BPatch_point.h"
-#include "dyninstversion.h"
+#include "BPatch_addressSpace.h"
+#include "BPatch_process.h"
+#include "dyninstversion.h"     // if this include errors, compile and install https://github.com/dyninst/dyninst
 
+using namespace std;
 using namespace Dyninst;
 
 //cmd line options
 char *originalBinary;
 char *instrumentedBinary;
-bool verbose = false;
+char *entryPointName = NULL;
+int verbose = 0;
 
 Dyninst::Address entryPoint;
 set < string > instrumentLibraries;
@@ -31,12 +40,16 @@ set < string > runtimeLibraries;
 set < string > skipAddresses;
 set < unsigned long > exitAddresses;
 unsigned int bbMinSize = 1;
-int bbSkip = 0;
-bool skipMainModule = false, do_bb = true, dynfix = false, performance = false;
+int bbSkip = 0, performance = 0;
+bool skipMainModule = false, do_bb = true, dynfix = false;
+unsigned long int insertions = 0;
+uintptr_t mapaddr = 0;
 
 BPatch_function *save_rdi;
 BPatch_function *restore_rdi;
 
+const char *functions[] = { "main", "_main", "_initproc", "_init", "start", "_start", NULL };
+
 const char *instLibrary = "libAflDyninst.so";
 
 static const char *OPT_STR = "fi:o:l:e:E:vs:dr:m:S:Dx";
@@ -50,7 +63,7 @@ static const char *USAGE = "-dfvxD -i <binary> -o <binary> -l <library> -e <addr
   -E: exit point - force exit(0) at this address (repeat for more than one)\n \
   -s: number of initial basic blocks to skip in binary\n \
   -m: minimum size of a basic bock to instrument (default: 1)\n \
-  -f: try to fix a dyninst bug that leads to crashes\n \
+  -f: try to fix a dyninst bug that leads to crashes (loss of 20%% performance)\n \
   -S: do not instrument this function (repeat for more than one)\n \
   -D: instrument only a simple fork server and also forced exit functions\n \
   -x: experimental performance mode\n \
@@ -62,13 +75,25 @@ bool parseOptions(int argc, char **argv) {
   while ((c = getopt(argc, argv, OPT_STR)) != -1) {
     switch ((char) c) {
     case 'x':
-      performance = true;
+      performance++;
+      if (performance == 3) {
+#if ( __amd64__ || __x86_64__ )
+        fprintf(stderr, "Warning: performance level 3 is currently totally experimental\n");
+#else
+        fprintf(stderr, "Warning: maximum performance level for non-intelx64 x86 is 2\n");
+        performance = 2;
+#endif
+      } else if (performance > 3) {
+        fprintf(stderr, "Warning: maximum performance level is 3\n");
+        performance = 3;
+      }
       break;
     case 'S':
       skipAddresses.insert(optarg);
       break;
     case 'e':
-      entryPoint = strtoul(optarg, NULL, 16);
+      if ((entryPoint = strtoul(optarg, NULL, 16)) < 0x1000)
+        entryPointName = optarg;
       break;
     case 'i':
       originalBinary = optarg;
@@ -96,13 +121,15 @@ bool parseOptions(int argc, char **argv) {
       skipMainModule = true;
       break;
     case 'f':
+#if (__amd64__ || __x86_64__)
       dynfix = true;
+#endif
       break;
     case 'D':
       do_bb = false;
       break;
     case 'v':
-      verbose = true;
+      verbose++;
       break;
     default:
       cerr << "Usage: " << argv[0] << USAGE;
@@ -110,6 +137,11 @@ bool parseOptions(int argc, char **argv) {
     }
   }
 
+  if (performance > 0 && do_bb == false) {
+    cerr << "Warning: -x performance options only enhance basic block coverage, not forkserver only mode" << endl;
+    performance = 0;
+  }
+
   if (originalBinary == NULL) {
     cerr << "Input binary is required!" << endl;
     cerr << "Usage: " << argv[0] << USAGE;
@@ -192,7 +224,7 @@ bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char
 
   BPatch_Set < BPatch_basicBlock * >::iterator iter;
   for (iter = allBlocks.begin(); iter != allBlocks.end(); iter++) {
-    if (*bbIndex < bbSkip || (*iter)->size() < bbMinSize) {    // skip over first bbSkip bbs
+    if (*bbIndex < bbSkip || (*iter)->size() < bbMinSize) {     // skip over first bbSkip bbs or below minimum size
       (*bbIndex)++;
       continue;
     }
@@ -232,7 +264,8 @@ bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char
       cerr << "Failed to insert instrumention in basic block at 0x" << hex << address << endl;
       (*bbIndex)++;
       continue;
-    }
+    } else
+      insertions++;
 
     (*bbIndex)++;
   }
@@ -241,6 +274,9 @@ bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char
 }
 
 int main(int argc, char **argv) {
+  char *func2patch = NULL;
+  int loop;
+
   if (argc < 3 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0) {
     cout << "Usage: " << argv[0] << USAGE;
     return false;
@@ -249,9 +285,10 @@ int main(int argc, char **argv) {
   if (!parseOptions(argc, argv)) {
     return EXIT_FAILURE;
   }
-  
+#if (__amd64__ || __x86_64__)
   if (do_bb == true) {
-    if (DYNINST_MAJOR_VERSION < 9 || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION < 3) || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION == 3 && DYNINST_PATCH_VERSION <= 2)) {
+    if (DYNINST_MAJOR_VERSION < 9 || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION < 3)
+        || (DYNINST_MAJOR_VERSION == 9 && DYNINST_MINOR_VERSION == 3 && DYNINST_PATCH_VERSION <= 2)) {
       if (dynfix == false)
         fprintf(stderr, "Warning: your dyninst version does not include a critical fix, you should use the -f option!\n");
     } else {
@@ -259,6 +296,7 @@ int main(int argc, char **argv) {
         fprintf(stderr, "Notice: your dyninst version is fixed, the -f option should not be necessary.\n");
     }
   }
+#endif
 
   BPatch bpatch;
   BPatch_binaryEdit *appBin = bpatch.openBinary(originalBinary, instrumentLibraries.size() != 1);
@@ -274,25 +312,34 @@ int main(int argc, char **argv) {
   vector < BPatch_module * >*modules = appImage->getModules();
   vector < BPatch_module * >::iterator moduleIter;
   vector < BPatch_function * >*funcsInModule;
-  BPatch_module *defaultModule = NULL;
+  BPatch_module *defaultModule = NULL, *firstModule = NULL;
   string defaultModuleName;
 
   // look for _init
   if (defaultModuleName.empty()) {
+    for (loop = 0; functions[loop] != NULL && func2patch == NULL; loop++) {
     for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) {
-      funcsInModule = (*moduleIter)->getProcedures();
       vector < BPatch_function * >::iterator funcsIterator;
+        char moduleName[1024];
+
+        if (firstModule == NULL)
+          firstModule = (*moduleIter);
+        (*moduleIter)->getName(moduleName, 1024);
+        funcsInModule = (*moduleIter)->getProcedures();
+        if (verbose >= 2)
+          cout << "Looking for init function " << functions[loop] << " in " << moduleName << endl;
       for (funcsIterator = funcsInModule->begin(); funcsIterator != funcsInModule->end(); ++funcsIterator) {
         char funcName[1024];
 
         (*funcsIterator)->getName(funcName, 1024);
-        if (string(funcName) == string("_init")) {
-          char moduleName[1024];
-
-          (*moduleIter)->getName(moduleName, 1024);
+          if (verbose >= 3 && loop == 0)
+            printf("module: %s function: %s\n", moduleName, funcName);
+          if (string(funcName) == string(functions[loop])) {
+            func2patch = (char *) functions[loop];
           defaultModuleName = string(moduleName);
-          if (verbose) {
-            cout << "Found _init in " << moduleName << endl;
+            defaultModule = (*moduleIter);
+            if (verbose >= 1) {
+              cout << "Found " << func2patch << " in " << moduleName << endl;
           }
           break;
         }
@@ -300,10 +347,15 @@ int main(int argc, char **argv) {
       if (!defaultModuleName.empty())
         break;
     }
+      if (func2patch != NULL)
+        break;
+    }
   }
   // last resort, by name of the binary
   if (defaultModuleName.empty())
     defaultModuleName = string(originalBinary).substr(string(originalBinary).find_last_of("\\/") + 1);
+  if (defaultModule == NULL)
+    defaultModule = firstModule;
 
   if (!appBin->loadLibrary(instLibrary)) {
     cerr << "Failed to open instrumentation library " << instLibrary << endl;
@@ -311,18 +363,20 @@ int main(int argc, char **argv) {
     return EXIT_FAILURE;
   }
 
-  appImage = appBin->getImage();
-
   /* Find code coverage functions in the instrumentation library */
   BPatch_function *initAflForkServer;
+
   save_rdi = findFuncByName(appImage, (char *) "save_rdi");
   restore_rdi = findFuncByName(appImage, (char *) "restore_rdi");
   BPatch_function *bbCallback = findFuncByName(appImage, (char *) "bbCallback");
   BPatch_function *forceCleanExit = findFuncByName(appImage, (char *) "forceCleanExit");
 
-  if (do_bb == true)
-    initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServer");
+  if (do_bb == true) {
+    if (performance >= 3)
+      initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServerVar");
   else
+      initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServer");
+  } else
     initAflForkServer = findFuncByName(appImage, (char *) "initOnlyAflForkServer");
 
   if (!initAflForkServer || !bbCallback || !save_rdi || !restore_rdi || !forceCleanExit) {
@@ -332,7 +386,77 @@ int main(int argc, char **argv) {
 
   int bbIndex = 0;
 
-  // instrument all shared libraries:
+  // if an entrypoint was set then find function, else find _init
+  BPatch_function *funcToPatch = NULL;
+
+  if (entryPoint == 0 && entryPointName == NULL) {
+    if (func2patch == NULL) {
+      cerr << "Couldn't locate _init, specify entry point manually with -e 0xaddr" << endl;
+      return EXIT_FAILURE;
+    }
+    BPatch_Vector < BPatch_function * >funcs;
+    defaultModule->findFunction(func2patch, funcs);
+    if (!funcs.size()) {
+      cerr << "Couldn't locate _init, specify entry point manually with -e 0xaddr" << endl;
+      return EXIT_FAILURE;
+    }
+    // there should really be only one
+    funcToPatch = funcs[0];
+  } else {
+    if (entryPointName != NULL) {
+      for (moduleIter = modules->begin(); moduleIter != modules->end() && funcToPatch == 0; ++moduleIter) {
+        BPatch_Vector < BPatch_function * >funcs;
+        (*moduleIter)->findFunction(entryPointName, funcs);
+        if (funcs.size() > 0) {
+          char moduleName[1024];
+
+          funcToPatch = funcs[0];
+          defaultModule = (*moduleIter);
+          defaultModule->getName(moduleName, 1024);
+          defaultModuleName = string(moduleName);
+          printf("Found entypoint %s in module %s\n", entryPointName, moduleName);
+          break;
+        }
+      }
+    }
+    if (!funcToPatch) {
+      if (verbose > 1)
+        printf("Looking for entrypoint %p\n", (char *) entryPoint);
+      funcToPatch = defaultModule->findFunctionByEntry(entryPoint);
+      if (!funcToPatch && defaultModule != firstModule) {
+        funcToPatch = firstModule->findFunctionByEntry(entryPoint);
+        if (funcToPatch)
+          defaultModule = firstModule;
+      }
+      if (!funcToPatch) {       // ok lets go hardcore ...
+        if (verbose > 1)
+          printf("OK we did not find the entrypoint so far, lets dig deeper ...\n");
+        for (moduleIter = modules->begin(); moduleIter != modules->end() && funcToPatch != NULL; ++moduleIter) {
+          vector < BPatch_function * >::iterator funcsIterator;
+          funcToPatch = (*moduleIter)->findFunctionByEntry(entryPoint);
+          if (funcToPatch)
+            defaultModule = (*moduleIter);
+        }
+      }
+      if (funcToPatch && verbose >= 1) {
+        char moduleName[1024];
+
+        defaultModule->getName(moduleName, 1024);
+        defaultModuleName = string(moduleName);
+        printf("Found entypoint %p in module %s\n", (void *) entryPoint, moduleName);
+      }
+    }
+  }
+  if (!funcToPatch) {
+    cerr << "Couldn't locate function at given entry point. " << endl;
+    cerr << "Try: readelf -ls " << originalBinary << " | egrep 'Entry|FUNC.*GLOBAL.*DEFAULT' | egrep -v '@|UND'" << endl;
+    return EXIT_FAILURE;
+  }
+  if (!insertCallToInit(appBin, initAflForkServer, defaultModule, funcToPatch)) {
+    cerr << "Could not insert init callback at given entry point." << endl;
+    return EXIT_FAILURE;
+  }
+
   for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) {
     char moduleName[1024];
 
@@ -346,7 +470,6 @@ int main(int argc, char **argv) {
     }
 
     if (string(moduleName).find(defaultModuleName) != string::npos) {
-      defaultModule = (*moduleIter);
       if (skipMainModule)
         continue;
     }
@@ -363,9 +486,9 @@ int main(int argc, char **argv) {
         int do_patch = 1;
 
         curFunc->getName(funcName, 1024);
-        if (string(funcName) == string("_start"))
+        if (string(funcName) == string("_init") || string(funcName) == string("__libc_csu_init") || string(funcName) == string("_start")
+          )
           continue;               // here's a bug on hlt // XXX: check what happens if removed
-        
         if (!skipAddresses.empty()) {
           set < string >::iterator saiter;
           for (saiter = skipAddresses.begin(); saiter != skipAddresses.end() && do_patch == 1; saiter++)
@@ -381,30 +504,6 @@ int main(int argc, char **argv) {
     }
   }
 
-  // if an entrypoint was set then find function, else find _init
-  BPatch_function *funcToPatch = NULL;
-
-  if (!entryPoint) {
-    BPatch_Vector < BPatch_function * >funcs;
-    defaultModule->findFunction("_init", funcs);
-    if (!funcs.size()) {
-      cerr << "Couldn't locate _init, specify entry point manually with -e 0xaddr" << endl;
-      return EXIT_FAILURE;
-    }
-    // there should really be only one
-    funcToPatch = funcs[0];
-  } else {
-    funcToPatch = defaultModule->findFunctionByEntry(entryPoint);
-  }
-  if (!funcToPatch) {
-    cerr << "Couldn't locate function at given entry point. " << endl;
-    return EXIT_FAILURE;
-  }
-  if (!insertCallToInit(appBin, initAflForkServer, defaultModule, funcToPatch)) {
-    cerr << "Could not insert init callback at given entry point." << endl;
-    return EXIT_FAILURE;
-  }
-
   if (!exitAddresses.empty()) {
     cout << "Instrumenting forced exit addresses." << endl;
     set < unsigned long >::iterator uliter;
@@ -442,10 +541,8 @@ int main(int argc, char **argv) {
 
       vector < BPatch_module * >*modules = libImg->getModules();
       moduleIter = modules->begin();
-
       for (; moduleIter != modules->end(); ++moduleIter) {
         char moduleName[1024];
-
         (*moduleIter)->getName(moduleName, 1024);
         cout << "Instrumenting module: " << moduleName << endl;
         vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures();
@@ -454,10 +551,22 @@ int main(int argc, char **argv) {
         for (funcIter = allFunctions->begin(); funcIter != allFunctions->end(); ++funcIter) {
           BPatch_function *curFunc = *funcIter;
           char funcName[1024];
+          int do_patch = 1;
 
           curFunc->getName(funcName, 1024);
-          if (string(funcName) == string("_start"))
+          if (string(funcName) == string("_init") || string(funcName) == string("__libc_csu_init") || string(funcName) == string("_start"))
             continue;
+          if (!skipAddresses.empty()) {
+            set < string >::iterator saiter;
+            for (saiter = skipAddresses.begin(); saiter != skipAddresses.end() && do_patch == 1; saiter++)
+              if (*saiter == string(funcName))
+                do_patch = 0;
+            if (do_patch == 0) {
+              cout << "Skipping instrumenting function " << funcName << endl;
+             continue;
+            }
+          }
+
           insertBBCallback(libBin, curFunc, funcName, bbCallback, &bbIndex);
         }
       }
@@ -470,6 +579,7 @@ int main(int argc, char **argv) {
     }
   }
 
+  printf("Did a total of %lu basic block insertions\n", insertions);
   cout << "All done! Happy fuzzing!" << endl;
   return EXIT_SUCCESS;
 }
diff --git a/afl-fuzz-dyninst.sh b/afl-fuzz-dyninst.sh
index bb10a95..b5370cb 100755
--- a/afl-fuzz-dyninst.sh
+++ b/afl-fuzz-dyninst.sh
@@ -1,5 +1,8 @@
 #!/bin/bash
 test -z "$1" -o "$1" = "-h" && { echo Syntax: $0 afl-fuzz-options ; echo sets the afl-dyninst environment variables ; exit 1 ; }
+sysctl -w kernel.core_pattern="core" > /dev/null
+sysctl -w kernel.randomize_va_space=0 > /dev/null
+echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null
 export AFL_SKIP_BIN_CHECK=1
 export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
diff --git a/libAflDyninst.cpp b/libAflDyninst.cpp
index d556a22..fb0ba9c 100644
--- a/libAflDyninst.cpp
+++ b/libAflDyninst.cpp
@@ -14,17 +14,25 @@
 
 using namespace std;
 
-static u8 *trace_bits;
+static u8 dummy[65536];
+static u8 *trace_bits = dummy; // this saves a test + jz instruction
 static s32 shm_id;
 static int __afl_temp_data;
 static pid_t __afl_fork_pid;
-static unsigned short prev_id;
+static unsigned short int prev_id = 0;
+static bool forkserver_installed = false;
+#if (__amd64__ || __x86_64__)
 static long saved_di;
 register long rdi asm("di");  // the warning is fine - we need the warning because of a bug in dyninst
+#endif
 
 #define PRINT_ERROR(string) (void)(write(2, string, strlen(string))+1) // the (...+1) weirdness is so we do not get an ignoring return value warning
 
 void initAflForkServer() {
+  if (forkserver_installed == true)
+    return;
+  forkserver_installed = true;
+  
   // we can not use fprint* stdout/stderr functions here, it fucks up some programs
   char *shm_env_var = getenv(SHM_ENV_VAR);
 
@@ -60,6 +68,7 @@ void initAflForkServer() {
     if (__afl_fork_pid == 0) {
       close(FORKSRV_FD);
       close(FORKSRV_FD + 1);
+      prev_id = 0;
       break;
     } else {
       // parrent stuff
@@ -76,10 +85,8 @@ void initAflForkServer() {
 
 // Should be called on basic block entry
 void bbCallback(unsigned short id) {
-  if (trace_bits) {
-    trace_bits[prev_id ^ id]++;
-    prev_id = id >> 1;
-  }
+  trace_bits[prev_id ^ id]++;
+  prev_id = id >> 1;
 }
 
 void forceCleanExit() {
@@ -87,15 +94,22 @@ void forceCleanExit() {
 }
 
 void save_rdi() {
+#if __amd64__ || __x86_64__
   saved_di = rdi;
+#endif
 }
 
 void restore_rdi() {
+#if __amd64__ || __x86_64__
   rdi = saved_di;
+#endif
 }
 
-
 void initOnlyAflForkServer() {
+  if (forkserver_installed == true)
+    return;
+  forkserver_installed = true;
+
   // enter fork() server thyme!
   int n = write(FORKSRV_FD + 1, &__afl_temp_data, 4);
 
@@ -118,6 +132,67 @@ void initOnlyAflForkServer() {
     if (__afl_fork_pid == 0) {
       close(FORKSRV_FD);
       close(FORKSRV_FD + 1);
+      prev_id = 0;
+      break;
+    } else {
+      // parrent stuff
+      n = write(FORKSRV_FD + 1, &__afl_fork_pid, 4);
+      pid_t temp_pid = waitpid(__afl_fork_pid, &__afl_temp_data, 2);
+
+      if (temp_pid == 0) {
+        return;
+      }
+      n = write(FORKSRV_FD + 1, &__afl_temp_data, 4);
+    }
+  }
+}
+
+
+void initAflForkServerVar(u8 *map) {
+  // we can not use fprint* stdout/stderr functions here, it fucks up some programs
+  if (forkserver_installed == true)
+    return;
+  forkserver_installed = true;
+
+  u8 **ptr = (u8**) map;
+  char *shm_env_var = getenv(SHM_ENV_VAR);
+  if (!shm_env_var) {
+    char buf[256];
+    PRINT_ERROR("Error getting shm\n");
+    snprintf(buf, sizeof(buf), "trace_bits: %p\n", ptr);
+    PRINT_ERROR(buf);
+    return;
+  }
+
+  shm_id = atoi(shm_env_var);
+  *ptr = (u8*)shmat(shm_id, NULL, 0);
+  if ((u8*)*ptr == (u8 *) - 1) {
+    PRINT_ERROR("Error: shmat\n");
+    return;
+  }
+  // enter fork() server thyme!
+  int n = write(FORKSRV_FD + 1, &__afl_temp_data, 4);
+
+  if (n != 4) {
+    PRINT_ERROR("Error writing fork server\n");
+    return;
+  }
+  while (1) {
+    n = read(FORKSRV_FD, &__afl_temp_data, 4);
+    if (n != 4) {
+      PRINT_ERROR("Error reading fork server\n");
+      return;
+    }
+
+    __afl_fork_pid = fork();
+    if (__afl_fork_pid < 0) {
+      PRINT_ERROR("Error on fork()\n");
+      return;
+    }
+    if (__afl_fork_pid == 0) {
+      close(FORKSRV_FD);
+      close(FORKSRV_FD + 1);
+      prev_id = 0;
       break;
     } else {
       // parrent stuff