about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--Makefile14
-rw-r--r--README.txt15
-rw-r--r--afl-dyninst.cpp239
4 files changed, 221 insertions, 53 deletions
diff --git a/CHANGES b/CHANGES
index b5ff722..16cbeb2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,9 +2,13 @@ Changelog
 =========
 
 https://github.com/vanhauser-thc/afl-dyninst
+ - added -x performance optimization options, before this afl-dyninst was meh,
+   now it is OK. It supports 3 levels: -x (+45%, -xx additional +45%,
+    -xxx additional ~3% but so far only on intel x64)
+   top speed is now ~110% on stock afl-dyninst and ~65% on stock afl-gcc
  - -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 :)
+ - afl-dyninst now works fine with AARCH64 and PPC :)
  - more verbose output, -vv -vvv support
  - fixed some typos
  - renamed afl-fuzz.sh to afl-fuzz-dyninst.sh and make install
diff --git a/Makefile b/Makefile
index f48af58..8ed2c0b 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ DEPS_ROOT = /usr/local
 INSTALL_ROOT = /usr/local
 
 CXX = g++
-CXXFLAGS = -g -Wall -O3 -std=c++11
+CXXFLAGS = -Wall -O3 -std=c++11 -g
 LIBFLAGS = -fpic -shared
 
 CC = gcc
@@ -19,6 +19,7 @@ CFLAGS = -Wall -pedantic -g -std=gnu99
 
 
 all: afl-dyninst libAflDyninst.so
+# afl-dyninst2 
 
 afl-dyninst: afl-dyninst.o
 	$(CXX) $(CXXFLAGS) -L$(DYNINST_ROOT)/lib \
@@ -28,12 +29,23 @@ afl-dyninst: afl-dyninst.o
 		-liberty \
 		-ldyninstAPI 
 
+afl-dyninst2: afl-dyninst2.o
+	$(CXX) $(CXXFLAGS) -L$(DYNINST_ROOT)/lib \
+		-L$(DEPS_ROOT)/lib \
+		-o afl-dyninst2 afl-dyninst2.o \
+		-lcommon \
+		-liberty \
+		-ldyninstAPI 
+
 libAflDyninst.so: libAflDyninst.cpp
 	$(CXX) $(CXXFLAGS) $(LIBFLAGS) -I$(AFL_ROOT) -I$(DEPS_ROOT)/include libAflDyninst.cpp -o libAflDyninst.so
 
 afl-dyninst.o: afl-dyninst.cpp
 	$(CXX) $(CXXFLAGS) -I$(DEPS_ROOT)/include -I$(DYNINST_ROOT)/include  -c afl-dyninst.cpp
 
+afl-dyninst2.o: afl-dyninst2.cpp
+	$(CXX) $(CXXFLAGS) -I$(DEPS_ROOT)/include -I$(DYNINST_ROOT)/include  -c afl-dyninst2.cpp
+
 clean:
 	rm -f afl-dyninst *.so *.o 
 
diff --git a/README.txt b/README.txt
index 7d99e3d..7b7868c 100644
--- a/README.txt
+++ b/README.txt
@@ -25,6 +25,12 @@ Usage: ./afl-dyninst-dfvD -i <binary> -o <binary> -l <library> -e <address> -E <
    -f: try to fix a dyninst bug that leads to crashes
    -S: do not instrument this function (repeat for more than one)
    -D: instrument fork server and forced exit functions but no basic blocks
+   -x: experimental performance modes (can be set up to three times)
+         level 1: ~40-50%% improvement
+         level 2: ~100%% vs normal, ~40%% vs level 1
+         level 3: ~110%% vs normal, ~5%% vs level 2
+       level 3 replaces how basic block coverage works and can be tried if
+       normal mode or level 1 or 2 lead to crashes randomly.
    -v: verbose output
 
 Switch -l is used to supply the names of the libraries that should 
