diff options
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | CHANGES | 12 | ||||
-rw-r--r-- | README.txt | 25 | ||||
-rw-r--r-- | afl-dyninst.cpp | 642 | ||||
-rwxr-xr-x | afl-dyninst.sh | 3 | ||||
-rwxr-xr-x | afl-fuzz.sh | 6 | ||||
-rw-r--r-- | libAflDyninst.cpp | 119 |
7 files changed, 438 insertions, 371 deletions
diff --git a/AUTHORS b/AUTHORS index 8870664..3143e27 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,4 +2,6 @@ This code was developed as part of a project with the Cisco Talos VULNDEV Team Authors: Aleksandar Nikolic <anikolich@sourcefire.com> +Fixes: + van Hauser <vh@thc.org> diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..2d25c88 --- /dev/null +++ b/CHANGES @@ -0,0 +1,12 @@ +Changelog +========= + +vh@thc.org / https://github.com/vanhauser-thc/afl-dyninst: + - added -f switch to fix a bug in dyninst where sometimes the edi/rdi + register is not saved which is used in the instrumentation function + when a function is using edi/rdi for parameter passing + - added -m switch to only instrument basic blocks of a minimum size + - code beautifications, more detailed output, spelling fixes + - added afl-dyninst.sh and afl-fuzz.sh helper scripts which presets + the necessary environment variables + - took over from https://github.com/talos-vulndev/afl-dyninst diff --git a/README.txt b/README.txt index 6f5764a..adecc8b 100644 --- a/README.txt +++ b/README.txt @@ -9,13 +9,15 @@ inserting callbacks for each basic block and an initialization callback either at _init or at specified entry point. Usage: ./afl-dyninst -i <binary> -o <binary> -l <library> -e <address> -s <number> - -i: Input binary - -o: Output binary - -l: Library to instrument (repeat for more than one) - -e: Entry point address to patch (required for stripped binaries) - -r: Runtime library to instrument (path to, repeat for more than one) - -s: Number of basic blocks to skip - -v: Verbose output + -i: Input binary + -o: Output binary + -l: Library to instrument (repeat for more than one) + -e: Entry point address to patch (required for stripped binaries) + -r: Runtime library to instrument (path to, repeat for more than one) + -s: Number of basic blocks to skip + -m: minimum size of a basic bock to instrument (default: 1) + -f: fix dyninst bug to sometimes not save edi/rdi register + -v: Verbose output Switch -l is used to supply the names of the libraries that should be instrumented along the binary. Instrumented libraries will be copied @@ -42,6 +44,15 @@ written to the same location with a ".ins" suffix as not to overwrite the original ones. Make sure to backup the originals and then rename the instrumented ones to original name. +Switch -m allows you to only instrument basic blocks of a minimum size - the +default minimum size is 1 + +Switch -f fixes a dyninst bug that lead to bugs in the instrumented program: +our basic block instrumentation function loaded into the instrumentd binaries +uses the edi/rdi. However dyninst does not always saves and restores it when +instrumenting that function leading to crashes and changed program behaviour +when the register is used for function parameters. + The instrumentation library "libDyninst.so" must be available in the current working directory as that is where the instrumented binary will be looking for it. diff --git a/afl-dyninst.cpp b/afl-dyninst.cpp index 4581f13..787fb18 100644 --- a/afl-dyninst.cpp +++ b/afl-dyninst.cpp @@ -23,365 +23,383 @@ using namespace Dyninst; char *originalBinary; char *instrumentedBinary; bool verbose = false; + Dyninst::Address entryPoint; -set<string> instrumentLibraries; -set<string> runtimeLibraries; -int bbSkip = 0; +set < string > instrumentLibraries; +set < string > runtimeLibraries; +int bbSkip = 0, dynfix = 0; +unsigned int bbMinSize = 1; bool skipMainModule = false; -const char *instLibrary = "libAflDyninst.so"; - -static const char *OPT_STR = "i:o:l:e:vs:dr:"; -static const char *USAGE = " -i <binary> -o <binary> -l <library> -e <address> -s <number>\n \ - -i: Input binary \n \ - -o: Output binary\n \ - -d: Don't instrument the binary, only supplied libraries\n \ - -l: Linked library to instrument (repeat for more than one)\n \ - -r: Runtime library to instrument (path to, repeat for more than one)\n \ - -e: Entry point address to patch (required for stripped binaries)\n \ - -s: Number of basic blocks to skip\n \ - -v: Verbose output\n"; - -bool parseOptions(int argc, char **argv) -{ - - int c; - while ((c = getopt (argc, argv, OPT_STR)) != -1) { - switch ((char) c) { - case 'e': - entryPoint = strtoul(optarg, NULL, 16);; - break; - case 'i': - originalBinary = optarg; - instrumentLibraries.insert(optarg); - break; - case 'o': - instrumentedBinary = optarg; - break; - case 'l': - instrumentLibraries.insert(optarg); - break; - case 'r': - runtimeLibraries.insert(optarg); - break; - case 's': - bbSkip = atoi(optarg); - break; - case 'd': - skipMainModule = true; - break; - case 'v': - verbose = true; - break; - default: - cerr << "Usage: " << argv[0] << USAGE; - return false; - } - } - - if(originalBinary == NULL) { - cerr << "Input binary is required!"<< endl; - cerr << "Usage: " << argv[0] << USAGE; - return false; - } +BPatch_function *save_rdi; +BPatch_function *restore_rdi; - if(instrumentedBinary == NULL) { - cerr << "Output binary is required!" << endl; - cerr << "Usage: " << argv[0] << USAGE; - return false; - } +const char *instLibrary = "libAflDyninst.so"; - if(skipMainModule && instrumentLibraries.empty()) { - cerr << "If using option -d , option -l is required." << endl; - cerr << "Usage: " << argv[0] << USAGE; - return false; +static const char *OPT_STR = "fi:o:l:e:vs:dr:m:"; +static const char *USAGE = " -i <binary> -o <binary> -l <library> -e <address> -s <number> -m <size>\n \ + -i: Input binary \n \ + -o: Output binary\n \ + -d: Don't instrument the binary, only supplied libraries\n \ + -l: Linked library to instrument (repeat for more than one)\n \ + -r: Runtime library to instrument (path to, repeat for more than one)\n \ + -e: Entry point address to patch (required for stripped binaries)\n \ + -s: Number of basic blocks to skip\n \ + -m: minimum size of a basic bock to instrument (default: 1)\n \ + -f: try to fix crashes\n \ + -v: Verbose output\n"; + +bool parseOptions(int argc, char **argv) { + int c; + + while ((c = getopt(argc, argv, OPT_STR)) != -1) { + switch ((char) c) { + case 'e': + entryPoint = strtoul(optarg, NULL, 16);; + break; + case 'i': + originalBinary = optarg; + instrumentLibraries.insert(optarg); + break; + case 'o': + instrumentedBinary = optarg; + break; + case 'l': + instrumentLibraries.insert(optarg); + break; + case 'r': + runtimeLibraries.insert(optarg); + break; + case 's': + bbSkip = atoi(optarg); + break; + case 'm': + bbMinSize = atoi(optarg); + break; + case 'd': + skipMainModule = true; + break; + case 'f': + dynfix = 1; + break; + case 'v': + verbose = true; + break; + default: + cerr << "Usage: " << argv[0] << USAGE; + return false; } - - return true; + } + + if (originalBinary == NULL) { + cerr << "Input binary is required!" << endl; + cerr << "Usage: " << argv[0] << USAGE; + return false; + } + + if (instrumentedBinary == NULL) { + cerr << "Output binary is required!" << endl; + cerr << "Usage: " << argv[0] << USAGE; + return false; + } + + if (skipMainModule && instrumentLibraries.empty()) { + cerr << "If using option -d , option -l is required." << endl; + cerr << "Usage: " << argv[0] << USAGE; + return false; + } + + return true; } -BPatch_function *findFuncByName (BPatch_image * appImage, char *funcName) -{ - BPatch_Vector < BPatch_function * >funcs; +BPatch_function *findFuncByName(BPatch_image * appImage, char *funcName) { + BPatch_Vector < BPatch_function * >funcs; - if (NULL == appImage->findFunction (funcName, funcs) || !funcs.size () - || NULL == funcs[0]) { - cerr << "Failed to find " << funcName << " function." << endl; - return NULL; - } + if (NULL == appImage->findFunction(funcName, funcs) || !funcs.size() + || NULL == funcs[0]) { + cerr << "Failed to find " << funcName << " function." << endl; + return NULL; + } - return funcs[0]; + return funcs[0]; } // 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) -{ - - /* Find the instrumentation points */ - vector<BPatch_point *> points; - vector < BPatch_point * >*funcEntry = funcInit->findPoint (BPatch_entry); - - 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); - - /* Insert the snippet at function entry */ - BPatchSnippetHandle *handle = - appBin->insertSnippet (instIncExpr, *funcEntry, BPatch_callBefore, - BPatch_lastSnippet); - if (!handle) { - cerr << "Failed to insert init callback." << endl; - return false; - } - return true; +bool insertCallToInit(BPatch_binaryEdit *appBin, BPatch_function *instIncFunc, BPatch_module *module, BPatch_function *funcInit) { + /* Find the instrumentation points */ + vector < BPatch_point * >points; + vector < BPatch_point * >*funcEntry = funcInit->findPoint(BPatch_entry); + + 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); + + /* Insert the snippet at function entry */ + BPatchSnippetHandle *handle = appBin->insertSnippet(instIncExpr, *funcEntry, BPatch_callBefore, + BPatch_lastSnippet); + + if (!handle) { + cerr << "Failed to insert init callback." << endl; + return false; + } + return true; } // 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) -{ - - BPatch_flowGraph *appCFG = curFunc->getCFG (); - unsigned short randID; - - if (!appCFG) { - cerr << "Failed to find CFG for function " << funcName << endl; - return false; +bool insertBBCallback(BPatch_binaryEdit *appBin, BPatch_function *curFunc, char *funcName, BPatch_function *instBBIncFunc, int *bbIndex) { + BPatch_flowGraph *appCFG = curFunc->getCFG(); + unsigned short randID; + + if (!appCFG) { + cerr << "Failed to find CFG for function " << funcName << endl; + return false; + } + + BPatch_Set < BPatch_basicBlock * >allBlocks; + if (!appCFG->getAllBasicBlocks(allBlocks)) { + cerr << "Failed to find basic blocks for function " << funcName << endl; + return false; + } else if (allBlocks.size() == 0) { + cerr << "No basic blocks for function " << funcName << endl; + return false; + } + + 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 + (*bbIndex)++; + continue; } + unsigned long address = (*iter)->getStartAddress(); - BPatch_Set < BPatch_basicBlock * >allBlocks; - if (!appCFG->getAllBasicBlocks (allBlocks)) { - cerr << "Failed to find basic blocks for function " << funcName << endl; - return false; - } else if (allBlocks.size () == 0) { - cerr << "No basic blocks for function " << funcName << endl; - return false; + randID = rand() % USHRT_MAX; + if (verbose) { + cout << "Instrumenting Basic Block 0x" << hex << address << " of " << funcName << " of size " << dec << (*iter)->size() << " with random id " << randID << endl; } - BPatch_Set < BPatch_basicBlock * >::iterator iter; - for (iter = allBlocks.begin (); iter != allBlocks.end (); iter++) { - if(*bbIndex < bbSkip) { // skip over first bbSkip bbs - (*bbIndex)++; - continue; + BPatch_Vector < BPatch_snippet * >instArgs1; + BPatch_Vector < BPatch_snippet * >instArgs; + BPatch_constExpr bbId(randID); - } - unsigned long address = (*iter)->getStartAddress (); - randID = rand() % USHRT_MAX; - if(verbose) { - cout << "Instrumenting Basic Block 0x" << hex << address << " of " << - funcName << " with random id " << randID << endl; - } + instArgs.push_back(&bbId); + BPatch_point *bbEntry = (*iter)->findEntryPoint(); - BPatch_Vector < BPatch_snippet * >instArgs; - BPatch_constExpr bbId (randID); - instArgs.push_back (&bbId); - BPatch_point *bbEntry = (*iter)->findEntryPoint (); - if (NULL == bbEntry) { - // warn the user, but continue - cerr << "Failed to find entry for basic block at 0x" << hex << address - << endl; - (*bbIndex)++; - continue; - } - BPatch_funcCallExpr instIncExpr (*instBBIncFunc, instArgs); - BPatchSnippetHandle *handle = - appBin->insertSnippet (instIncExpr, *bbEntry, BPatch_callBefore, - BPatch_lastSnippet); - if (!handle) { - // warn the user, but continue to next bb - cerr << "Failed to insert instrumention in basic block at 0x" << hex << - address << endl; - (*bbIndex)++; - continue; - } + if (NULL == bbEntry) { + // warn the user, but continue + cerr << "Failed to find entry for basic block at 0x" << hex << address << endl; + (*bbIndex)++; + continue; + } + + BPatch_funcCallExpr instIncExpr1(*save_rdi, instArgs1); + BPatch_funcCallExpr instIncExpr3(*restore_rdi, instArgs1); + BPatch_funcCallExpr instIncExpr(*instBBIncFunc, instArgs); + BPatchSnippetHandle *handle; + if (dynfix) + handle = appBin->insertSnippet(instIncExpr1, *bbEntry, BPatch_callBefore, BPatch_lastSnippet); + handle = appBin->insertSnippet(instIncExpr, *bbEntry, BPatch_callBefore, BPatch_lastSnippet); + if (dynfix) + handle = appBin->insertSnippet(instIncExpr3, *bbEntry, BPatch_callBefore, BPatch_lastSnippet); - (*bbIndex)++; + if (!handle) { + // warn the user, but continue to next bb + cerr << "Failed to insert instrumention in basic block at 0x" << hex << address << endl; + (*bbIndex)++; + continue; } - return true; + (*bbIndex)++; + } + return true; } -int main (int argc, char **argv) -{ - - if(!parseOptions(argc,argv)) { - return EXIT_FAILURE; +int main(int argc, char **argv) { + if (!parseOptions(argc, argv)) { + return EXIT_FAILURE; + } + + BPatch bpatch; + BPatch_binaryEdit *appBin = bpatch.openBinary(originalBinary, instrumentLibraries.size() != 1); + + if (appBin == NULL) { + cerr << "Failed to open binary" << endl; + return EXIT_FAILURE; + } + + BPatch_image *appImage = appBin->getImage(); + + //get and iterate over all modules, instrumenting only the default and manually specified ones + vector < BPatch_module * >*modules = appImage->getModules(); + vector < BPatch_module * >::iterator moduleIter; + vector < BPatch_function * >*funcsInModule; + BPatch_module *defaultModule = NULL; + string defaultModuleName; + + // look for _init + if (defaultModuleName.empty()) { + for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) { + funcsInModule = (*moduleIter)->getProcedures(); + vector < BPatch_function * >::iterator funcsIterator; + 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); + defaultModuleName = string(moduleName); + if (verbose) { + cout << "Found _init in " << moduleName << endl; + } + break; + } + } + if (!defaultModuleName.empty()) + break; } - - BPatch bpatch; - - BPatch_binaryEdit *appBin = bpatch.openBinary (originalBinary, instrumentLibraries.size() != 1); - if (appBin == NULL) { - cerr << "Failed to open binary" << endl; - return EXIT_FAILURE; + } + // last resort, by name of the binary + if (defaultModuleName.empty()) + defaultModuleName = string(originalBinary).substr(string(originalBinary).find_last_of("\\/") + 1); + + if (!appBin->loadLibrary(instLibrary)) { + cerr << "Failed to open instrumentation library " << instLibrary << endl; + cerr << "It needs to be located in the current working directory." << endl; + return EXIT_FAILURE; + } + + appImage = appBin->getImage(); + + /* Find code coverage functions in the instrumentation library */ + BPatch_function *initAflForkServer = findFuncByName(appImage, (char *) "initAflForkServer"); + save_rdi = findFuncByName(appImage, (char *) "save_rdi"); + restore_rdi = findFuncByName(appImage, (char *) "restore_rdi"); + BPatch_function *bbCallback = findFuncByName(appImage, (char *) "bbCallback"); + + if (!initAflForkServer || !bbCallback || !save_rdi || !restore_rdi) { + cerr << "Instrumentation library lacks callbacks!" << endl; + return EXIT_FAILURE; + } + + int bbIndex = 0; + + // instrument all shared libraries: + for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) { + char moduleName[1024]; + + (*moduleIter)->getName(moduleName, 1024); + + if ((*moduleIter)->isSharedLib()) { + if (instrumentLibraries.find(moduleName) == instrumentLibraries.end()) { + cout << "Skipping library: " << moduleName << endl; + continue; + } } - - BPatch_image *appImage = appBin->getImage (); - - - //get and iterate over all modules, instrumenting only the default and manualy specified ones - vector < BPatch_module * >*modules = appImage->getModules (); - vector < BPatch_module * >::iterator moduleIter; - vector < BPatch_function * >* funcsInModule; - BPatch_module *defaultModule = NULL; - string defaultModuleName; - - // look for _init - if(defaultModuleName.empty()){ - for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter){ - funcsInModule = (*moduleIter)->getProcedures(); - vector < BPatch_function * >::iterator funcsIterator; - 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); - defaultModuleName = string(moduleName); - if(verbose) { - cout << "Found _init in " << moduleName<< endl; - } - break; - } - } - if(!defaultModuleName.empty()) break; - } + if (string(moduleName).find(defaultModuleName) != string::npos) { + defaultModule = (*moduleIter); + if (skipMainModule) + continue; } - // last resort, by name of the binary - if(defaultModuleName.empty()) - defaultModuleName = string(originalBinary).substr(string(originalBinary).find_last_of("\\/")+1); - - if (!appBin->loadLibrary (instLibrary)) { - cerr << "Failed to open instrumentation library." << endl; - cerr << "It needs to be located in the current working directory." << endl; - return EXIT_FAILURE; + 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; + char funcName[1024]; + + curFunc->getName(funcName, 1024); + if (string(funcName) == string("_start")) + continue; // here's a bug on hlt // XXX: check what happens if removed + insertBBCallback(appBin, curFunc, funcName, bbCallback, &bbIndex); } + } - appImage = appBin->getImage (); - - /* Find code coverage functions in the instrumentation library */ - BPatch_function *initAflForkServer = - findFuncByName (appImage, (char *) "initAflForkServer"); - BPatch_function *bbCallback = - findFuncByName (appImage, (char *) "bbCallback"); - if (!initAflForkServer || !bbCallback ) { - cerr << "Instrumentation library lacks callbacks!" << endl; - return EXIT_FAILURE; + // if entrypoint 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 manualy. " << 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; + } + + cout << "Saving the instrumented binary to " << instrumentedBinary << " ..." << endl; + // Output the instrumented binary + if (!appBin->writeFile(instrumentedBinary)) { + cerr << "Failed to write output file: " << instrumentedBinary << endl; + return EXIT_FAILURE; + } + + 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); + + if (libBin == NULL) { + cerr << "Failed to open binary " << *rtLibIter << endl; + return EXIT_FAILURE; + } + BPatch_image *libImg = libBin->getImage(); + vector < BPatch_module * >*modules = libImg->getModules(); + moduleIter = modules->begin(); - int bbIndex = 0; - for (moduleIter = modules->begin (); moduleIter != modules->end (); ++moduleIter) { + for (; moduleIter != modules->end(); ++moduleIter) { char moduleName[1024]; - (*moduleIter)->getName (moduleName, 1024); - - if ((*moduleIter)->isSharedLib ()) { - if (instrumentLibraries.find (moduleName) == instrumentLibraries.end ()) { - cout << "Skipping library: " << moduleName << endl; - continue; - } - } - if (string (moduleName).find (defaultModuleName) != string::npos) { - defaultModule = (*moduleIter); - if(skipMainModule) continue; - } + (*moduleIter)->getName(moduleName, 1024); cout << "Instrumenting module: " << moduleName << endl; - vector < BPatch_function * >*allFunctions = - (*moduleIter)->getProcedures (); + 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; - char funcName[1024]; - curFunc->getName (funcName, 1024); - if(string (funcName) == string("_start")) continue; // here's a bug on hlt - insertBBCallback (appBin, curFunc, funcName, bbCallback, &bbIndex); - } - - } + for (funcIter = allFunctions->begin(); funcIter != allFunctions->end(); ++funcIter) { + BPatch_function *curFunc = *funcIter; + char funcName[1024]; - //if entrypoint set ,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 manualy. "<< endl; - return EXIT_FAILURE; + curFunc->getName(funcName, 1024); + if (string(funcName) == string("_start")) + continue; + insertBBCallback(libBin, curFunc, funcName, bbCallback, &bbIndex); } - // 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; + } + if (!libBin->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; + } } + } - cout << "Saving the instrumented binary to " << instrumentedBinary << "..." << endl; - // Output the instrumented binary - if (!appBin->writeFile (instrumentedBinary)) { - cerr << "Failed to write output file: " << instrumentedBinary << endl; - return EXIT_FAILURE; - } - - 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); - if (libBin == NULL) { - cerr << "Failed to open binary "<< *rtLibIter << endl; - return EXIT_FAILURE; - } - BPatch_image *libImg = libBin->getImage (); - 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 (); - vector < BPatch_function * >::iterator funcIter; - // iterate over all functions in the module - for (funcIter = allFunctions->begin (); funcIter != allFunctions->end (); - ++funcIter) { - BPatch_function *curFunc = *funcIter; - char funcName[1024]; - curFunc->getName (funcName, 1024); - if(string (funcName) == string("_start")) continue; - insertBBCallback (libBin, curFunc, funcName, bbCallback, &bbIndex); - } - } - if (!libBin->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; - } - } - } - - cout << "All done! Happy fuzzing!" << endl; - return EXIT_SUCCESS; - + cout << "All done! Happy fuzzing!" << endl; + return EXIT_SUCCESS; } diff --git a/afl-dyninst.sh b/afl-dyninst.sh new file mode 100755 index 0000000..dd7d747 --- /dev/null +++ b/afl-dyninst.sh @@ -0,0 +1,3 @@ +#!/bin/sh +export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so +afl-dyninst $* diff --git a/afl-fuzz.sh b/afl-fuzz.sh new file mode 100755 index 0000000..c9986c6 --- /dev/null +++ b/afl-fuzz.sh @@ -0,0 +1,6 @@ +#!/bin/bash +test -z "$1" -o "$1" = "-h" && { echo Syntax: $0 afl-fuzz-options ; echo sets the afl-dyninst environment variables ; exit 1 ; } +export AFL_SKIP_BIN_CHECK=1 +export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so +#export AFL_PRELOAD=./desock.so +afl-fuzz $* diff --git a/libAflDyninst.cpp b/libAflDyninst.cpp index 514144f..ef9d046 100644 --- a/libAflDyninst.cpp +++ b/libAflDyninst.cpp @@ -14,70 +14,85 @@ using namespace std; - -static u8* trace_bits; -static s32 shm_id; /* ID of the SHM region */ +static u8 *trace_bits; +static s32 shm_id; static int __afl_temp_data; static pid_t __afl_fork_pid; static unsigned short prev_id; +static long saved_di; +register long rdi asm("di"); // the warning is fine - we need the warning because of a bug in dyninst +void initAflForkServer() { + char *shm_env_var = getenv(SHM_ENV_VAR); -void initAflForkServer() -{ - char *shm_env_var = getenv(SHM_ENV_VAR); - if(!shm_env_var) { - printf("Error getting shm\n"); - return; - } - shm_id = atoi(shm_env_var); - trace_bits = (u8*)shmat(shm_id, NULL, 0); - if(trace_bits == (u8*)-1) { - perror("shmat"); - return; - } + if (!shm_env_var) { + printf("Error getting shm\n"); + return; + } + shm_id = atoi(shm_env_var); + trace_bits = (u8 *) shmat(shm_id, NULL, 0); + if (trace_bits == (u8 *) - 1) { + perror("shmat"); + return; + } + // enter fork() server thyme! + int n = write(FORKSRV_FD + 1, &__afl_temp_data, 4); - // enter fork() server thyme! - int n = write(FORKSRV_FD+1, &__afl_temp_data,4); - if( n!=4 ) { - printf("Error writting fork server\n"); - return; + if (n != 4) { + printf("Error writting fork server\n"); + return; + } + while (1) { + n = read(FORKSRV_FD, &__afl_temp_data, 4); + if (n != 4) { + printf("Error reading fork server %x\n", __afl_temp_data); + return; } - while(1) { - n = read(FORKSRV_FD,&__afl_temp_data,4); - if(n != 4) { - printf("Error reading fork server %x\n",__afl_temp_data); - return; - } - __afl_fork_pid = fork(); - if(__afl_fork_pid < 0) { - printf("Error on fork()\n"); - return; - } - if(__afl_fork_pid == 0) { - close(FORKSRV_FD); - close(FORKSRV_FD+1); - 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); - } + __afl_fork_pid = fork(); + if (__afl_fork_pid < 0) { + printf("Error on fork()\n"); + return; + } + if (__afl_fork_pid == 0) { + close(FORKSRV_FD); + close(FORKSRV_FD + 1); + 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); } + } +} +// Should be called on basic block entry +void bbCallback(unsigned short id) { + if (trace_bits) { + trace_bits[prev_id ^ id]++; + prev_id = id >> 1; + } } +void save_rdi() { + saved_di = rdi; +/* + asm("pop %rax"); // take care of rip + asm("push %rdi"); + asm("push %rax"); +*/ +} -// Should be called on basic block entry -void bbCallback(unsigned short id) -{ - if(trace_bits) { - trace_bits[prev_id ^ id]++; - prev_id = id >> 1; - } +void restore_rdi() { + rdi = saved_di; +/* + asm("pop %rax"); // take care of rip + asm("pop %rdi"); + asm("push %rax"); +*/ } |