diff options
author | Nguyễn Gia Phong <cnx@loang.net> | 2024-11-05 12:47:14 +0900 |
---|---|---|
committer | Nguyễn Gia Phong <cnx@loang.net> | 2024-11-05 16:27:39 +0900 |
commit | 1fe6579eb183c8762c6ce41fc2ace742c8f5a5c9 (patch) | |
tree | 169abf126dbd3ff291e93194252a17ca3d91cd00 | |
parent | 3aa0dbdc85f9a4cadac0152ed1bfb4cad7c3174b (diff) | |
download | afl-dyninst-1fe6579eb183c8762c6ce41fc2ace742c8f5a5c9.tar.gz |
Rework afl-dyninst's CLI
It is now compatible with help2man, hence the new barebone manual page.
-rw-r--r-- | CHANGES | 10 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | afl-dyninst.cc | 207 |
3 files changed, 124 insertions, 113 deletions
diff --git a/CHANGES b/CHANGES index 57f4bf2..058282a 100644 --- a/CHANGES +++ b/CHANGES @@ -3,13 +3,17 @@ Tag: 1.0.0 Build recipe rework Additions: - - Compliance with REUSE 3.0 has been added + - Manual page for afl-dyninst(1) + - Positional arguments for input and output binaries + of afl-dyninst(1) + - Long command-line options for afl-dyninst(1) - Make target uninstall + - Compliance with REUSE 3.0 Removals: - Support for Dyninst < 10 - - Command-line options -dfl - + - afl-dyninst(1)'s command-line options -dfilo + - afl-dyninst's unnecessary info logs Remote: https://github.com/vanhauser-thc/afl-dyninst Date: 2021-05-21 diff --git a/Makefile b/Makefile index df078b0..9c7135c 100644 --- a/Makefile +++ b/Makefile @@ -14,13 +14,14 @@ VERSION ::= 1.0.0 PREFIX ?= /usr/local BINDIR ::= $(DESTDIR)$(PREFIX)/bin LIBDIR ::= $(DESTDIR)$(PREFIX)/lib +MANDIR ::= $(DESTDIR)$(PREFIX)/share/man # Override on non-FHS environments DYNINST_LIB ?= $(LIBDIR) # Override to . for local development AFL_DYNINST_LIB ?= $(LIBDIR) -CPPFLAGS = -DPROG=\"afl-dyninst\" -DVERSION=\"$(VERSION)\"\ +CPPFLAGS = -DVERSION=\"$(VERSION)\"\ -DAFL_DYNINST_LIB=\"$(AFL_DYNINST_LIB)/libafldyninst.so\"\ -DDYNINSTAPI_RT_LIB=\"$(DYNINST_LIB)/libdyninstAPI_RT.so\" CXXFLAGS += -std=c++11 -Wextra -Werror @@ -29,8 +30,9 @@ LDLIBS += -ldyninstAPI BIN ::= afl-dyninst afl-dyninst-env LIB ::= libafldyninst.so +MAN ::= afl-dyninst.1 -all: $(BIN) $(LIB) +all: $(BIN) $(LIB) $(MAN) afl-dyninst: afl-dyninst.cc @@ -41,10 +43,13 @@ afl-dyninst-env: afl-dyninst-env.m4 %.so: %.cc $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $< -o $@ +%.1: % + help2man --no-info --output=$@ `realpath $<` + clean: - rm -f $(BIN) $(LIB) + rm -f $(BIN) $(LIB) $(MAN) -install: $(BIN:%=$(BINDIR)/%) $(LIB:%=$(LIBDIR)/%) +install: $(BIN:%=$(BINDIR)/%) $(LIB:%=$(LIBDIR)/%) $(MAN:%.1:$(MANDIR)/man1/%.1) $(BINDIR)/%: % install -Dm 755 $< $@ @@ -52,5 +57,10 @@ $(BINDIR)/%: % $(LIBDIR)/%: % install -Dm 644 $< $@ +$(MANDIR)/man1/%.1 : %.1 + install -Dm 644 $< $@ + uninstall: - rm -f $(BIN:%=$(BINDIR)/%) $(LIB:%=$(LIBDIR)/%) + rm -f $(BIN:%=$(BINDIR)/%) + rm -f $(LIB:%=$(LIBDIR)/%) + rm -f $(MAN:%.1:$(MANDIR)/man1/%.1) diff --git a/afl-dyninst.cc b/afl-dyninst.cc index 5fb3d38..745b072 100644 --- a/afl-dyninst.cc +++ b/afl-dyninst.cc @@ -32,14 +32,11 @@ using namespace std; using namespace Dyninst; // cmd line options -char *originalBinary; -char *instrumentedBinary; char *entryPointName = NULL; int verbose = 0; Dyninst::Address entryPoint; set<string> todo; -set<string> instrumentLibraries; set<string> runtimeLibraries; set<string> skipAddresses; set<string> onlyAddresses; @@ -55,95 +52,6 @@ BPatch_function *restore_rdi; const char *functions[] = {"main", "_main", "_initproc", "_init", "start", "_start", NULL}; -static const char *OPT_STR = "fi:o:l:e:E:vs:dr:m:S:I:Dx"; -static const char *USAGE = " -vxD -i <binary> -o <binary> -e <address> -E <address> -s <number> -S <funcname> -I <funcname> -m <size>\n \ - -i: input binary \n \ - -o: output binary\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 \ - -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: 10)\n \ - -I: only instrument this function and nothing else (repeat for more than one)\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 (~25-50% speed improvement)\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 'x': - 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 > 2) performance = 2; - break; - case 'I': - onlyAddresses.insert(optarg); - break; - case 'S': - skipAddresses.insert(optarg); - break; - case 'e': - if ((entryPoint = strtoul(optarg, NULL, 16)) < 0x1000) - entryPointName = optarg; - break; - case 'i': - originalBinary = optarg; - instrumentLibraries.insert(optarg); - break; - case 'o': - instrumentedBinary = optarg; - break; - case 'E': - exitAddresses.insert(strtoul(optarg, NULL, 16)); - break; - case 'r': - runtimeLibraries.insert(optarg); - break; - case 's': - bbSkip = atoi(optarg); - break; - case 'm': - bbMinSize = atoi(optarg); - break; - case 'D': - do_bb = false; - break; - case 'v': - verbose++; - 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; - } - - if (instrumentedBinary == NULL) { - cerr << "Output binary 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; @@ -189,14 +97,12 @@ bool insertCallToInit(BPatch_addressSpace *appBin, BPatch_function *instIncFunc, 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); handle = appBin->insertSnippet(instIncExpr, *funcEntry, BPatch_callBefore, BPatch_lastSnippet); @@ -315,17 +221,110 @@ bool insertBBCallback(BPatch_addressSpace *appBin, BPatch_function *curFunc, cha } int main(int argc, char **argv) { - char *func2patch = NULL; - int loop; + static const char *const USAGE = "Usage: afl-dyninst" + " [OPTIONS]... INFILE OUTFILE\n\n" + "Instrument binary to be fuzzed by AFL.\n\n" + "Options:\n" + " -h, --help show this help message and exit\n" + " --version show program's version number and exit\n" + " -e ADDR, --entry=ADDR " + "entry point address to patch (required for stripped binaries)\n" + " -E ADDR, --exit=ADDR force exit(0) at this address (multiple use)\n" + " -D " + "instrument only a simple fork server and also forced exit functions\n" + " -r PATH, --library=PATH runtime library to instrument (multiple use)\n" + " -I NAME, --include=NAME " + "instrument only this function and nothing else (multiple use)\n" + " -S NAME, --exclude=NAME " + "do not instrument this function (multiple use)\n" + " -m N, --min-size=N " + "minimum size of a basic bock to instrument (default to 10)\n" + " -s N, --skip=N " + "number of initial basic blocks to skip in binary\n" + " -v, --verbose enable verbose output (up to 3 levels)\n" + " -x " + "experimental performance mode (multiple use, ~25-50% speed improvement)\n"; - if (argc < 3 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0) { - cout << "Usage: " << argv[0] << USAGE; - return false; + int c; + int option_index = 0; + const static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"entry", required_argument, NULL, 'e'}, + {"exit", required_argument, NULL, 'E'}, + {"library", required_argument, NULL, 'r'}, + {"include", required_argument, NULL, 'I'}, + {"exclude", required_argument, NULL, 'S'}, + {"min-size", required_argument, NULL, 'm'}, + {"skip", required_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 0}, + {NULL, 0, NULL, 0}, + }; + while ((c = getopt_long(argc, argv, "he:E:Dr:I:S:m:s:vx", + long_options, &option_index)) != -1) { + switch (c) { + case 0: + if (strcmp(long_options[option_index].name, "version") == 0) { + std::cout << "afl-dyninst " VERSION "\n"; + return EXIT_SUCCESS; + } + __builtin_unreachable(); + case 'h': + std::cout << USAGE; + return EXIT_SUCCESS; + case 'e': + if ((entryPoint = strtoul(optarg, NULL, 16)) < 0x1000) + entryPointName = optarg; + break; + case 'E': + exitAddresses.insert(strtoul(optarg, NULL, 16)); + break; + case 'D': + do_bb = false; + break; + case 'r': + runtimeLibraries.insert(optarg); + break; + case 'I': + onlyAddresses.insert(optarg); + break; + case 'S': + skipAddresses.insert(optarg); + break; + case 'm': + bbMinSize = atoi(optarg); + break; + case 's': + bbSkip = atoi(optarg); + break; + case 'v': + verbose++; + break; + case 'x': + performance++; + if (performance > 2) { +//#if ( __amd64__ || __x86_64__ ) +// std::cerr << "Warning: performance level 3 is currently totally experimental\n"; +//#else +// std::cerr << "Warning: maximum performance level for non-intelx64 x86 is 2\n"; + performance = 2; +//#endif + } + break; + default: + return EXIT_FAILURE; + } } - - if (!parseOptions(argc, argv)) { + if (optind >= argc) { + std::cerr << USAGE; + return EXIT_FAILURE; + } + const char *const originalBinary = argv[optind]; + if (++optind >= argc) { + std::cerr << USAGE; return EXIT_FAILURE; } + const char *const instrumentedBinary = argv[optind]; BPatch bpatch; @@ -359,8 +358,9 @@ int main(int argc, char **argv) { string defaultModuleName; // look for _init + char *func2patch = NULL; if (defaultModuleName.empty()) { - for (loop = 0; functions[loop] != NULL && func2patch == NULL; loop++) { + for (unsigned loop = 0; functions[loop] != NULL && func2patch == NULL; loop++) { for (moduleIter = modules->begin(); moduleIter != modules->end(); ++moduleIter) { vector<BPatch_function *>::iterator funcsIterator; char moduleName[1024]; @@ -569,7 +569,6 @@ int main(int argc, char **argv) { } } - cout << "Saving the instrumented binary to " << instrumentedBinary << " ..." << endl; // Output the instrumented binary BPatch_binaryEdit *appBinr = dynamic_cast<BPatch_binaryEdit *>(appBin); @@ -681,7 +680,5 @@ int main(int argc, char **argv) { exit(-1); } } - - cout << "All done! Happy fuzzing!" << endl; return EXIT_SUCCESS; } |