diff options
Diffstat (limited to 'libtokencap')
-rw-r--r-- | libtokencap/Makefile | 2 | ||||
-rw-r--r-- | libtokencap/README.md (renamed from libtokencap/README.tokencap) | 12 | ||||
-rw-r--r-- | libtokencap/libtokencap.so.c | 70 |
3 files changed, 38 insertions, 46 deletions
diff --git a/libtokencap/Makefile b/libtokencap/Makefile index a464f76d..ec4c8f95 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -18,7 +18,7 @@ HELPER_PATH = $(PREFIX)/lib/afl VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) -CFLAGS ?= -O3 -funroll-loops +CFLAGS ?= -O3 -funroll-loops -I ../include/ CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign all: libtokencap.so diff --git a/libtokencap/README.tokencap b/libtokencap/README.md index 650739f2..baf69da1 100644 --- a/libtokencap/README.tokencap +++ b/libtokencap/README.md @@ -1,10 +1,8 @@ -========================================= -strcmp() / memcmp() token capture library -========================================= +# strcmp() / memcmp() token capture library (See ../docs/README for the general instruction manual.) -This Linux-only companion library allows you to instrument strcmp(), memcmp(), +This Linux-only companion library allows you to instrument `strcmp()`, `memcmp()`, and related functions to automatically extract syntax tokens passed to any of these libcalls. The resulting list of tokens may be then given as a starting dictionary to afl-fuzz (the -x option) to improve coverage on subsequent @@ -31,15 +29,18 @@ with -fno-builtin and is linked dynamically. If you wish to automate the first part without mucking with CFLAGS in Makefiles, you can set AFL_NO_BUILTIN=1 when using afl-gcc. This setting specifically adds the following flags: +``` -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp -fno-builtin-strcasencmp -fno-builtin-memcmp -fno-builtin-strstr -fno-builtin-strcasestr +``` The next step is simply loading this library via LD_PRELOAD. The optimal usage pattern is to allow afl-fuzz to fuzz normally for a while and build up a corpus, and then fire off the target binary, with libtokencap.so loaded, on every file found by AFL in that earlier run. This demonstrates the basic principle: +``` export AFL_TOKEN_FILE=$PWD/temp_output.txt for i in <out_dir>/queue/id*; do @@ -48,6 +49,7 @@ found by AFL in that earlier run. This demonstrates the basic principle: done sort -u temp_output.txt >afl_dictionary.txt +``` If you don't get any results, the target library is probably not using strcmp() and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or @@ -55,7 +57,7 @@ the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect. PS. The library is Linux-only because there is probably no particularly portable and non-invasive way to distinguish between read-only and read-write memory -mappings. The __tokencap_load_mappings() function is the only thing that would +mappings. The `__tokencap_load_mappings()` function is the only thing that would need to be changed for other OSes. Porting to platforms with /proc/<pid>/maps (e.g., FreeBSD) should be trivial. diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 54072279..17b6190c 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -27,30 +27,26 @@ #include "../config.h" #ifndef __linux__ -# error "Sorry, this library is Linux-specific for now!" -#endif /* !__linux__ */ - +#error "Sorry, this library is Linux-specific for now!" +#endif /* !__linux__ */ /* Mapping data and such */ #define MAX_MAPPINGS 1024 -static struct mapping { - void *st, *en; -} __tokencap_ro[MAX_MAPPINGS]; +static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS]; static u32 __tokencap_ro_cnt; static u8 __tokencap_ro_loaded; static FILE* __tokencap_out_file; - /* Identify read-only regions in memory. Only parameters that fall into these ranges are worth dumping when passed to strcmp() and so on. Read-write regions are far more likely to contain user input instead. */ static void __tokencap_load_mappings(void) { - u8 buf[MAX_LINE]; + u8 buf[MAX_LINE]; FILE* f = fopen("/proc/self/maps", "r"); __tokencap_ro_loaded = 1; @@ -59,8 +55,8 @@ static void __tokencap_load_mappings(void) { while (fgets(buf, MAX_LINE, f)) { - u8 rf, wf; - void* st, *en; + u8 rf, wf; + void *st, *en; if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue; if (wf == 'w' || rf != 'r') continue; @@ -76,7 +72,6 @@ static void __tokencap_load_mappings(void) { } - /* Check an address against the list of read-only mappings. */ static u8 __tokencap_is_ro(const void* ptr) { @@ -85,20 +80,19 @@ static u8 __tokencap_is_ro(const void* ptr) { if (!__tokencap_ro_loaded) __tokencap_load_mappings(); - for (i = 0; i < __tokencap_ro_cnt; i++) + for (i = 0; i < __tokencap_ro_cnt; i++) if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1; return 0; } - /* Dump an interesting token to output file, quoting and escaping it properly. */ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { - u8 buf[MAX_AUTO_EXTRA * 4 + 1]; + u8 buf[MAX_AUTO_EXTRA * 4 + 1]; u32 i; u32 pos = 0; @@ -120,9 +114,7 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { pos += 4; break; - default: - - buf[pos++] = ptr[i]; + default: buf[pos++] = ptr[i]; } @@ -130,11 +122,10 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { buf[pos] = 0; - fprintf(__tokencap_out_file, "\"%s\"\n", buf); + fprintf(__tokencap_out_file, "\"%s\"\n", buf); } - /* Replacements for strcmp(), memcmp(), and so on. Note that these will be used only if the target is compiled with -fno-builtins and linked dynamically. */ @@ -151,13 +142,13 @@ int strcmp(const char* str1, const char* str2) { if (c1 != c2) return (c1 > c2) ? 1 : -1; if (!c1) return 0; - str1++; str2++; + str1++; + str2++; } } - #undef strncmp int strncmp(const char* str1, const char* str2, size_t len) { @@ -171,7 +162,8 @@ int strncmp(const char* str1, const char* str2, size_t len) { if (!c1) return 0; if (c1 != c2) return (c1 > c2) ? 1 : -1; - str1++; str2++; + str1++; + str2++; } @@ -179,7 +171,6 @@ int strncmp(const char* str1, const char* str2, size_t len) { } - #undef strcasecmp int strcasecmp(const char* str1, const char* str2) { @@ -193,13 +184,13 @@ int strcasecmp(const char* str1, const char* str2) { if (c1 != c2) return (c1 > c2) ? 1 : -1; if (!c1) return 0; - str1++; str2++; + str1++; + str2++; } } - #undef strncasecmp int strncasecmp(const char* str1, const char* str2, size_t len) { @@ -213,7 +204,8 @@ int strncasecmp(const char* str1, const char* str2, size_t len) { if (!c1) return 0; if (c1 != c2) return (c1 > c2) ? 1 : -1; - str1++; str2++; + str1++; + str2++; } @@ -221,7 +213,6 @@ int strncasecmp(const char* str1, const char* str2, size_t len) { } - #undef memcmp int memcmp(const void* mem1, const void* mem2, size_t len) { @@ -233,7 +224,8 @@ int memcmp(const void* mem1, const void* mem2, size_t len) { unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2; if (c1 != c2) return (c1 > c2) ? 1 : -1; - mem1++; mem2++; + mem1++; + mem2++; } @@ -241,7 +233,6 @@ int memcmp(const void* mem1, const void* mem2, size_t len) { } - #undef strstr char* strstr(const char* haystack, const char* needle) { @@ -249,16 +240,17 @@ char* strstr(const char* haystack, const char* needle) { if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, strlen(haystack), 1); - if (__tokencap_is_ro(needle)) - __tokencap_dump(needle, strlen(needle), 1); + if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1); do { + const char* n = needle; const char* h = haystack; - while(*n && *h && *n == *h) n++, h++; + while (*n && *h && *n == *h) + n++, h++; - if(!*n) return (char*)haystack; + if (!*n) return (char*)haystack; } while (*(haystack++)); @@ -266,7 +258,6 @@ char* strstr(const char* haystack, const char* needle) { } - #undef strcasestr char* strcasestr(const char* haystack, const char* needle) { @@ -274,25 +265,24 @@ char* strcasestr(const char* haystack, const char* needle) { if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, strlen(haystack), 1); - if (__tokencap_is_ro(needle)) - __tokencap_dump(needle, strlen(needle), 1); + if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1); do { const char* n = needle; const char* h = haystack; - while(*n && *h && tolower(*n) == tolower(*h)) n++, h++; + while (*n && *h && tolower(*n) == tolower(*h)) + n++, h++; - if(!*n) return (char*)haystack; + if (!*n) return (char*)haystack; - } while(*(haystack++)); + } while (*(haystack++)); return 0; } - /* Init code to open the output file (or default to stderr). */ __attribute__((constructor)) void __tokencap_init(void) { |