@@ -72,6 +78,15 @@ basic block instrumentation. That would serve no purpose - unless there is
 another interesting tool coming up: afl-pin (already available at
 https://github.com/vanhauser-thc/afl-pin) and afl-dynamorio (wip)
 
+Switch -x enables performance modes, -x level 1, -xx level 2 and  -xxx level 3
+level 3 is only availble for intel x64 and can either save your ass or not
+work for you whatsoever.
+level 1 (-x) is highly recommended (+50%).
+level 2 (-xx) gives an additonal 40% but removes (usually unnecessary) precautions
+level 3 (-xxx) gives only a very small additional speed and works differently,
+ it basically replaces the instrumented instructions by dyninst with own ones.
+ this is a good idea when you run into dyninst bugs.
+
 
 Compiling:
 ----------
diff --git a/afl-dyninst.cpp b/afl-dyninst.cpp
index b908b24..4ff3edb 100644
--- a/afl-dyninst.cpp
+++ b/afl-dyninst.cpp
@@ -35,6 +35,7 @@ char *entryPointName = NULL;
 int verbose = 0;
 
 Dyninst::Address entryPoint;
+set < string > todo;
 set < string > instrumentLibraries;
 set < string > runtimeLibraries;
 set < string > skipAddresses;
@@ -66,7 +67,12 @@ static const char *USAGE = "-dfvxD -i <binary> -o <binary> -l <library> -e <addr
   -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 \
+  -x: experimental performance modes (can be set up to three times)\n \
+        level 1: ~40-50%% improvement\n \
+        level 2: ~100%% vs normal, ~40%% vs level 1\n \
+        level 3: ~110%% vs normal, ~5%% vs level 2\n \
+      level 3 replaces how basic block coverage works and can be tried if\n \
+      normal mode or level 1 or 2 lead to crashes randomly.\n \
   -v: verbose output\n";
 
 bool parseOptions(int argc, char **argv) {
@@ -177,23 +183,48 @@ BPatch_function *findFuncByName(BPatch_image * appImage, char *funcName) {
 
 // insert callback to initialization function in the instrumentation library
 // either at _init or at manualy specified entry point.
-bool insertCallToInit(BPatch_binaryEdit *appBin, BPatch_function *instIncFunc, BPatch_module *module, BPatch_function *funcInit) {
+bool insertCallToInit(BPatch_addressSpace * appBin, BPatch_function * instIncFunc, BPatch_module * module, BPatch_function * funcInit, bool install_hack) {
   /* Find the instrumentation points */
   vector < BPatch_point * >points;
   vector < BPatch_point * >*funcEntry = funcInit->findPoint(BPatch_entry);
+  BPatch_image *appImage = appBin->getImage();
+  BPatchSnippetHandle *handle;
 
   if (NULL == funcEntry) {
     cerr << "Failed to find entry for function. " << endl;
     return false;
   }
 
-  cout << "Inserting init callback." << endl;
-  BPatch_Vector < BPatch_snippet * >instArgs;   // init has no args
-  BPatch_funcCallExpr instIncExpr(*instIncFunc, instArgs);
+  if (performance >= 3 && install_hack == true) {
+    cout << "Inserting global variables" << endl;
+    // we set up a fake map so we do not have crashes if the the forkserver
+    // is not installed in _init but later for speed reasons.
+    // we could also check in the bb() code if map == 0 but that would
+    // cost precious instructions.
+    BPatch_variableExpr *fakemap = appBin->malloc(65536);
+    BPatch_constExpr fakemap_ptr(fakemap->getBaseAddr());
+    BPatch_variableExpr *map = appBin->malloc(*(appImage->findType("size_t")), "map");
+    BPatch_arithExpr initmap(BPatch_assign, *map, fakemap_ptr);
+
+    appBin->insertSnippet(initmap, *funcEntry, BPatch_firstSnippet);
+    BPatch_constExpr map_ptr(map->getBaseAddr());
+    BPatch_variableExpr *prev_id = appBin->malloc(*(appImage->findType("size_t")), "prev_id");
+    BPatch_arithExpr initprevid(BPatch_assign, *prev_id, BPatch_constExpr(0));
+
+    appBin->insertSnippet(initprevid, *funcEntry);
+    BPatch_Vector < BPatch_snippet * >instArgs;
+    cout << "Inserting init callback." << endl;
+    instArgs.push_back(&map_ptr);
+    BPatch_funcCallExpr instIncExpr(*instIncFunc, instArgs);
+
+    handle = appBin->insertSnippet(instIncExpr, *funcEntry, BPatch_callBefore, BPatch_lastSnippet);
+  } else {
+    BPatch_Vector < BPatch_snippet * >instArgs;
+    cout << "Inserting init callback." << endl;
+    BPatch_funcCallExpr instIncExpr(*instIncFunc, instArgs);
 
-  /* Insert the snippet at function entry */
-  BPatchSnippetHandle *handle = appBin->insertSnippet(instIncExpr, *funcEntry, BPatch_callBefore,
-                                                      BPatch_lastSnippet);
+    handle = appBin->insertSnippet(instIncExpr, *funcEntry, BPatch_callBefore, BPatch_lastSnippet);
+  }
 
   if (!handle) {
     cerr << "Failed to insert init callback." << endl;
@@ -204,7 +235,8 @@ bool insertCallToInit(BPatch_binaryEdit *appBin, BPatch_function *instIncFunc, B
 
 // inserts a callback for each basic block assigning it an instrumentation
 // time 16bit random ID just as afl
-bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char *funcName, BPatch_function *instBBIncFunc, int *bbIndex) {
+bool insertBBCallback(BPatch_addressSpace * appBin, BPatch_function * curFunc, char *funcName, BPatch_function * instBBIncFunc, int *bbIndex) {
+  BPatch_image *appImage = appBin->getImage();
   BPatch_flowGraph *appCFG = curFunc->getCFG();
   unsigned short randID;
 
@@ -228,19 +260,33 @@ bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char
       (*bbIndex)++;
       continue;
     }
-    unsigned long address = (*iter)->getStartAddress();
 
-    randID = rand() % USHRT_MAX;
-    if (verbose) {
-      cout << "Instrumenting Basic Block 0x" << hex << address << " of " << funcName << " with size " << dec << (*iter)->size() << " with random id " << randID << "/0x" << hex << randID << endl;
+    BPatch_point *bbEntry = (*iter)->findEntryPoint();
+
+    if (performance >= 1) {
+      if ((*iter)->isEntryBlock() == false) {
+        bool good = false;
+
+        BPatch_Vector < BPatch_basicBlock * >sources;
+        (*iter)->getSources(sources);
+        for (unsigned int i = 0; i < sources.size() && good == false; i++) {
+          BPatch_Vector < BPatch_basicBlock * >targets;
+          sources[i]->getTargets(targets);
+          if (targets.size() > 1)
+            good = true;
+        }
+        if (good == false)
+          continue;
+      }
     }
 
-    BPatch_Vector < BPatch_snippet * >instArgs1;
-    BPatch_Vector < BPatch_snippet * >instArgs;
-    BPatch_constExpr bbId(randID);
+    unsigned long address = (*iter)->getStartAddress();
 
-    instArgs.push_back(&bbId);
-    BPatch_point *bbEntry = (*iter)->findEntryPoint();
+    randID = rand() % USHRT_MAX;
+    if (verbose >= 1) {
+      cout << "Instrumenting Basic Block 0x" << hex << address << " of " << funcName << " with size " << dec << (*iter)->size() << " with random id " << randID << "/0x" << hex <<
+        randID << endl;
+    }
 
     if (NULL == bbEntry) {
       // warn the user, but continue
@@ -249,15 +295,39 @@ bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char
       continue;
     }
 
-    BPatch_funcCallExpr instIncExpr1(*save_rdi, instArgs1);
-    BPatch_funcCallExpr instIncExpr3(*restore_rdi, instArgs1);
-    BPatch_funcCallExpr instIncExpr(*instBBIncFunc, instArgs);
     BPatchSnippetHandle *handle;
-    if (dynfix == true)
-      handle = appBin->insertSnippet(instIncExpr1, *bbEntry, BPatch_callBefore, BPatch_lastSnippet);
-    handle = appBin->insertSnippet(instIncExpr, *bbEntry, BPatch_callBefore, BPatch_lastSnippet);
-    if (dynfix == true)
-      handle = appBin->insertSnippet(instIncExpr3, *bbEntry, BPatch_callBefore, BPatch_lastSnippet);
+
+    if (performance >= 3) {
+      // these are dummy instructions we overwrite later
+      BPatch_variableExpr *pid = appImage->findVariable("prev_id");
+      BPatch_arithExpr new_prev_id(BPatch_assign, *pid, BPatch_arithExpr(BPatch_divide, BPatch_constExpr(8), BPatch_constExpr(2)));
+
+      handle = appBin->insertSnippet(new_prev_id, *bbEntry, BPatch_lastSnippet);
+      BPatch_variableExpr *map = appImage->findVariable("map");
+      BPatch_variableExpr *pid2 = appImage->findVariable("prev_id");
+      BPatch_arithExpr map_idx(BPatch_arithExpr(BPatch_plus, *map, BPatch_arithExpr(BPatch_divide, *pid2, BPatch_constExpr(2))));
+
+      if (mapaddr == 0) {
+        printf("Map for AFL is installed at: %p\n", (void *) map->getBaseAddr());
+        mapaddr = (uintptr_t) map->getBaseAddr();
+      }
+      handle = appBin->insertSnippet(map_idx, *bbEntry, BPatch_firstSnippet);
+    } else {
+      BPatch_Vector < BPatch_snippet * >instArgs1;
+      BPatch_Vector < BPatch_snippet * >instArgs;
+      BPatch_constExpr bbId(randID);
+
+      instArgs.push_back(&bbId);
+      BPatch_funcCallExpr instIncExpr1(*save_rdi, instArgs1);
+      BPatch_funcCallExpr instIncExpr3(*restore_rdi, instArgs1);
+      BPatch_funcCallExpr instIncExpr(*instBBIncFunc, instArgs);
+
+      if (dynfix == true)
+        handle = appBin->insertSnippet(instIncExpr1, *bbEntry, BPatch_callBefore, BPatch_firstSnippet);
+      handle = appBin->insertSnippet(instIncExpr, *bbEntry, BPatch_callBefore);
+      if (dynfix == true)
+        handle = appBin->insertSnippet(instIncExpr3, *bbEntry, BPatch_callBefore, BPatch_lastSnippet);
+    }
 
     if (!handle) {
       // warn the user, but continue to next bb
@@ -299,7 +369,13 @@ int main(int argc, char **argv) {
 #endif
 
   BPatch bpatch;
-  BPatch_binaryEdit *appBin = bpatch.openBinary(originalBinary, instrumentLibraries.size() != 1);
+
+  if (performance >= 2) {
+    bpatch.setSaveFPR(false);
+    bpatch.setTrampRecursive(true);
+  }
+
+  BPatch_addressSpace *appBin = bpatch.openBinary(originalBinary, instrumentLibraries.size() != 1);
 
   if (appBin == NULL) {
     cerr << "Failed to open binary" << endl;
@@ -318,8 +394,8 @@ int main(int argc, char **argv) {
   // look for _init
   if (defaultModuleName.empty()) {
     for (loop = 0; functions[loop] != NULL && func2patch == NULL; loop++) {
-    for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) {
-      vector < BPatch_function * >::iterator funcsIterator;
+      for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) {
+        vector < BPatch_function * >::iterator funcsIterator;
         char moduleName[1024];
 
         if (firstModule == NULL)
@@ -328,25 +404,25 @@ int main(int argc, char **argv) {
         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];
+        for (funcsIterator = funcsInModule->begin(); funcsIterator != funcsInModule->end(); ++funcsIterator) {
+          char funcName[1024];
 
-        (*funcsIterator)->getName(funcName, 1024);
+          (*funcsIterator)->getName(funcName, 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);
+            defaultModuleName = string(moduleName);
             defaultModule = (*moduleIter);
             if (verbose >= 1) {
               cout << "Found " << func2patch << " in " << moduleName << endl;
+            }
+            break;
           }
-          break;
         }
+        if (!defaultModuleName.empty())
+          break;
       }
-      if (!defaultModuleName.empty())
-        break;
-    }
       if (func2patch != NULL)
         break;
     }
@@ -374,7 +450,7 @@ int main(int argc, char **argv) {
   if (do_bb == true) {
     if (performance >= 3)
       initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServerVar");
-  else
+    else
       initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServer");
   } else
     initAflForkServer = findFuncByName(appImage, (char *) "initOnlyAflForkServer");
@@ -452,7 +528,7 @@ int main(int argc, char **argv) {
     cerr << "Try: readelf -ls " << originalBinary << " | egrep 'Entry|FUNC.*GLOBAL.*DEFAULT' | egrep -v '@|UND'" << endl;
     return EXIT_FAILURE;
   }
-  if (!insertCallToInit(appBin, initAflForkServer, defaultModule, funcToPatch)) {
+  if (!insertCallToInit(appBin, initAflForkServer, defaultModule, funcToPatch, true)) {
     cerr << "Could not insert init callback at given entry point." << endl;
     return EXIT_FAILURE;
   }
@@ -461,7 +537,6 @@ int main(int argc, char **argv) {
     char moduleName[1024];
 
     (*moduleIter)->getName(moduleName, 1024);
-
     if ((*moduleIter)->isSharedLib()) {
       if (instrumentLibraries.find(moduleName) == instrumentLibraries.end()) {
         cout << "Skipping library: " << moduleName << endl;
@@ -473,12 +548,11 @@ int main(int argc, char **argv) {
       if (skipMainModule)
         continue;
     }
-    
+
     if (do_bb == true) {
       cout << "Instrumenting module: " << moduleName << endl;
       vector < BPatch_function * >*allFunctions = (*moduleIter)->getProcedures();
       vector < BPatch_function * >::iterator funcIter;
-
       // iterate over all functions in the module
       for (funcIter = allFunctions->begin(); funcIter != allFunctions->end(); ++funcIter) {
         BPatch_function *curFunc = *funcIter;
@@ -488,7 +562,7 @@ int main(int argc, char **argv) {
         curFunc->getName(funcName, 1024);
         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
+          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++)
@@ -507,13 +581,14 @@ int main(int argc, char **argv) {
   if (!exitAddresses.empty()) {
     cout << "Instrumenting forced exit addresses." << endl;
     set < unsigned long >::iterator uliter;
+
     for (uliter = exitAddresses.begin(); uliter != exitAddresses.end(); uliter++) {
-      if (*uliter > 0 && (signed long)*uliter != -1) {
+      if (*uliter > 0 && (signed long) *uliter != -1) {
         funcToPatch = defaultModule->findFunctionByEntry(*uliter);
         if (!funcToPatch) {
           cerr << "Could not find enty point 0x" << hex << *uliter << " (continuing)" << endl;
         } else {
-          if (!insertCallToInit(appBin, forceCleanExit, defaultModule, funcToPatch))
+          if (!insertCallToInit(appBin, forceCleanExit, defaultModule, funcToPatch, false))
             cerr << "Could not insert force clean exit callback at 0x" << hex << *uliter << " (continuing)" << endl;
         }
       }
@@ -522,16 +597,19 @@ int main(int argc, char **argv) {
 
   cout << "Saving the instrumented binary to " << instrumentedBinary << " ..." << endl;
   // Output the instrumented binary
-  if (!appBin->writeFile(instrumentedBinary)) {
+  BPatch_binaryEdit *appBinr = dynamic_cast < BPatch_binaryEdit * >(appBin);
+
+  if (!appBinr->writeFile(instrumentedBinary)) {
     cerr << "Failed to write output file: " << instrumentedBinary << endl;
     return EXIT_FAILURE;
   }
-
+  todo.insert(instrumentedBinary);
+  
   if (!runtimeLibraries.empty()) {
     cout << "Instrumenting runtime libraries." << endl;
     set < string >::iterator rtLibIter;
     for (rtLibIter = runtimeLibraries.begin(); rtLibIter != runtimeLibraries.end(); rtLibIter++) {
-      BPatch_binaryEdit *libBin = bpatch.openBinary((*rtLibIter).c_str(), false);
+      BPatch_addressSpace *libBin = bpatch.openBinary((*rtLibIter).c_str(), false);
 
       if (libBin == NULL) {
         cerr << "Failed to open binary " << *rtLibIter << endl;
@@ -543,6 +621,7 @@ int main(int argc, char **argv) {
       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();
@@ -563,23 +642,81 @@ int main(int argc, char **argv) {
                 do_patch = 0;
             if (do_patch == 0) {
               cout << "Skipping instrumenting function " << funcName << endl;
-             continue;
+              continue;
             }
           }
 
           insertBBCallback(libBin, curFunc, funcName, bbCallback, &bbIndex);
         }
       }
-      if (!libBin->writeFile((*rtLibIter + ".ins").c_str())) {
+      appBinr = dynamic_cast < BPatch_binaryEdit * >(libBin);
+      if (!appBinr->writeFile((*rtLibIter + ".ins").c_str())) {
         cerr << "Failed to write output file: " << (*rtLibIter + ".ins").c_str() << endl;
         return EXIT_FAILURE;
       } else {
         cout << "Saved the instrumented library to " << (*rtLibIter + ".ins").c_str() << "." << endl;
+        todo.insert(*rtLibIter + ".ins");
       }
     }
   }
-
+  
   printf("Did a total of %lu basic block insertions\n", insertions);
+  
+  if (performance >= 3) {
+    int fd;
+    struct stat st;
+    uint64_t i, found = 0;
+    unsigned char *ptr;
+
+    unsigned char snip1[] = {
+      0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    unsigned char snip2[] = {
+      0x08, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    unsigned char fullsnip[] = {
+      0x53, 0x50, 0x41, 0x52, 0x48, 0xBB, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x03, 0x48, 0x85, 0xc0, 0x74, 0x28, 0x49, 0xBA, 0x08, 0x00, 0x71, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x66, 0x41, 0x8b, 0x1a, 0x66, 0x81, 0xf3, 0x99, 0x99, 0x48, 0x0f, 0xb7, 0xdb, 0x80, 0x04, 0x18, 0x01, 0x66, 0x41, 0x8b, 0x1a, 0x66, 0xd1, 0xfb,
+      0x66, 0x41, 0x89, 0x1a,
+      0x41, 0x5a, 0x58, 0x5b, 0x90, 0x90, 0x90, 0x90
+    };
+    memcpy(snip1, (char *) &mapaddr, sizeof(mapaddr));
+    memcpy(fullsnip + 6, (char *) &mapaddr, sizeof(mapaddr));
+    mapaddr += sizeof(mapaddr);
+    memcpy(snip2, (char *) &mapaddr, sizeof(mapaddr));
+    memcpy(fullsnip + 24, (char *) &mapaddr, sizeof(mapaddr));
+    set < string >::iterator fn;
+    for (fn = todo.begin(); fn != todo.end(); fn++) {
+      cout << "Reinstrumenting " << *fn << " ..." << endl;
+      if ((fd = open((const char *) (fn->c_str()), O_RDWR)) == -1 || fstat(fd, &st) != 0) {
+        cerr << "Error: file is gone: " << *fn << endl;
+        exit(-1);
+      }
+      if ((size_t) st.st_size < (size_t) sizeof(fullsnip)) {
+        cerr << "Error: somethings horrible wrong here with " << *fn << " ..." << endl;
+        continue;
+      }
+      ptr = (unsigned char *) mmap(NULL, st.st_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
+      for (i = 2; i < (size_t) st.st_size - (size_t) sizeof(fullsnip); i++) {
+        if (memcmp(ptr + i, snip1, sizeof(snip1)) == 0 && memcmp(ptr + i + sizeof(snip1) + 4, snip2, sizeof(snip2)) == 0) {
+          found++;
+          fullsnip[0x27] = rand() % 256;
+          fullsnip[0x28] = rand() % 256;
+          memcpy(ptr + i - 2, fullsnip, sizeof(fullsnip));
+        }
+      }
+      //printf("found %lu entries, snipsize %u\n", found, (unsigned int)sizeof(fullsnip));
+      munmap((void *) ptr, st.st_size);
+      close(fd);
+    }
+    if (found == insertions) {
+      printf("SUCCESS! Performance level 3 succeeded :)\n");
+    } else {
+      fprintf(stderr, "Error: can not complete performance level 3, could not find all insertions (%lu of %lu).\n", found, insertions);
+      exit(-1);
+    }
+  }
+
   cout << "All done! Happy fuzzing!" << endl;
   return EXIT_SUCCESS;
 }