From e12acaa20367f335549c2db97b88ac5c8ffbeab7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 15 Apr 2023 10:12:20 +0200 Subject: fix custom mutator C examples --- custom_mutators/examples/custom_mutator_helpers.h | 342 ---------------------- custom_mutators/examples/custom_send.c | 8 +- custom_mutators/examples/example.c | 116 +++----- custom_mutators/examples/post_library_gif.so.c | 53 +--- custom_mutators/examples/post_library_png.so.c | 24 +- custom_mutators/examples/simple_example.c | 28 +- 6 files changed, 72 insertions(+), 499 deletions(-) delete mode 100644 custom_mutators/examples/custom_mutator_helpers.h (limited to 'custom_mutators') diff --git a/custom_mutators/examples/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h deleted file mode 100644 index 62e6efba..00000000 --- a/custom_mutators/examples/custom_mutator_helpers.h +++ /dev/null @@ -1,342 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include - -#define INITIAL_GROWTH_SIZE (64) - -#define RAND_BELOW(limit) (rand() % (limit)) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this fills in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -typedef struct { - -} afl_t; - -static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { - - static s8 interesting_8[] = {INTERESTING_8}; - static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; - static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - - switch (RAND_BELOW(12)) { - - case 0: { - - /* Flip a single bit somewhere. Spooky! */ - - s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); - - out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); - - break; - - } - - case 1: { - - /* Set byte to interesting value. */ - - u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; - out_buf[(RAND_BELOW(end - begin) + begin)] = val; - - break; - - } - - case 2: { - - /* Set word to interesting value, randomly choosing endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u16 *)(out_buf + byte_idx) = - interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; - break; - case 1: - *(u16 *)(out_buf + byte_idx) = - SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); - break; - - } - - break; - - } - - case 3: { - - /* Set dword to interesting value, randomly choosing endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u32 *)(out_buf + byte_idx) = - interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u32 *)(out_buf + byte_idx) = - SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 4: { - - /* Set qword to interesting value, randomly choosing endian. */ - - if (end - begin < 8) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 7) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u64 *)(out_buf + byte_idx) = - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u64 *)(out_buf + byte_idx) = SWAP64( - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 5: { - - /* Randomly subtract from byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 6: { - - /* Randomly add to byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 7: { - - /* Randomly subtract from word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 8: { - - /* Randomly add to word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 9: { - - /* Randomly subtract from dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 10: { - - /* Randomly add to dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 11: { - - /* Just set a random byte to a random value. Because, - why not. We use XOR with 1-255 to eliminate the - possibility of a no-op. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); - - break; - - } - - } - -} - -/* This function calculates the next power of 2 greater or equal its argument. - @return The rounded up power of 2 (if no overflow) or 0 on overflow. -*/ -static inline size_t next_pow2(size_t in) { - - if (in == 0 || in > (size_t)-1) - return 0; /* avoid undefined behaviour under-/overflow */ - size_t out = in - 1; - out |= out >> 1; - out |= out >> 2; - out |= out >> 4; - out |= out >> 8; - out |= out >> 16; - return out + 1; - -} - -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) return *buf; - - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); - - /* handle overflow */ - if (!next_size) { next_size = size_needed; } - - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; - - return *buf; - -} - -/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { - - void * scratch_buf = *buf1; - size_t scratch_size = *size1; - *buf1 = *buf2; - *size1 = *size2; - *buf2 = scratch_buf; - *size2 = scratch_size; - -} - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/custom_mutators/examples/custom_send.c b/custom_mutators/examples/custom_send.c index 7de72819..9cc4b160 100644 --- a/custom_mutators/examples/custom_send.c +++ b/custom_mutators/examples/custom_send.c @@ -10,21 +10,21 @@ // afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo // -#include "custom_mutator_helpers.h" - #include #include #include #include #include +#include "afl-fuzz.h" + typedef struct my_mutator { - afl_t *afl; + afl_state_t *afl; } my_mutator_t; -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); if (!data) { diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c index e680ec8e..42c7469c 100644 --- a/custom_mutators/examples/example.c +++ b/custom_mutators/examples/example.c @@ -7,7 +7,7 @@ */ // You need to use -I/path/to/AFLplusplus/include -I. -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" #include #include @@ -26,19 +26,14 @@ static const char *commands[] = { typedef struct my_mutator { - afl_t *afl; + afl_state_t *afl; // any additional data here! size_t trim_size_current; int trimmming_steps; int cur_step; - // Reused buffers: - BUF_VAR(u8, fuzz); - BUF_VAR(u8, data); - BUF_VAR(u8, havoc); - BUF_VAR(u8, trim); - BUF_VAR(u8, post_process); + u8 *mutated_out, *post_process_buf, *trim_buf; } my_mutator_t; @@ -53,7 +48,7 @@ typedef struct my_mutator { * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { srand(seed); // needed also by surgical_havoc_mutate() @@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { } + if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) { + + perror("afl_custom_init malloc"); + return NULL; + + } + + if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) { + + perror("afl_custom_init malloc"); + return NULL; + + } + + if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) { + + perror("afl_custom_init malloc"); + return NULL; + + } + data->afl = afl; return data; @@ -96,31 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, // the fuzzer size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; - // maybe_grow is optimized to be quick for reused buffers. - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } + memcpy(data->mutated_out, buf, buf_size); // Randomly select a command string to add as a header to the packet - memcpy(mutated_out, commands[rand() % 3], 3); + memcpy(data->mutated_out, commands[rand() % 3], 3); - // Mutate the payload of the packet - int i; - for (i = 0; i < 8; ++i) { + if (mutated_size > max_size) { mutated_size = max_size; } - // Randomly perform one of the (no len modification) havoc mutations - surgical_havoc_mutate(mutated_out, 3, mutated_size); - - } - - if (max_size > mutated_size) { mutated_size = max_size; } - - *out_buf = mutated_out; + *out_buf = data->mutated_out; return mutated_size; } @@ -144,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { - uint8_t *post_process_buf = - maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); - if (!post_process_buf) { + if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; } - perror("custom mutator realloc failed."); - *out_buf = NULL; - return 0; + memcpy(data->post_process_buf + 5, buf, buf_size); + data->post_process_buf[0] = 'A'; + data->post_process_buf[1] = 'F'; + data->post_process_buf[2] = 'L'; + data->post_process_buf[3] = '+'; + data->post_process_buf[4] = '+'; - } - - memcpy(post_process_buf + 5, buf, buf_size); - post_process_buf[0] = 'A'; - post_process_buf[1] = 'F'; - post_process_buf[2] = 'L'; - post_process_buf[3] = '+'; - post_process_buf[4] = '+'; - - *out_buf = post_process_buf; + *out_buf = data->post_process_buf; return buf_size + 5; @@ -197,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, data->cur_step = 0; - if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { - - perror("init_trim grow"); - return -1; - - } - memcpy(data->trim_buf, buf, buf_size); data->trim_size_current = buf_size; @@ -284,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) { size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t max_size) { - if (buf_size == 0) { - - *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); - if (!*out_buf) { - - perror("custom havoc: maybe_grow"); - return 0; - - } + *out_buf = buf; // in-place mutation - **out_buf = rand() % 256; - buf_size = 1; - - } else { - - // We reuse buf here. It's legal and faster. - *out_buf = buf; - - } + if (buf_size <= sizeof(size_t)) { return buf_size; } - size_t victim = rand() % buf_size; + size_t victim = rand() % (buf_size - sizeof(size_t)); (*out_buf)[victim] += rand() % 10; return buf_size; @@ -371,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, void afl_custom_deinit(my_mutator_t *data) { free(data->post_process_buf); - free(data->havoc_buf); - free(data->data_buf); - free(data->fuzz_buf); + free(data->mutated_out); free(data->trim_buf); free(data); diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c index 3cb018a6..6737c627 100644 --- a/custom_mutators/examples/post_library_gif.so.c +++ b/custom_mutators/examples/post_library_gif.so.c @@ -45,9 +45,8 @@ 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` and return the original `len`. - NOTE: the following is currently NOT true, we abort in this case! 2) If you want to skip this test case altogether and have AFL generate a - new one, return 0 or set `*out_buf = NULL`. + new one, return 0. Use this sparingly - it's faster than running the target program with patently useless inputs, but still wastes CPU time. @@ -59,8 +58,6 @@ Note that the buffer will *not* be freed for you. To avoid memory leaks, you need to free it or reuse it on subsequent calls (as shown below). - *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - Alright. The example below shows a simple postprocessor that tries to make sure that all input files start with "GIF89a". @@ -72,7 +69,7 @@ #include #include #include -#include "alloc-inl.h" +#include "afl-fuzz.h" /* Header that must be present at the beginning of every test case: */ @@ -80,8 +77,7 @@ typedef struct post_state { - unsigned char *buf; - size_t size; + size_t size; } post_state_t; @@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) { } - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - return state; } @@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) { size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, unsigned int len, unsigned char **out_buf) { + /* we do in-place modification as we do not increase the size */ + + *out_buf = in_buf; + /* Skip execution altogether for buffers shorter than 6 bytes (just to show how it's done). We can trust len to be sane. */ @@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, /* Do nothing for buffers that already start with the expected header. */ - if (!memcmp(in_buf, HEADER, strlen(HEADER))) { - - *out_buf = in_buf; - return len; - - } - - /* Allocate memory for new buffer, reusing previous allocation if - possible. Note we have to use afl-fuzz's own realloc! - We use afl_realloc because it is effective. - You can also work within in_buf, and assign it to *out_buf. */ - - *out_buf = afl_realloc(out_buf, len); - - /* If we're out of memory, the most graceful thing to do is to return the - original buffer and give up on modifying it. Let AFL handle OOM on its - own later on. */ - - if (!*out_buf) { - - *out_buf = in_buf; - return len; - - } - - if (len > strlen(HEADER)) - memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER), - len - strlen(HEADER)); + if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; } /* Insert the new header. */ @@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, /* Gets called afterwards */ void afl_custom_deinit(post_state_t *data) { - free(data->buf); free(data); } diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c index cd65b1bc..652da497 100644 --- a/custom_mutators/examples/post_library_png.so.c +++ b/custom_mutators/examples/post_library_png.so.c @@ -30,7 +30,7 @@ #include #include #include -#include "alloc-inl.h" +#include "afl-fuzz.h" /* A macro to round an integer up to 4 kB. */ @@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) { } - state->buf = calloc(sizeof(unsigned char), 4096); + state->buf = calloc(sizeof(unsigned char), MAX_FILE); if (!state->buf) { free(state); @@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, } - /* This is not a good way to do it, if you do not need to grow the buffer - then just work with in_buf instead for speed reasons. - But we want to show how to grow a buffer, so this is how it's done: */ - - unsigned int pos = 8; - unsigned char *new_buf = afl_realloc(out_buf, UP4K(len)); - - if (!new_buf) { - - *out_buf = in_buf; - return len; - - } - - memcpy(new_buf, in_buf, len); + unsigned int pos = 8; /* Minimum size of a zero-length PNG chunk is 12 bytes; if we don't have that, we can bail out. */ @@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, if (real_cksum != file_cksum) { - *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; + *(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum; } @@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, } - *out_buf = new_buf; + *out_buf = data->buf; return len; } diff --git a/custom_mutators/examples/simple_example.c b/custom_mutators/examples/simple_example.c index d888ec1f..2c0abe29 100644 --- a/custom_mutators/examples/simple_example.c +++ b/custom_mutators/examples/simple_example.c @@ -1,6 +1,6 @@ // This simple example just creates random buffer <= 100 filled with 'A' // needs -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" #include #include @@ -13,14 +13,14 @@ typedef struct my_mutator { - afl_t *afl; + afl_state_t *afl; // Reused buffers: - BUF_VAR(u8, fuzz); + u8 *fuzz_buf; } my_mutator_t; -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { srand(seed); my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); @@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { } + data->fuzz_buf = (u8 *)malloc(MAX_FILE); + if (!data->fuzz_buf) { + + perror("afl_custom_init malloc"); + return NULL; + + } + data->afl = afl; return data; @@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, int size = (rand() % 100) + 1; if (size > max_size) size = max_size; - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - memset(mutated_out, _FIXED_CHAR, size); + memset(data->fuzz_buf, _FIXED_CHAR, size); - *out_buf = mutated_out; + *out_buf = data->fuzz_buf; return size; } -- cgit 1.4.1 From 70e30958649f44e104330431cde31e80fbd8557f Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: added first dummy atnwalk.c file --- custom_mutators/atnwalk/atnwalk.c | 173 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 custom_mutators/atnwalk/atnwalk.c (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c new file mode 100644 index 00000000..483ae542 --- /dev/null +++ b/custom_mutators/atnwalk/atnwalk.c @@ -0,0 +1,173 @@ +#include "../../include/afl-fuzz.h" + +#include +#include +#include +#include +#include +#include + + +#define INIT_BUF_SIZE 4096 +#define SOCKET_NAME "/tmp/atnwalk.socket" + +// handshake constants +const uint8_t SERVER_ARE_YOU_ALIVE = 42; +const uint8_t SERVER_YES_I_AM_ALIVE = 213; + +// control bits +const uint8_t SERVER_DECODE_BIT = 0b00000001; +const uint8_t SERVER_ENCODE_BIT = 0b00000010; +const uint8_t SERVER_MUTATE_BIT = 0b00000100; +const uint8_t SERVER_CROSSOVER_BIT = 0b00001000; + + +typedef struct atnwalk_mutator { + uint8_t *decoded_buf; + size_t decoded_size; +} atnwalk_mutator_t; + + +int read_all(int fd, uint8_t *buf, size_t buf_size) { + int n; + size_t offset = 0; + while (offset < buf_size) { + n = read(fd, buf + offset, buf_size - offset); + if (n == -1) { + return 0; + } + offset += n; + } + return 1; +} + + +int write_all(int fd, uint8_t *buf, size_t buf_size) { + int n; + size_t offset = 0; + while (offset < buf_size) { + n = write(fd, buf + offset, buf_size - offset); + if (n == -1) { + return 0; + } + offset += n; + } + return 1; +} + + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { + srand(seed); + atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); + if (!data) { + perror("afl_custom_init alloc"); + return NULL; + } + data->decoded_buf = (uint8_t *) malloc(INIT_BUF_SIZE); + data->decoded_size = INIT_BUF_SIZE; + return data; +} + +// TODO: implement +/** + * Perform custom mutations on a given input + * + * (Optional for now. Required in the future) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf, + uint8_t *add_buf, size_t add_buf_size, size_t max_size) { + struct sockaddr_un addr; + int fd_socket; + ssize_t n; + uint8_t buffer[5]; + + // initialize the socket + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd_socket == -1) { + perror("socket"); + *out_buf = NULL; + return 0; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { + perror("atnwalk server is down"); + *out_buf = NULL; + return 0; + } + + if (!write_all(fd_socket, buffer, 5)) { + perror("write to atnwalk server failed"); + *out_buf = NULL; + return 0; + } + + if (read_all(fd_socket, buffer, 5)) { + perror("read to atnwalk server failed"); + exit(EXIT_FAILURE); + } + + close(fd_socket); +} + +// TODO: implement +/** + * A post-processing function to use right before AFL writes the test case to + * disk in order to execute the target. + * + * (Optional) If this functionality is not needed, simply don't define this + * function. + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Buffer containing the test case to be executed + * @param[in] buf_size Size of the test case + * @param[out] out_buf Pointer to the buffer containing the test case after + * processing. External library should allocate memory for out_buf. + * The buf pointer may be reused (up to the given buf_size); + * @return Size of the output buffer after processing or the needed amount. + * A return of 0 indicates an error. + */ +size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { + data->decoded_buf[0] = 'p'; + data->decoded_buf[1] = 'u'; + data->decoded_buf[2] = 't'; + data->decoded_buf[3] = 's'; + data->decoded_buf[4] = ' '; + data->decoded_buf[5] = ';'; + data->decoded_buf[6] = '\n'; + return 7; +} + +// TODO: implement +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(atnwalk_mutator_t *data) { + free(data->decoded_buf); + free(data); +} -- cgit 1.4.1 From a3bc8d3440acefb7168c849337e4a4841bf11c3d Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: fixed wrong implementation of control bits in atnwalk.c --- custom_mutators/atnwalk/atnwalk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 483ae542..cc9f9618 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -16,10 +16,10 @@ const uint8_t SERVER_ARE_YOU_ALIVE = 42; const uint8_t SERVER_YES_I_AM_ALIVE = 213; // control bits -const uint8_t SERVER_DECODE_BIT = 0b00000001; -const uint8_t SERVER_ENCODE_BIT = 0b00000010; -const uint8_t SERVER_MUTATE_BIT = 0b00000100; -const uint8_t SERVER_CROSSOVER_BIT = 0b00001000; +const uint8_t SERVER_CROSSOVER_BIT = 0b00000001; +const uint8_t SERVER_MUTATE_BIT = 0b00000010; +const uint8_t SERVER_DECODE_BIT = 0b00000100; +const uint8_t SERVER_ENCODE_BIT = 0b00001000; typedef struct atnwalk_mutator { -- cgit 1.4.1 From 450dbae8cd2ae278e0b381d172cb7694f40278cb Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: first version with unix domain sockets is ready for testing --- custom_mutators/atnwalk/atnwalk.c | 254 +++++++++++++++++++++++++++++++++----- src/afl-fuzz-run.c | 11 +- 2 files changed, 232 insertions(+), 33 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index cc9f9618..584add61 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -1,5 +1,4 @@ -#include "../../include/afl-fuzz.h" - +#include #include #include #include @@ -7,10 +6,10 @@ #include #include - #define INIT_BUF_SIZE 4096 #define SOCKET_NAME "/tmp/atnwalk.socket" + // handshake constants const uint8_t SERVER_ARE_YOU_ALIVE = 42; const uint8_t SERVER_YES_I_AM_ALIVE = 213; @@ -23,8 +22,10 @@ const uint8_t SERVER_ENCODE_BIT = 0b00001000; typedef struct atnwalk_mutator { - uint8_t *decoded_buf; - size_t decoded_size; + uint8_t *fuzz_buf; + size_t fuzz_size; + uint8_t *post_process_buf; + size_t post_process_size; } atnwalk_mutator_t; @@ -55,6 +56,32 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) { return 1; } +void put_uint32(uint8_t *buf, uint32_t val) { + buf[0] = (uint8_t) (val >> 24); + buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16); + buf[2] = (uint8_t) ((val & 0x0000ff00) >> 8); + buf[3] = (uint8_t) (val & 0x000000ff); +} + +uint32_t to_uint32(uint8_t *buf) { + uint32_t val = 0; + val |= (((uint32_t) buf[0]) << 24); + val |= (((uint32_t) buf[1]) << 16); + val |= (((uint32_t) buf[2]) << 8); + val |= ((uint32_t) buf[3]); + return val; +} + +void put_uint64(uint8_t *buf, uint64_t val) { + buf[0] = (uint8_t) (val >> 56); + buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48); + buf[2] = (uint8_t) ((val & 0x0000ff0000000000) >> 40); + buf[3] = (uint8_t) ((val & 0x000000ff00000000) >> 32); + buf[4] = (uint8_t) ((val & 0x00000000ff000000) >> 24); + buf[5] = (uint8_t) ((val & 0x0000000000ff0000) >> 16); + buf[6] = (uint8_t) ((val & 0x000000000000ff00) >> 8); + buf[7] = (uint8_t) (val & 0x00000000000000ff); +} /** * Initialize this custom mutator @@ -67,19 +94,21 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) { * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ -atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { +atnwalk_mutator_t *afl_custom_init(void *afl, unsigned int seed) { srand(seed); atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); if (!data) { perror("afl_custom_init alloc"); return NULL; } - data->decoded_buf = (uint8_t *) malloc(INIT_BUF_SIZE); - data->decoded_size = INIT_BUF_SIZE; + data->fuzz_buf = (uint8_t *) malloc(INIT_BUF_SIZE); + data->fuzz_size = INIT_BUF_SIZE; + data->post_process_buf = (uint8_t *) malloc(INIT_BUF_SIZE); + data->post_process_size = INIT_BUF_SIZE; return data; } -// TODO: implement + /** * Perform custom mutations on a given input * @@ -100,13 +129,12 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u uint8_t *add_buf, size_t add_buf_size, size_t max_size) { struct sockaddr_un addr; int fd_socket; - ssize_t n; - uint8_t buffer[5]; + uint8_t ctrl_buf[8]; + uint8_t wanted; // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (fd_socket == -1) { - perror("socket"); *out_buf = NULL; return 0; } @@ -114,26 +142,127 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - perror("atnwalk server is down"); + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // TODO: how to set connection deadline? maybe not required if server already closes the connection? + + // TODO: there should be some kind of loop retrying with different seeds and ultimately giving up on that input? + // maybe this is not necessary, because we may also just return a single byte in case of failure? + + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { + close(fd_socket); *out_buf = NULL; return 0; } - if (!write_all(fd_socket, buffer, 5)) { - perror("write to atnwalk server failed"); + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // tell the server what we want to do + wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; + + // 50% chance to perform a crossover if there is an additional buffer available + if ((add_buf_size > 0) && (rand() % 2)) { + wanted |= SERVER_CROSSOVER_BIT; + } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = wanted; + put_uint32(ctrl_buf + 1, (uint32_t) buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + close(fd_socket); *out_buf = NULL; return 0; } - if (read_all(fd_socket, buffer, 5)) { - perror("read to atnwalk server failed"); - exit(EXIT_FAILURE); + // send the data to mutate and encode + if (!write_all(fd_socket, buf, buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + if (wanted & SERVER_CROSSOVER_BIT) { + // since we requested crossover, we will first tell how much additional data is to be expected + put_uint32(ctrl_buf, (uint32_t) add_buf_size); + if (!write_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // send the additional data for crossover + if (!write_all(fd_socket, add_buf, add_buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // lastly, a seed is required for crossover so send one + put_uint64(ctrl_buf, (uint64_t) rand()); + if (!write_all(fd_socket, ctrl_buf, 8)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + } + + // since we requested mutation, we need to provide a seed for that + put_uint64(ctrl_buf, (uint64_t) rand()); + if (!write_all(fd_socket, ctrl_buf, 8)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + size_t new_size = (size_t) to_uint32(ctrl_buf); + + // if the data is too large then we ignore this round + if (new_size > max_size) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + if (new_size > buf_size) { + // buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate + if (new_size > data->fuzz_size) { + data->fuzz_size = new_size << 1; + data->fuzz_buf = (uint8_t *) realloc(data->fuzz_buf, data->fuzz_size); + } + *out_buf = data->fuzz_buf; + } else { + // new_size fits into buf, so re-use it + *out_buf = buf; + } + + // obtain the encoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; } close(fd_socket); + return new_size; } -// TODO: implement + /** * A post-processing function to use right before AFL writes the test case to * disk in order to execute the target. @@ -151,23 +280,90 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u * A return of 0 indicates an error. */ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { - data->decoded_buf[0] = 'p'; - data->decoded_buf[1] = 'u'; - data->decoded_buf[2] = 't'; - data->decoded_buf[3] = 's'; - data->decoded_buf[4] = ' '; - data->decoded_buf[5] = ';'; - data->decoded_buf[6] = '\n'; - return 7; + struct sockaddr_un addr; + int fd_socket; + uint8_t ctrl_buf[8]; + + // initialize the socket + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd_socket == -1) { + *out_buf = NULL; + return 0; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = SERVER_DECODE_BIT; + put_uint32(ctrl_buf + 1, (uint32_t) buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // send the data to decode + if (!write_all(fd_socket, buf, buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + size_t new_size = (size_t) to_uint32(ctrl_buf); + + // need to use data->post_process_buf, let's see whether we need to reallocate + if (new_size > data->post_process_size) { + data->post_process_size = new_size << 1; + data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size); + } + *out_buf = data->post_process_buf; + + // obtain the decoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + close(fd_socket); + return new_size; } -// TODO: implement + /** * Deinitialize everything * * @param data The data ptr from afl_custom_init */ void afl_custom_deinit(atnwalk_mutator_t *data) { - free(data->decoded_buf); + free(data->fuzz_buf); + free(data->post_process_buf); free(data); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ee4a3298..26a1ea36 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -130,12 +130,15 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { new_size = afl->max_length; } - - if (new_mem != *mem) { *mem = new_mem; } + // TODO: think about how to enable the change without breaking other implementations + // if (new_mem != *mem) { *mem = new_mem; } /* everything as planned. use the potentially new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); - len = new_size; + // TODO: think about how to enable the change without breaking other implementations + afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); + + // TODO: think about how to enable the change without breaking other implementations + // len = new_size; } else { -- cgit 1.4.1 From e55b5c54080698ee2efe317321c1f387c225115b Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: fixed the server handshake commands, works now --- custom_mutators/atnwalk/atnwalk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 584add61..387d8b5d 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -11,8 +11,8 @@ // handshake constants -const uint8_t SERVER_ARE_YOU_ALIVE = 42; -const uint8_t SERVER_YES_I_AM_ALIVE = 213; +const uint8_t SERVER_ARE_YOU_ALIVE = 213; +const uint8_t SERVER_YES_I_AM_ALIVE = 42; // control bits const uint8_t SERVER_CROSSOVER_BIT = 0b00000001; -- cgit 1.4.1 From 529a51c16053125ff0ddce7c6bd149f4ebe65461 Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: implemented status screen and 50% havoc and 50% splice schedule with limited rounds per queue entry --- custom_mutators/atnwalk/atnwalk.c | 137 ++++++++++++++++++++++++++++++++++---- 1 file changed, 124 insertions(+), 13 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 387d8b5d..0194ff18 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -1,3 +1,5 @@ +#include "../../include/afl-fuzz.h" + #include #include #include @@ -6,9 +8,14 @@ #include #include -#define INIT_BUF_SIZE 4096 +#define BUF_SIZE_INIT 4096 #define SOCKET_NAME "/tmp/atnwalk.socket" +// how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry +#define ATNWALK_ERRORS_MAX 1 + +// how many execution timeouts to tolerate until moving on to the next queue entry +#define EXEC_TIMEOUT_MAX 2 // handshake constants const uint8_t SERVER_ARE_YOU_ALIVE = 213; @@ -22,6 +29,14 @@ const uint8_t SERVER_ENCODE_BIT = 0b00001000; typedef struct atnwalk_mutator { + afl_state_t *afl; + uint8_t atnwalk_error_count; + uint64_t prev_timeouts; + uint32_t prev_hits; + uint32_t stage_havoc_cur; + uint32_t stage_havoc_max; + uint32_t stage_splice_cur; + uint32_t stage_splice_max; uint8_t *fuzz_buf; size_t fuzz_size; uint8_t *post_process_buf; @@ -56,6 +71,7 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) { return 1; } + void put_uint32(uint8_t *buf, uint32_t val) { buf[0] = (uint8_t) (val >> 24); buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16); @@ -63,6 +79,7 @@ void put_uint32(uint8_t *buf, uint32_t val) { buf[3] = (uint8_t) (val & 0x000000ff); } + uint32_t to_uint32(uint8_t *buf) { uint32_t val = 0; val |= (((uint32_t) buf[0]) << 24); @@ -72,6 +89,7 @@ uint32_t to_uint32(uint8_t *buf) { return val; } + void put_uint64(uint8_t *buf, uint64_t val) { buf[0] = (uint8_t) (val >> 56); buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48); @@ -83,6 +101,7 @@ void put_uint64(uint8_t *buf, uint64_t val) { buf[7] = (uint8_t) (val & 0x00000000000000ff); } + /** * Initialize this custom mutator * @@ -94,21 +113,48 @@ void put_uint64(uint8_t *buf, uint64_t val) { * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ -atnwalk_mutator_t *afl_custom_init(void *afl, unsigned int seed) { +atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { srand(seed); atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); if (!data) { perror("afl_custom_init alloc"); return NULL; } - data->fuzz_buf = (uint8_t *) malloc(INIT_BUF_SIZE); - data->fuzz_size = INIT_BUF_SIZE; - data->post_process_buf = (uint8_t *) malloc(INIT_BUF_SIZE); - data->post_process_size = INIT_BUF_SIZE; + data->afl = afl; + data->prev_hits = 0; + data->fuzz_buf = (uint8_t *) malloc(BUF_SIZE_INIT); + data->fuzz_size = BUF_SIZE_INIT; + data->post_process_buf = (uint8_t *) malloc(BUF_SIZE_INIT); + data->post_process_size = BUF_SIZE_INIT; return data; } +unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, const unsigned char *buf, size_t buf_size) { + // afl_custom_fuzz_count is called exactly once before entering the 'stage-loop' for the current queue entry + // thus, we use it to reset the error count and to initialize stage variables (somewhat not intended by the API, + // but still better than rewriting the whole thing to have a custom mutator stage) + data->atnwalk_error_count = 0; + data->prev_timeouts = data->afl->total_tmouts; + + // it might happen that on the last execution of the splice stage a new path is found + // we need to fix that here and count it + if (data->prev_hits) { + data->afl->stage_finds[STAGE_SPLICE] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; + } + data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; + data->stage_havoc_cur = 0; + data->stage_splice_cur = 0; + + // 50% havoc, 50% splice + data->stage_havoc_max = data->afl->stage_max >> 1; + if (data->stage_havoc_max < HAVOC_MIN) { + data->stage_havoc_max = HAVOC_MIN; + } + data->stage_splice_max = data->stage_havoc_max; + return data->stage_havoc_max + data->stage_splice_max; +} + /** * Perform custom mutations on a given input * @@ -132,6 +178,48 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u uint8_t ctrl_buf[8]; uint8_t wanted; + // let's display what's going on in a nice way + if (data->stage_havoc_cur == 0) { + data->afl->stage_name = (uint8_t *) "atnwalk - havoc"; + } + if (data->stage_havoc_cur == data->stage_havoc_max) { + data->afl->stage_name = (uint8_t *) "atnwalk - splice"; + } + + // increase the respective havoc or splice counters + if (data->stage_havoc_cur < data->stage_havoc_max) { + data->stage_havoc_cur++; + data->afl->stage_cycles[STAGE_HAVOC]++; + } else { + // if there is nothing to splice, continue with havoc and skip splicing this time + if (data->afl->ready_for_splicing_count < 1) { + data->stage_havoc_max = data->afl->stage_max; + data->stage_havoc_cur++; + data->afl->stage_cycles[STAGE_HAVOC]++; + } else { + data->stage_splice_cur++; + data->afl->stage_cycles[STAGE_SPLICE]++; + } + } + + // keep track of found new corpus seeds per stage and run the stage twice as long as initially planned + if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { + if (data->stage_splice_cur <= 1) { + data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; + } else { + data->afl->stage_finds[STAGE_SPLICE] += + data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; + } + } + data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; + + // check whether this input produces a lot of timeouts, if it does then abandon this queue entry + if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) { + data->afl->stage_max = data->afl->stage_cur; + *out_buf = buf; + return buf_size; + } + // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (fd_socket == -1) { @@ -147,11 +235,6 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u return 0; } - // TODO: how to set connection deadline? maybe not required if server already closes the connection? - - // TODO: there should be some kind of loop retrying with different seeds and ultimately giving up on that input? - // maybe this is not necessary, because we may also just return a single byte in case of failure? - // ask whether the server is alive ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; if (!write_all(fd_socket, ctrl_buf, 1)) { @@ -170,8 +253,8 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // tell the server what we want to do wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; - // 50% chance to perform a crossover if there is an additional buffer available - if ((add_buf_size > 0) && (rand() % 2)) { + // perform a crossover if we are splicing + if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; } @@ -196,6 +279,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u put_uint32(ctrl_buf, (uint32_t) add_buf_size); if (!write_all(fd_socket, ctrl_buf, 4)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -203,6 +290,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // send the additional data for crossover if (!write_all(fd_socket, add_buf, add_buf_size)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -211,6 +302,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -220,6 +315,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -227,6 +326,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // obtain the required buffer size for the data that will be returned if (!read_all(fd_socket, ctrl_buf, 4)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -235,6 +338,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // if the data is too large then we ignore this round if (new_size > max_size) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } @@ -254,6 +361,10 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // obtain the encoded data if (!read_all(fd_socket, *out_buf, new_size)) { close(fd_socket); + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } *out_buf = buf; return buf_size; } -- cgit 1.4.1 From 9ab902402cd33156257fc0355c0105e7e03f5ba3 Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: fixed code clones in atnwalk.c, introduced new environment variable AFL_POST_PROCESS_KEEP_ORIGINAL in AFL++ to integrate atnwalk without re-compiling afl-fuzz --- custom_mutators/atnwalk/atnwalk.c | 144 +++++++++++++------------------------- include/afl-fuzz.h | 4 +- include/envs.h | 1 + src/afl-fuzz-run.c | 11 +-- src/afl-fuzz-state.c | 7 ++ src/afl-fuzz.c | 2 + 6 files changed, 66 insertions(+), 103 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 0194ff18..901b8a9e 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -1,4 +1,4 @@ -#include "../../include/afl-fuzz.h" +#include "afl-fuzz.h" #include #include @@ -9,7 +9,7 @@ #include #define BUF_SIZE_INIT 4096 -#define SOCKET_NAME "/tmp/atnwalk.socket" +#define SOCKET_NAME "./atnwalk.socket" // how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry #define ATNWALK_ERRORS_MAX 1 @@ -155,6 +155,29 @@ unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, const unsigned char return data->stage_havoc_max + data->stage_splice_max; } + +size_t fail_fatal(int fd_socket, uint8_t **out_buf) { + if (fd_socket != -1) { + close(fd_socket); + } + *out_buf = NULL; + return 0; +} + + +size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { + if (fd_socket != -1) { + close(fd_socket); + } + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } + *out_buf = buf; + return buf_size; +} + + /** * Perform custom mutations on a given input * @@ -202,7 +225,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u } } - // keep track of found new corpus seeds per stage and run the stage twice as long as initially planned + // keep track of found new corpus seeds per stage if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { if (data->stage_splice_cur <= 1) { data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; @@ -216,38 +239,28 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // check whether this input produces a lot of timeouts, if it does then abandon this queue entry if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) { data->afl->stage_max = data->afl->stage_cur; - *out_buf = buf; - return buf_size; + return fail_gracefully(-1, data, buf, buf_size, out_buf); } // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd_socket == -1) { - *out_buf = NULL; - return 0; - } + if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // ask whether the server is alive ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; if (!write_all(fd_socket, ctrl_buf, 1)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // see whether the server replies as expected if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // tell the server what we want to do @@ -262,88 +275,48 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u ctrl_buf[0] = wanted; put_uint32(ctrl_buf + 1, (uint32_t) buf_size); if (!write_all(fd_socket, ctrl_buf, 5)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // send the data to mutate and encode if (!write_all(fd_socket, buf, buf_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } if (wanted & SERVER_CROSSOVER_BIT) { // since we requested crossover, we will first tell how much additional data is to be expected put_uint32(ctrl_buf, (uint32_t) add_buf_size); if (!write_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // send the additional data for crossover if (!write_all(fd_socket, add_buf, add_buf_size)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // lastly, a seed is required for crossover so send one put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } } // since we requested mutation, we need to provide a seed for that put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // obtain the required buffer size for the data that will be returned if (!read_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } size_t new_size = (size_t) to_uint32(ctrl_buf); // if the data is too large then we ignore this round if (new_size > max_size) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } if (new_size > buf_size) { @@ -360,13 +333,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // obtain the encoded data if (!read_all(fd_socket, *out_buf, new_size)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } close(fd_socket); @@ -398,54 +365,41 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (fd_socket == -1) { - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // ask whether the server is alive ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; if (!write_all(fd_socket, ctrl_buf, 1)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // see whether the server replies as expected if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // tell the server what we want and how much data will be sent ctrl_buf[0] = SERVER_DECODE_BIT; put_uint32(ctrl_buf + 1, (uint32_t) buf_size); if (!write_all(fd_socket, ctrl_buf, 5)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // send the data to decode if (!write_all(fd_socket, buf, buf_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // obtain the required buffer size for the data that will be returned if (!read_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } size_t new_size = (size_t) to_uint32(ctrl_buf); @@ -458,9 +412,7 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf // obtain the decoded data if (!read_all(fd_socket, *out_buf, new_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } close(fd_socket); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 23c20cc4..5d9b17e7 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -386,8 +386,8 @@ typedef struct afl_env_vars { afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems, - afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme, - afl_no_startup_calibration; + afl_keep_timeouts, afl_pizza_mode, afl_post_process_keep_original, + afl_no_crash_readme, afl_no_startup_calibration; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, diff --git a/include/envs.h b/include/envs.h index 2204a100..1527dfcb 100644 --- a/include/envs.h +++ b/include/envs.h @@ -177,6 +177,7 @@ static char *afl_environment_variables[] = { "AFL_PATH", "AFL_PERFORMANCE_FILE", "AFL_PERSISTENT_RECORD", + "AFL_POST_PROCESS_KEEP_ORIGINAL", "AFL_PRELOAD", "AFL_TARGET_ENV", "AFL_PYTHON_MODULE", diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 26a1ea36..3c3d4817 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -130,15 +130,16 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { new_size = afl->max_length; } - // TODO: think about how to enable the change without breaking other implementations - // if (new_mem != *mem) { *mem = new_mem; } /* everything as planned. use the potentially new data. */ - // TODO: think about how to enable the change without breaking other implementations afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); - // TODO: think about how to enable the change without breaking other implementations - // len = new_size; + if (likely(!afl->afl_env.afl_post_process_keep_original)) { + + if (new_mem != *mem) { *mem = new_mem; } + len = new_size; + + } } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0576f84f..10bc2768 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -377,6 +377,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_post_process_keep_original = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 1f0fcab1..b83af257 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -284,6 +284,8 @@ static void usage(u8 *argv0, int more_help) { PERSISTENT_MSG + "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n" + " but execute the post-processed one\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" -- cgit 1.4.1 From d7e6f8cb386a24b5ec090caa6befe27461cd2190 Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:10:19 +0200 Subject: Create README.md --- custom_mutators/atnwalk/README.md | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 custom_mutators/atnwalk/README.md (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/README.md b/custom_mutators/atnwalk/README.md new file mode 100644 index 00000000..badb856f --- /dev/null +++ b/custom_mutators/atnwalk/README.md @@ -0,0 +1,45 @@ +# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations + +This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets. + +Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running. + +## Build + +```bash +gcc -I ../../include/ -shared -fPIC -Wall -O3 atnwalk.c -o atnwalk.so +``` + +## Run + +**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed) + +```bash +# create the required a random seed first +mkdir -p ~/campaign/example/seeds +cd ~/campaign/example/seeds +head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded + +# create the required atnwalk directory and copy the seed +cd ../ +mkdir -p atnwalk/in +cp ./seeds/seed.encoded atnwalk/in/seed +cd atnwalk + +# assign to a single core when benchmarking it, change the CPU number as required +CPU_ID=0 + +# start the ATNwalk server +nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 & + +# start AFL++ with ATNwalk +AFL_SKIP_CPUFREQ=1 \ + AFL_DISABLE_TRIM=1 \ + AFL_CUSTOM_MUTATOR_ONLY=1 \ + AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \ + AFL_POST_PROCESS_KEEP_ORIGINAL=1 \ + ~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry + +# make sure to kill the ATNwalk server process after you're done +kill "$(cat atnwalk.pid)" +``` -- cgit 1.4.1 From 6bd48a48cbed1f923ff0999ea24af1f548c2e2bc Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 22 Apr 2023 11:39:44 +0200 Subject: code format --- custom_mutators/README.md | 33 +- custom_mutators/atnwalk/atnwalk.c | 681 ++++++++++++++++++++++---------------- docs/Changelog.md | 4 + frida_mode/src/js/js_api.c | 4 +- 4 files changed, 423 insertions(+), 299 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/README.md b/custom_mutators/README.md index 8d01856f..a5a572c0 100644 --- a/custom_mutators/README.md +++ b/custom_mutators/README.md @@ -11,7 +11,20 @@ The `./examples` folder contains examples for custom mutators in python and C. In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`. -## The AFL++ grammar agnostic grammar mutator +## Production-Ready Custom Mutators + +This directory holds ready to use custom mutators. +Just type "make" in the individual subdirectories. + +Use with e.g. + +`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....` + +and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator. + +Multiple custom mutators can be used by separating their paths with `:` in the environment variable. + +### The AFL++ grammar agnostic grammar mutator In `./autotokens` you find a token-level fuzzer that does not need to know anything about the grammar of an input as long as it is in ascii and allows @@ -21,7 +34,7 @@ It is very fast and effective. If you are looking for an example of how to effectively create a custom mutator take a look at this one. -## The AFL++ Grammar Mutator +### The AFL++ Grammar Mutator If you use git to clone AFL++, then the following will incorporate our excellent grammar custom mutator: @@ -34,18 +47,18 @@ Read the README in the [Grammar-Mutator] repository on how to use it. [Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator -## Production-Ready Custom Mutators - -This directory holds ready to use custom mutators. -Just type "make" in the individual subdirectories. +Note that this custom mutator is not very good though! -Use with e.g. +### Other Mutators -`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....` +atnwalk and gramatron are grammar custom mutators. Example grammars are +provided. -and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator. +honggfuzz, libfuzzer and libafl are partial implementations based on the +mutator implementations of the respective fuzzers. +More for playing than serious usage. -Multiple custom mutators can be used by separating their paths with `:` in the environment variable. +radamsa is slow and not very good. ## 3rd Party Custom Mutators diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 901b8a9e..c3a2cd95 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -11,10 +11,12 @@ #define BUF_SIZE_INIT 4096 #define SOCKET_NAME "./atnwalk.socket" -// how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry +// how many errors (e.g. timeouts) to tolerate until moving on to the next queue +// entry #define ATNWALK_ERRORS_MAX 1 -// how many execution timeouts to tolerate until moving on to the next queue entry +// how many execution timeouts to tolerate until moving on to the next queue +// entry #define EXEC_TIMEOUT_MAX 2 // handshake constants @@ -27,80 +29,87 @@ const uint8_t SERVER_MUTATE_BIT = 0b00000010; const uint8_t SERVER_DECODE_BIT = 0b00000100; const uint8_t SERVER_ENCODE_BIT = 0b00001000; - typedef struct atnwalk_mutator { - afl_state_t *afl; - uint8_t atnwalk_error_count; - uint64_t prev_timeouts; - uint32_t prev_hits; - uint32_t stage_havoc_cur; - uint32_t stage_havoc_max; - uint32_t stage_splice_cur; - uint32_t stage_splice_max; - uint8_t *fuzz_buf; - size_t fuzz_size; - uint8_t *post_process_buf; - size_t post_process_size; -} atnwalk_mutator_t; + afl_state_t *afl; + uint8_t atnwalk_error_count; + uint64_t prev_timeouts; + uint32_t prev_hits; + uint32_t stage_havoc_cur; + uint32_t stage_havoc_max; + uint32_t stage_splice_cur; + uint32_t stage_splice_max; + uint8_t *fuzz_buf; + size_t fuzz_size; + uint8_t *post_process_buf; + size_t post_process_size; + +} atnwalk_mutator_t; int read_all(int fd, uint8_t *buf, size_t buf_size) { - int n; - size_t offset = 0; - while (offset < buf_size) { - n = read(fd, buf + offset, buf_size - offset); - if (n == -1) { - return 0; - } - offset += n; - } - return 1; -} + int n; + size_t offset = 0; + while (offset < buf_size) { + + n = read(fd, buf + offset, buf_size - offset); + if (n == -1) { return 0; } + offset += n; + + } + + return 1; -int write_all(int fd, uint8_t *buf, size_t buf_size) { - int n; - size_t offset = 0; - while (offset < buf_size) { - n = write(fd, buf + offset, buf_size - offset); - if (n == -1) { - return 0; - } - offset += n; - } - return 1; } +int write_all(int fd, uint8_t *buf, size_t buf_size) { + + int n; + size_t offset = 0; + while (offset < buf_size) { + + n = write(fd, buf + offset, buf_size - offset); + if (n == -1) { return 0; } + offset += n; + + } + + return 1; -void put_uint32(uint8_t *buf, uint32_t val) { - buf[0] = (uint8_t) (val >> 24); - buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16); - buf[2] = (uint8_t) ((val & 0x0000ff00) >> 8); - buf[3] = (uint8_t) (val & 0x000000ff); } +void put_uint32(uint8_t *buf, uint32_t val) { + + buf[0] = (uint8_t)(val >> 24); + buf[1] = (uint8_t)((val & 0x00ff0000) >> 16); + buf[2] = (uint8_t)((val & 0x0000ff00) >> 8); + buf[3] = (uint8_t)(val & 0x000000ff); -uint32_t to_uint32(uint8_t *buf) { - uint32_t val = 0; - val |= (((uint32_t) buf[0]) << 24); - val |= (((uint32_t) buf[1]) << 16); - val |= (((uint32_t) buf[2]) << 8); - val |= ((uint32_t) buf[3]); - return val; } +uint32_t to_uint32(uint8_t *buf) { + + uint32_t val = 0; + val |= (((uint32_t)buf[0]) << 24); + val |= (((uint32_t)buf[1]) << 16); + val |= (((uint32_t)buf[2]) << 8); + val |= ((uint32_t)buf[3]); + return val; -void put_uint64(uint8_t *buf, uint64_t val) { - buf[0] = (uint8_t) (val >> 56); - buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48); - buf[2] = (uint8_t) ((val & 0x0000ff0000000000) >> 40); - buf[3] = (uint8_t) ((val & 0x000000ff00000000) >> 32); - buf[4] = (uint8_t) ((val & 0x00000000ff000000) >> 24); - buf[5] = (uint8_t) ((val & 0x0000000000ff0000) >> 16); - buf[6] = (uint8_t) ((val & 0x000000000000ff00) >> 8); - buf[7] = (uint8_t) (val & 0x00000000000000ff); } +void put_uint64(uint8_t *buf, uint64_t val) { + + buf[0] = (uint8_t)(val >> 56); + buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); + buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); + buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32); + buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24); + buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); + buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); + buf[7] = (uint8_t)(val & 0x00000000000000ff); + +} /** * Initialize this custom mutator @@ -114,69 +123,82 @@ void put_uint64(uint8_t *buf, uint64_t val) { * Return NULL on error. */ atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { - srand(seed); - atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); - if (!data) { - perror("afl_custom_init alloc"); - return NULL; - } - data->afl = afl; - data->prev_hits = 0; - data->fuzz_buf = (uint8_t *) malloc(BUF_SIZE_INIT); - data->fuzz_size = BUF_SIZE_INIT; - data->post_process_buf = (uint8_t *) malloc(BUF_SIZE_INIT); - data->post_process_size = BUF_SIZE_INIT; - return data; -} + srand(seed); + atnwalk_mutator_t *data = + (atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t)); + if (!data) { -unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, const unsigned char *buf, size_t buf_size) { - // afl_custom_fuzz_count is called exactly once before entering the 'stage-loop' for the current queue entry - // thus, we use it to reset the error count and to initialize stage variables (somewhat not intended by the API, - // but still better than rewriting the whole thing to have a custom mutator stage) - data->atnwalk_error_count = 0; - data->prev_timeouts = data->afl->total_tmouts; + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + data->prev_hits = 0; + data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT); + data->fuzz_size = BUF_SIZE_INIT; + data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT); + data->post_process_size = BUF_SIZE_INIT; + return data; - // it might happen that on the last execution of the splice stage a new path is found - // we need to fix that here and count it - if (data->prev_hits) { - data->afl->stage_finds[STAGE_SPLICE] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; - } - data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; - data->stage_havoc_cur = 0; - data->stage_splice_cur = 0; - - // 50% havoc, 50% splice - data->stage_havoc_max = data->afl->stage_max >> 1; - if (data->stage_havoc_max < HAVOC_MIN) { - data->stage_havoc_max = HAVOC_MIN; - } - data->stage_splice_max = data->stage_havoc_max; - return data->stage_havoc_max + data->stage_splice_max; } +unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, + const unsigned char *buf, size_t buf_size) { + + // afl_custom_fuzz_count is called exactly once before entering the + // 'stage-loop' for the current queue entry thus, we use it to reset the error + // count and to initialize stage variables (somewhat not intended by the API, + // but still better than rewriting the whole thing to have a custom mutator + // stage) + data->atnwalk_error_count = 0; + data->prev_timeouts = data->afl->total_tmouts; + + // it might happen that on the last execution of the splice stage a new path + // is found we need to fix that here and count it + if (data->prev_hits) { + + data->afl->stage_finds[STAGE_SPLICE] += + data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; + + } + + data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; + data->stage_havoc_cur = 0; + data->stage_splice_cur = 0; + + // 50% havoc, 50% splice + data->stage_havoc_max = data->afl->stage_max >> 1; + if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; } + data->stage_splice_max = data->stage_havoc_max; + return data->stage_havoc_max + data->stage_splice_max; -size_t fail_fatal(int fd_socket, uint8_t **out_buf) { - if (fd_socket != -1) { - close(fd_socket); - } - *out_buf = NULL; - return 0; } +size_t fail_fatal(int fd_socket, uint8_t **out_buf) { + + if (fd_socket != -1) { close(fd_socket); } + *out_buf = NULL; + return 0; -size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { - if (fd_socket != -1) { - close(fd_socket); - } - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; } +size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, + size_t buf_size, uint8_t **out_buf) { + + if (fd_socket != -1) { close(fd_socket); } + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + + data->afl->stage_max = data->afl->stage_cur; + + } + + *out_buf = buf; + return buf_size; + +} /** * Perform custom mutations on a given input @@ -194,152 +216,214 @@ size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, siz * produce data larger than max_size. * @return Size of the mutated output. */ -size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf, - uint8_t *add_buf, size_t add_buf_size, size_t max_size) { - struct sockaddr_un addr; - int fd_socket; - uint8_t ctrl_buf[8]; - uint8_t wanted; - - // let's display what's going on in a nice way - if (data->stage_havoc_cur == 0) { - data->afl->stage_name = (uint8_t *) "atnwalk - havoc"; - } - if (data->stage_havoc_cur == data->stage_havoc_max) { - data->afl->stage_name = (uint8_t *) "atnwalk - splice"; - } +size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, + uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size, + size_t max_size) { + + struct sockaddr_un addr; + int fd_socket; + uint8_t ctrl_buf[8]; + uint8_t wanted; + + // let's display what's going on in a nice way + if (data->stage_havoc_cur == 0) { + + data->afl->stage_name = (uint8_t *)"atnwalk - havoc"; + + } + + if (data->stage_havoc_cur == data->stage_havoc_max) { + + data->afl->stage_name = (uint8_t *)"atnwalk - splice"; + + } + + // increase the respective havoc or splice counters + if (data->stage_havoc_cur < data->stage_havoc_max) { + + data->stage_havoc_cur++; + data->afl->stage_cycles[STAGE_HAVOC]++; + + } else { + + // if there is nothing to splice, continue with havoc and skip splicing this + // time + if (data->afl->ready_for_splicing_count < 1) { + + data->stage_havoc_max = data->afl->stage_max; + data->stage_havoc_cur++; + data->afl->stage_cycles[STAGE_HAVOC]++; - // increase the respective havoc or splice counters - if (data->stage_havoc_cur < data->stage_havoc_max) { - data->stage_havoc_cur++; - data->afl->stage_cycles[STAGE_HAVOC]++; } else { - // if there is nothing to splice, continue with havoc and skip splicing this time - if (data->afl->ready_for_splicing_count < 1) { - data->stage_havoc_max = data->afl->stage_max; - data->stage_havoc_cur++; - data->afl->stage_cycles[STAGE_HAVOC]++; - } else { - data->stage_splice_cur++; - data->afl->stage_cycles[STAGE_SPLICE]++; - } - } - // keep track of found new corpus seeds per stage - if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { - if (data->stage_splice_cur <= 1) { - data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; - } else { - data->afl->stage_finds[STAGE_SPLICE] += - data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; - } - } - data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; + data->stage_splice_cur++; + data->afl->stage_cycles[STAGE_SPLICE]++; - // check whether this input produces a lot of timeouts, if it does then abandon this queue entry - if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) { - data->afl->stage_max = data->afl->stage_cur; - return fail_gracefully(-1, data, buf, buf_size, out_buf); } - // initialize the socket - fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); - if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - return fail_fatal(fd_socket, out_buf); - } + } - // ask whether the server is alive - ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; - if (!write_all(fd_socket, ctrl_buf, 1)) { - return fail_fatal(fd_socket, out_buf); - } + // keep track of found new corpus seeds per stage + if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { - // see whether the server replies as expected - if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - return fail_fatal(fd_socket, out_buf); - } + if (data->stage_splice_cur <= 1) { - // tell the server what we want to do - wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; + data->afl->stage_finds[STAGE_HAVOC] += + data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; - // perform a crossover if we are splicing - if (data->stage_splice_cur > 0) { - wanted |= SERVER_CROSSOVER_BIT; - } + } else { + + data->afl->stage_finds[STAGE_SPLICE] += + data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; - // tell the server what we want and how much data will be sent - ctrl_buf[0] = wanted; - put_uint32(ctrl_buf + 1, (uint32_t) buf_size); - if (!write_all(fd_socket, ctrl_buf, 5)) { - return fail_fatal(fd_socket, out_buf); } - // send the data to mutate and encode - if (!write_all(fd_socket, buf, buf_size)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + } + + data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; + + // check whether this input produces a lot of timeouts, if it does then + // abandon this queue entry + if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) { + + data->afl->stage_max = data->afl->stage_cur; + return fail_gracefully(-1, data, buf, buf_size, out_buf); + + } + + // initialize the socket + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { + + return fail_fatal(fd_socket, out_buf); + + } + + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { + + return fail_fatal(fd_socket, out_buf); + + } + + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || + ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + + return fail_fatal(fd_socket, out_buf); + + } + + // tell the server what we want to do + wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; + + // perform a crossover if we are splicing + if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = wanted; + put_uint32(ctrl_buf + 1, (uint32_t)buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + + return fail_fatal(fd_socket, out_buf); + + } + + // send the data to mutate and encode + if (!write_all(fd_socket, buf, buf_size)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + if (wanted & SERVER_CROSSOVER_BIT) { + + // since we requested crossover, we will first tell how much additional data + // is to be expected + put_uint32(ctrl_buf, (uint32_t)add_buf_size); + if (!write_all(fd_socket, ctrl_buf, 4)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + } - if (wanted & SERVER_CROSSOVER_BIT) { - // since we requested crossover, we will first tell how much additional data is to be expected - put_uint32(ctrl_buf, (uint32_t) add_buf_size); - if (!write_all(fd_socket, ctrl_buf, 4)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } - - // send the additional data for crossover - if (!write_all(fd_socket, add_buf, add_buf_size)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } - - // lastly, a seed is required for crossover so send one - put_uint64(ctrl_buf, (uint64_t) rand()); - if (!write_all(fd_socket, ctrl_buf, 8)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } + // send the additional data for crossover + if (!write_all(fd_socket, add_buf, add_buf_size)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + } - // since we requested mutation, we need to provide a seed for that - put_uint64(ctrl_buf, (uint64_t) rand()); + // lastly, a seed is required for crossover so send one + put_uint64(ctrl_buf, (uint64_t)rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } - // obtain the required buffer size for the data that will be returned - if (!read_all(fd_socket, ctrl_buf, 4)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } - size_t new_size = (size_t) to_uint32(ctrl_buf); + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - // if the data is too large then we ignore this round - if (new_size > max_size) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } - if (new_size > buf_size) { - // buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate - if (new_size > data->fuzz_size) { - data->fuzz_size = new_size << 1; - data->fuzz_buf = (uint8_t *) realloc(data->fuzz_buf, data->fuzz_size); - } - *out_buf = data->fuzz_buf; - } else { - // new_size fits into buf, so re-use it - *out_buf = buf; - } + } + + // since we requested mutation, we need to provide a seed for that + put_uint64(ctrl_buf, (uint64_t)rand()); + if (!write_all(fd_socket, ctrl_buf, 8)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + size_t new_size = (size_t)to_uint32(ctrl_buf); + + // if the data is too large then we ignore this round + if (new_size > max_size) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + if (new_size > buf_size) { + + // buf is too small, need to use data->fuzz_buf, let's see whether we need + // to reallocate + if (new_size > data->fuzz_size) { + + data->fuzz_size = new_size << 1; + data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size); - // obtain the encoded data - if (!read_all(fd_socket, *out_buf, new_size)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } - close(fd_socket); - return new_size; -} + *out_buf = data->fuzz_buf; + + } else { + + // new_size fits into buf, so re-use it + *out_buf = buf; + } + + // obtain the encoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + close(fd_socket); + return new_size; + +} /** * A post-processing function to use right before AFL writes the test case to @@ -357,68 +441,88 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u * @return Size of the output buffer after processing or the needed amount. * A return of 0 indicates an error. */ -size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { - struct sockaddr_un addr; - int fd_socket; - uint8_t ctrl_buf[8]; - - // initialize the socket - fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd_socket == -1) { - return fail_fatal(fd_socket, out_buf); - } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); - if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - return fail_fatal(fd_socket, out_buf); - } +size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, + size_t buf_size, uint8_t **out_buf) { - // ask whether the server is alive - ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; - if (!write_all(fd_socket, ctrl_buf, 1)) { - return fail_fatal(fd_socket, out_buf); - } + struct sockaddr_un addr; + int fd_socket; + uint8_t ctrl_buf[8]; - // see whether the server replies as expected - if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - return fail_fatal(fd_socket, out_buf); - } + // initialize the socket + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { - // tell the server what we want and how much data will be sent - ctrl_buf[0] = SERVER_DECODE_BIT; - put_uint32(ctrl_buf + 1, (uint32_t) buf_size); - if (!write_all(fd_socket, ctrl_buf, 5)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } + return fail_fatal(fd_socket, out_buf); - // send the data to decode - if (!write_all(fd_socket, buf, buf_size)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } + } - // obtain the required buffer size for the data that will be returned - if (!read_all(fd_socket, ctrl_buf, 4)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } - size_t new_size = (size_t) to_uint32(ctrl_buf); + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { - // need to use data->post_process_buf, let's see whether we need to reallocate - if (new_size > data->post_process_size) { - data->post_process_size = new_size << 1; - data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size); - } - *out_buf = data->post_process_buf; + return fail_fatal(fd_socket, out_buf); - // obtain the decoded data - if (!read_all(fd_socket, *out_buf, new_size)) { - return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); - } + } - close(fd_socket); - return new_size; -} + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || + ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + + return fail_fatal(fd_socket, out_buf); + + } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = SERVER_DECODE_BIT; + put_uint32(ctrl_buf + 1, (uint32_t)buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + } + + // send the data to decode + if (!write_all(fd_socket, buf, buf_size)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + size_t new_size = (size_t)to_uint32(ctrl_buf); + + // need to use data->post_process_buf, let's see whether we need to reallocate + if (new_size > data->post_process_size) { + + data->post_process_size = new_size << 1; + data->post_process_buf = + (uint8_t *)realloc(data->post_process_buf, data->post_process_size); + + } + + *out_buf = data->post_process_buf; + + // obtain the decoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); + + } + + close(fd_socket); + return new_size; + +} /** * Deinitialize everything @@ -426,7 +530,10 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf * @param data The data ptr from afl_custom_init */ void afl_custom_deinit(atnwalk_mutator_t *data) { - free(data->fuzz_buf); - free(data->post_process_buf); - free(data); + + free(data->fuzz_buf); + free(data->post_process_buf); + free(data); + } + diff --git a/docs/Changelog.md b/docs/Changelog.md index 5ed5ef2b..f33acff9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,8 +4,12 @@ release of the tool. See README.md for the general instruction manual. ### Version ++4.07a (dev) + - afl-fuzz: + - new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal + data before post process on finds - afl-showmap: - added custom mutator post_process and send support + - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! ### Version ++4.06c (release) diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 00278082..288aec95 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -156,8 +156,8 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions( } -__attribute__((visibility("default"))) void js_api_set_instrument_no_dynamic_load( - void) { +__attribute__((visibility("default"))) void +js_api_set_instrument_no_dynamic_load(void) { ranges_inst_dynamic_load = FALSE; -- cgit 1.4.1 From 46237c33322bbe92d35436718b37062f5c1a8cb6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 24 Apr 2023 19:20:52 +0200 Subject: makefile for atwalk --- custom_mutators/atnwalk/Makefile | 7 +++++++ custom_mutators/atnwalk/README.md | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 custom_mutators/atnwalk/Makefile (limited to 'custom_mutators') diff --git a/custom_mutators/atnwalk/Makefile b/custom_mutators/atnwalk/Makefile new file mode 100644 index 00000000..bf83cae5 --- /dev/null +++ b/custom_mutators/atnwalk/Makefile @@ -0,0 +1,7 @@ +all: atnwalk.so + +atnwalk.so: atnwalk.c + $(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c + +clean: + rm -f *.so *.o *~ core diff --git a/custom_mutators/atnwalk/README.md b/custom_mutators/atnwalk/README.md index badb856f..730349a3 100644 --- a/custom_mutators/atnwalk/README.md +++ b/custom_mutators/atnwalk/README.md @@ -6,9 +6,7 @@ Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed ## Build -```bash -gcc -I ../../include/ -shared -fPIC -Wall -O3 atnwalk.c -o atnwalk.so -``` +Just type `make` to build `atnwalk.so`. ## Run -- cgit 1.4.1 From f3dc56f59a25eca60666393b43e0eef4811ac825 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 14:54:38 +0200 Subject: update custom mutators --- custom_mutators/honggfuzz/honggfuzz.c | 18 +- custom_mutators/honggfuzz/mangle.c | 1181 ++++++++++++++++------------- custom_mutators/radamsa/radamsa-mutator.c | 11 +- 3 files changed, 678 insertions(+), 532 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c index d7b3c9c5..0dd59aee 100644 --- a/custom_mutators/honggfuzz/honggfuzz.c +++ b/custom_mutators/honggfuzz/honggfuzz.c @@ -3,14 +3,14 @@ #include #include -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" #include "mangle.h" #define NUMBER_OF_MUTATIONS 5 -uint8_t * queue_input; +uint8_t *queue_input; size_t queue_input_size; -afl_state_t * afl_struct; +afl_state_t *afl_struct; run_t run; honggfuzz_t global; struct _dynfile_t dynfile; @@ -18,8 +18,8 @@ struct _dynfile_t dynfile; typedef struct my_mutator { afl_state_t *afl; - run_t * run; - u8 * mutator_buf; + run_t *run; + u8 *mutator_buf; unsigned int seed; unsigned int extras_cnt, a_extras_cnt; @@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { /* When a new queue entry is added we check if there are new dictionary entries to add to honggfuzz structure */ -uint8_t afl_custom_queue_new_entry(my_mutator_t * data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { +void afl_custom_queue_new_entry(my_mutator_t *data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { if (run.global->mutate.dictionaryCnt >= 1024) return; @@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data, } - return 0; + return; } diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c index 637d428d..7b7ccb91 100644 --- a/custom_mutators/honggfuzz/mangle.c +++ b/custom_mutators/honggfuzz/mangle.c @@ -39,11 +39,16 @@ #include "libhfcommon/log.h" #include "libhfcommon/util.h" -static inline size_t mangle_LenLeft(run_t* run, size_t off) { - if (off >= run->dynfile->size) { - LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size); - } - return (run->dynfile->size - off - 1); +static inline size_t mangle_LenLeft(run_t *run, size_t off) { + + if (off >= run->dynfile->size) { + + LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size); + + } + + return (run->dynfile->size - off - 1); + } /* @@ -51,196 +56,233 @@ static inline size_t mangle_LenLeft(run_t* run, size_t off) { * Based on an idea by https://twitter.com/gamozolabs */ static inline size_t mangle_getLen(size_t max) { - if (max > _HF_INPUT_MAX_SIZE) { - LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE); - } - if (max == 0) { - LOG_F("max == 0"); - } - if (max == 1) { - return 1; - } - /* Give 50% chance the the uniform distribution */ - if (util_rnd64() & 1) { - return (size_t)util_rndGet(1, max); - } + if (max > _HF_INPUT_MAX_SIZE) { + + LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, + (size_t)_HF_INPUT_MAX_SIZE); + + } + + if (max == 0) { LOG_F("max == 0"); } + if (max == 1) { return 1; } + + /* Give 50% chance the the uniform distribution */ + if (util_rnd64() & 1) { return (size_t)util_rndGet(1, max); } + + /* effectively exprand() */ + return (size_t)util_rndGet(1, util_rndGet(1, max)); - /* effectively exprand() */ - return (size_t)util_rndGet(1, util_rndGet(1, max)); } /* Prefer smaller values here, so use mangle_getLen() */ -static inline size_t mangle_getOffSet(run_t* run) { - return mangle_getLen(run->dynfile->size) - 1; +static inline size_t mangle_getOffSet(run_t *run) { + + return mangle_getLen(run->dynfile->size) - 1; + } /* Offset which can be equal to the file size */ -static inline size_t mangle_getOffSetPlus1(run_t* run) { - size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE); - return mangle_getLen(reqlen) - 1; +static inline size_t mangle_getOffSetPlus1(run_t *run) { + + size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE); + return mangle_getLen(reqlen) - 1; + } -static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) { - if (off_from >= run->dynfile->size) { - return; - } - if (off_to >= run->dynfile->size) { - return; - } - if (off_from == off_to) { - return; - } +static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to, + size_t len) { + + if (off_from >= run->dynfile->size) { return; } + if (off_to >= run->dynfile->size) { return; } + if (off_from == off_to) { return; } - size_t len_from = run->dynfile->size - off_from; - len = HF_MIN(len, len_from); + size_t len_from = run->dynfile->size - off_from; + len = HF_MIN(len, len_from); - size_t len_to = run->dynfile->size - off_to; - len = HF_MIN(len, len_to); + size_t len_to = run->dynfile->size - off_to; + len = HF_MIN(len, len_to); + + memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len); - memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len); } -static inline void mangle_Overwrite( - run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) { - if (len == 0) { - return; - } - size_t maxToCopy = run->dynfile->size - off; - if (len > maxToCopy) { - len = maxToCopy; - } +static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src, + size_t len, bool printable) { + + if (len == 0) { return; } + size_t maxToCopy = run->dynfile->size - off; + if (len > maxToCopy) { len = maxToCopy; } + + memmove(&run->dynfile->data[off], src, len); + if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); } - memmove(&run->dynfile->data[off], src, len); - if (printable) { - util_turnToPrintable(&run->dynfile->data[off], len); - } } -static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) { - if (run->dynfile->size >= run->global->mutate.maxInputSz) { - return 0; - } - if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) { - len = run->global->mutate.maxInputSz - run->dynfile->size; - } +static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len, + bool printable) { - input_setSize(run, run->dynfile->size + len); - mangle_Move(run, off, off + len, run->dynfile->size); - if (printable) { - memset(&run->dynfile->data[off], ' ', len); - } + if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; } + if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) { + + len = run->global->mutate.maxInputSz - run->dynfile->size; + + } + + input_setSize(run, run->dynfile->size + len); + mangle_Move(run, off, off + len, run->dynfile->size); + if (printable) { memset(&run->dynfile->data[off], ' ', len); } + + return len; - return len; } -static inline void mangle_Insert( - run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) { - len = mangle_Inflate(run, off, len, printable); - mangle_Overwrite(run, off, val, len, printable); +static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val, + size_t len, bool printable) { + + len = mangle_Inflate(run, off, len, printable); + mangle_Overwrite(run, off, val, len, printable); + } -static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) { - if (util_rnd64() & 1) { - mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable); - } else { - mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable); - } +static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len, + bool printable) { + + if (util_rnd64() & 1) { + + mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable); + + } else { + + mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable); + + } + } -static inline void mangle_UseValueAt( - run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) { - if (util_rnd64() & 1) { - mangle_Overwrite(run, off, val, len, printable); - } else { - mangle_Insert(run, off, val, len, printable); - } +static inline void mangle_UseValueAt(run_t *run, size_t off, const uint8_t *val, + size_t len, bool printable) { + + if (util_rnd64() & 1) { + + mangle_Overwrite(run, off, val, len, printable); + + } else { + + mangle_Insert(run, off, val, len, printable); + + } + } -static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) { - /* No big deal if those two are overlapping */ - size_t off1 = mangle_getOffSet(run); - size_t maxlen1 = run->dynfile->size - off1; - size_t off2 = mangle_getOffSet(run); - size_t maxlen2 = run->dynfile->size - off2; - size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2)); +static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) { - if (off1 == off2) { - return; - } + /* No big deal if those two are overlapping */ + size_t off1 = mangle_getOffSet(run); + size_t maxlen1 = run->dynfile->size - off1; + size_t off2 = mangle_getOffSet(run); + size_t maxlen2 = run->dynfile->size - off2; + size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2)); + + if (off1 == off2) { return; } + + for (size_t i = 0; i < (len / 2); i++) { + + /* + * First - from the head, next from the tail. Don't worry about layout of + * the overlapping part - there's no good solution to that, and it can be + * left somewhat scrambled, while still preserving the entropy + */ + const uint8_t tmp1 = run->dynfile->data[off2 + i]; + run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i]; + run->dynfile->data[off1 + i] = tmp1; + const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i]; + run->dynfile->data[off2 + (len - 1) - i] = + run->dynfile->data[off1 + (len - 1) - i]; + run->dynfile->data[off1 + (len - 1) - i] = tmp2; + + } - for (size_t i = 0; i < (len / 2); i++) { - /* - * First - from the head, next from the tail. Don't worry about layout of the overlapping - * part - there's no good solution to that, and it can be left somewhat scrambled, - * while still preserving the entropy - */ - const uint8_t tmp1 = run->dynfile->data[off2 + i]; - run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i]; - run->dynfile->data[off1 + i] = tmp1; - const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i]; - run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i]; - run->dynfile->data[off1 + (len - 1) - i] = tmp2; - } } -static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); +static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) { + + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); - /* Use a temp buf, as Insert/Inflate can change source bytes */ - uint8_t* tmpbuf = (uint8_t*)util_Malloc(len); - defer { - free(tmpbuf); - }; - memmove(tmpbuf, &run->dynfile->data[off], len); + /* Use a temp buf, as Insert/Inflate can change source bytes */ + uint8_t *tmpbuf = (uint8_t *)util_Malloc(len); + defer { + + free(tmpbuf); + + }; + + memmove(tmpbuf, &run->dynfile->data[off], len); + + mangle_UseValue(run, tmpbuf, len, printable); - mangle_UseValue(run, tmpbuf, len, printable); } -static void mangle_Bytes(run_t* run, bool printable) { - uint16_t buf; - if (printable) { - util_rndBufPrintable((uint8_t*)&buf, sizeof(buf)); - } else { - buf = util_rnd64(); - } +static void mangle_Bytes(run_t *run, bool printable) { + + uint16_t buf; + if (printable) { + + util_rndBufPrintable((uint8_t *)&buf, sizeof(buf)); + + } else { + + buf = util_rnd64(); + + } + + /* Overwrite with random 1-2-byte values */ + size_t toCopy = util_rndGet(1, 2); + mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable); - /* Overwrite with random 1-2-byte values */ - size_t toCopy = util_rndGet(1, 2); - mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable); } -static void mangle_ByteRepeat(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t destOff = off + 1; - size_t maxSz = run->dynfile->size - destOff; +static void mangle_ByteRepeat(run_t *run, bool printable) { - /* No space to repeat */ - if (!maxSz) { - mangle_Bytes(run, printable); - return; - } + size_t off = mangle_getOffSet(run); + size_t destOff = off + 1; + size_t maxSz = run->dynfile->size - destOff; + + /* No space to repeat */ + if (!maxSz) { + + mangle_Bytes(run, printable); + return; + + } + + size_t len = mangle_getLen(maxSz); + if (util_rnd64() & 0x1) { + + len = mangle_Inflate(run, destOff, len, printable); + + } + + memset(&run->dynfile->data[destOff], run->dynfile->data[off], len); - size_t len = mangle_getLen(maxSz); - if (util_rnd64() & 0x1) { - len = mangle_Inflate(run, destOff, len, printable); - } - memset(&run->dynfile->data[destOff], run->dynfile->data[off], len); } -static void mangle_Bit(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7)); - if (printable) { - util_turnToPrintable(&(run->dynfile->data[off]), 1); - } +static void mangle_Bit(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7)); + if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); } + } static const struct { - const uint8_t val[8]; - const size_t size; + + const uint8_t val[8]; + const size_t size; + } mangleMagicVals[] = { + /* 1B - No endianness */ {"\x00\x00\x00\x00\x00\x00\x00\x00", 1}, {"\x01\x00\x00\x00\x00\x00\x00\x00", 1}, @@ -472,436 +514,543 @@ static const struct { {"\x00\x00\x00\x00\x00\x00\x00\x80", 8}, {"\x01\x00\x00\x00\x00\x00\x00\x80", 8}, {"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8}, + }; -static void mangle_Magic(run_t* run, bool printable) { - uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1); - mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable); +static void mangle_Magic(run_t *run, bool printable) { + + uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1); + mangle_UseValue(run, mangleMagicVals[choice].val, + mangleMagicVals[choice].size, printable); + } -static void mangle_StaticDict(run_t* run, bool printable) { - if (run->global->mutate.dictionaryCnt == 0) { - mangle_Bytes(run, printable); - return; - } - uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1); - mangle_UseValue(run, run->global->mutate.dictionary[choice].val, - run->global->mutate.dictionary[choice].len, printable); +static void mangle_StaticDict(run_t *run, bool printable) { + + if (run->global->mutate.dictionaryCnt == 0) { + + mangle_Bytes(run, printable); + return; + + } + + uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1); + mangle_UseValue(run, run->global->mutate.dictionary[choice].val, + run->global->mutate.dictionary[choice].len, printable); + } -static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) { - if (!run->global->feedback.cmpFeedback) { - return NULL; - } - cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap; - uint32_t cnt = ATOMIC_GET(cmpf->cnt); - if (cnt == 0) { - return NULL; - } - if (cnt > ARRAYSIZE(cmpf->valArr)) { - cnt = ARRAYSIZE(cmpf->valArr); - } - uint32_t choice = util_rndGet(0, cnt - 1); - *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len); - if (*len == 0) { - return NULL; - } - return cmpf->valArr[choice].val; +static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) { + + if (!run->global->feedback.cmpFeedback) { return NULL; } + cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap; + uint32_t cnt = ATOMIC_GET(cmpf->cnt); + if (cnt == 0) { return NULL; } + if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); } + uint32_t choice = util_rndGet(0, cnt - 1); + *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len); + if (*len == 0) { return NULL; } + return cmpf->valArr[choice].val; + } -static void mangle_ConstFeedbackDict(run_t* run, bool printable) { - size_t len; - const uint8_t* val = mangle_FeedbackDict(run, &len); - if (val == NULL) { - mangle_Bytes(run, printable); - return; - } - mangle_UseValue(run, val, len, printable); +static void mangle_ConstFeedbackDict(run_t *run, bool printable) { + + size_t len; + const uint8_t *val = mangle_FeedbackDict(run, &len); + if (val == NULL) { + + mangle_Bytes(run, printable); + return; + + } + + mangle_UseValue(run, val, len, printable); + } -static void mangle_MemSet(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); - int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX); +static void mangle_MemSet(run_t *run, bool printable) { - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); - } + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + int val = + printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX); + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + memset(&run->dynfile->data[off], val, len); - memset(&run->dynfile->data[off], val, len); } -static void mangle_MemClr(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); - int val = printable ? ' ' : 0; +static void mangle_MemClr(run_t *run, bool printable) { - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); - } + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + int val = printable ? ' ' : 0; + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + memset(&run->dynfile->data[off], val, len); - memset(&run->dynfile->data[off], val, len); } -static void mangle_RandomBuf(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); +static void mangle_RandomBuf(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + if (printable) { + + util_rndBufPrintable(&run->dynfile->data[off], len); + + } else { + + util_rndBuf(&run->dynfile->data[off], len); + + } + +} + +static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen, + uint64_t range, bool printable) { + + int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range; + + switch (varLen) { + + case 1: { + + run->dynfile->data[off] += delta; + break; - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); } - if (printable) { - util_rndBufPrintable(&run->dynfile->data[off], len); - } else { - util_rndBuf(&run->dynfile->data[off], len); + case 2: { + + int16_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap16(val); + val += delta; + val = __builtin_bswap16(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; + } -} -static inline void mangle_AddSubWithRange( - run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) { - int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range; - - switch (varLen) { - case 1: { - run->dynfile->data[off] += delta; - break; - } - case 2: { - int16_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap16(val); - val += delta; - val = __builtin_bswap16(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - case 4: { - int32_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap32(val); - val += delta; - val = __builtin_bswap32(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - case 8: { - int64_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap64(val); - val += delta; - val = __builtin_bswap64(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - default: { - LOG_F("Unknown variable length size: %zu", varLen); - } + case 4: { + + int32_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap32(val); + val += delta; + val = __builtin_bswap32(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; + } -} -static void mangle_AddSub(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); + case 8: { + + int64_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap64(val); + val += delta; + val = __builtin_bswap64(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; - /* 1,2,4,8 */ - size_t varLen = 1U << util_rndGet(0, 3); - if ((run->dynfile->size - off) < varLen) { - varLen = 1; } - uint64_t range; - switch (varLen) { - case 1: - range = 16; - break; - case 2: - range = 4096; - break; - case 4: - range = 1048576; - break; - case 8: - range = 268435456; - break; - default: - LOG_F("Invalid operand size: %zu", varLen); + default: { + + LOG_F("Unknown variable length size: %zu", varLen); + } - mangle_AddSubWithRange(run, off, varLen, range, printable); + } + } -static void mangle_IncByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32; - } else { - run->dynfile->data[off] += (uint8_t)1UL; - } +static void mangle_AddSub(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + + /* 1,2,4,8 */ + size_t varLen = 1U << util_rndGet(0, 3); + if ((run->dynfile->size - off) < varLen) { varLen = 1; } + + uint64_t range; + switch (varLen) { + + case 1: + range = 16; + break; + case 2: + range = 4096; + break; + case 4: + range = 1048576; + break; + case 8: + range = 268435456; + break; + default: + LOG_F("Invalid operand size: %zu", varLen); + + } + + mangle_AddSubWithRange(run, off, varLen, range, printable); + } -static void mangle_DecByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32; - } else { - run->dynfile->data[off] -= (uint8_t)1UL; - } +static void mangle_IncByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32; + + } else { + + run->dynfile->data[off] += (uint8_t)1UL; + + } + } -static void mangle_NegByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32; - } else { - run->dynfile->data[off] = ~(run->dynfile->data[off]); - } +static void mangle_DecByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32; + + } else { + + run->dynfile->data[off] -= (uint8_t)1UL; + + } + } -static void mangle_Expand(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len; - if (util_rnd64() % 16) { - len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off)); - } else { - len = mangle_getLen(run->global->mutate.maxInputSz - off); - } +static void mangle_NegByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32; + + } else { + + run->dynfile->data[off] = ~(run->dynfile->data[off]); + + } - mangle_Inflate(run, off, len, printable); } -static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) { - if (run->dynfile->size <= 2U) { - return; - } +static void mangle_Expand(run_t *run, bool printable) { - size_t off_start = mangle_getOffSet(run); - size_t len = mangle_LenLeft(run, off_start); - if (len == 0) { - return; - } - if (util_rnd64() % 16) { - len = mangle_getLen(HF_MIN(16, len)); - } else { - len = mangle_getLen(len); - } - size_t off_end = off_start + len; - size_t len_to_move = run->dynfile->size - off_end; + size_t off = mangle_getOffSet(run); + size_t len; + if (util_rnd64() % 16) { + + len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off)); + + } else { + + len = mangle_getLen(run->global->mutate.maxInputSz - off); + + } + + mangle_Inflate(run, off, len, printable); - mangle_Move(run, off_end, off_start, len_to_move); - input_setSize(run, run->dynfile->size - len); } -static void mangle_ASCIINum(run_t* run, bool printable) { - size_t len = util_rndGet(2, 8); - char buf[20]; - snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64()); +static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) { + + if (run->dynfile->size <= 2U) { return; } + + size_t off_start = mangle_getOffSet(run); + size_t len = mangle_LenLeft(run, off_start); + if (len == 0) { return; } + if (util_rnd64() % 16) { + + len = mangle_getLen(HF_MIN(16, len)); + + } else { + + len = mangle_getLen(len); + + } + + size_t off_end = off_start + len; + size_t len_to_move = run->dynfile->size - off_end; + + mangle_Move(run, off_end, off_start, len_to_move); + input_setSize(run, run->dynfile->size - len); - mangle_UseValue(run, (const uint8_t*)buf, len, printable); } -static void mangle_ASCIINumChange(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); +static void mangle_ASCIINum(run_t *run, bool printable) { - /* Find a digit */ - for (; off < run->dynfile->size; off++) { - if (isdigit(run->dynfile->data[off])) { - break; - } - } - size_t left = run->dynfile->size - off; - if (left == 0) { - return; - } + size_t len = util_rndGet(2, 8); - size_t len = 0; - uint64_t val = 0; - /* 20 is maximum lenght of a string representing a 64-bit unsigned value */ - for (len = 0; (len < 20) && (len < left); len++) { - char c = run->dynfile->data[off + len]; - if (!isdigit(c)) { - break; - } - val *= 10; - val += (c - '0'); - } + char buf[20]; + snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64()); - switch (util_rndGet(0, 7)) { - case 0: - val++; - break; - case 1: - val--; - break; - case 2: - val *= 2; - break; - case 3: - val /= 2; - break; - case 4: - val = util_rnd64(); - break; - case 5: - val += util_rndGet(1, 256); - break; - case 6: - val -= util_rndGet(1, 256); - break; - case 7: - val = ~(val); - break; - default: - LOG_F("Invalid choice"); - }; - - char buf[20]; - snprintf(buf, sizeof(buf), "%-19" PRIu64, val); - - mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable); -} - -static void mangle_Splice(run_t* run, bool printable) { - if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { - mangle_Bytes(run, printable); - return; - } + mangle_UseValue(run, (const uint8_t *)buf, len, printable); - size_t sz = 0; - const uint8_t* buf = input_getRandomInputAsBuf(run, &sz); - if (!buf) { - LOG_E("input_getRandomInputAsBuf() returned no input"); - mangle_Bytes(run, printable); - return; - } - if (!sz) { - mangle_Bytes(run, printable); - return; - } +} - size_t remoteOff = mangle_getLen(sz) - 1; - size_t len = mangle_getLen(sz - remoteOff); - mangle_UseValue(run, &buf[remoteOff], len, printable); -} - -static void mangle_Resize(run_t* run, bool printable) { - ssize_t oldsz = run->dynfile->size; - ssize_t newsz = 0; - - uint64_t choice = util_rndGet(0, 32); - switch (choice) { - case 0: /* Set new size arbitrarily */ - newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz); - break; - case 1 ... 4: /* Increase size by a small value */ - newsz = oldsz + (ssize_t)util_rndGet(0, 8); - break; - case 5: /* Increase size by a larger value */ - newsz = oldsz + (ssize_t)util_rndGet(9, 128); - break; - case 6 ... 9: /* Decrease size by a small value */ - newsz = oldsz - (ssize_t)util_rndGet(0, 8); - break; - case 10: /* Decrease size by a larger value */ - newsz = oldsz - (ssize_t)util_rndGet(9, 128); - break; - case 11 ... 32: /* Do nothing */ - newsz = oldsz; - break; - default: - LOG_F("Illegal value from util_rndGet: %" PRIu64, choice); - break; - } - if (newsz < 1) { - newsz = 1; - } - if (newsz > (ssize_t)run->global->mutate.maxInputSz) { - newsz = run->global->mutate.maxInputSz; - } +static void mangle_ASCIINumChange(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + + /* Find a digit */ + for (; off < run->dynfile->size; off++) { + + if (isdigit(run->dynfile->data[off])) { break; } + + } + + size_t left = run->dynfile->size - off; + if (left == 0) { return; } + + size_t len = 0; + uint64_t val = 0; + /* 20 is maximum lenght of a string representing a 64-bit unsigned value */ + for (len = 0; (len < 20) && (len < left); len++) { + + char c = run->dynfile->data[off + len]; + if (!isdigit(c)) { break; } + val *= 10; + val += (c - '0'); + + } + + switch (util_rndGet(0, 7)) { + + case 0: + val++; + break; + case 1: + val--; + break; + case 2: + val *= 2; + break; + case 3: + val /= 2; + break; + case 4: + val = util_rnd64(); + break; + case 5: + val += util_rndGet(1, 256); + break; + case 6: + val -= util_rndGet(1, 256); + break; + case 7: + val = ~(val); + break; + default: + LOG_F("Invalid choice"); + + }; + + char buf[20]; + snprintf(buf, sizeof(buf), "%-19" PRIu64, val); + + mangle_UseValueAt(run, off, (const uint8_t *)buf, len, printable); - input_setSize(run, (size_t)newsz); - if (newsz > oldsz) { - if (printable) { - memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); - } - } } -void mangle_mangleContent(run_t* run, int speed_factor) { - static void (*const mangleFuncs[])(run_t * run, bool printable) = { - mangle_Shrink, - mangle_Expand, - mangle_Bit, - mangle_IncByte, - mangle_DecByte, - mangle_NegByte, - mangle_AddSub, - mangle_MemSet, - mangle_MemClr, - mangle_MemSwap, - mangle_MemCopy, - mangle_Bytes, - mangle_ASCIINum, - mangle_ASCIINumChange, - mangle_ByteRepeat, - mangle_Magic, - mangle_StaticDict, - mangle_ConstFeedbackDict, - mangle_RandomBuf, - mangle_Splice, - }; - - if (run->mutationsPerRun == 0U) { - return; - } - if (run->dynfile->size == 0U) { - mangle_Resize(run, /* printable= */ run->global->cfg.only_printable); +static void mangle_Splice(run_t *run, bool printable) { + + if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { + + mangle_Bytes(run, printable); + return; + + } + + size_t sz = 0; + const uint8_t *buf = input_getRandomInputAsBuf(run, &sz); + if (!buf) { + + LOG_E("input_getRandomInputAsBuf() returned no input"); + mangle_Bytes(run, printable); + return; + + } + + if (!sz) { + + mangle_Bytes(run, printable); + return; + + } + + size_t remoteOff = mangle_getLen(sz) - 1; + size_t len = mangle_getLen(sz - remoteOff); + mangle_UseValue(run, &buf[remoteOff], len, printable); + +} + +static void mangle_Resize(run_t *run, bool printable) { + + ssize_t oldsz = run->dynfile->size; + ssize_t newsz = 0; + + uint64_t choice = util_rndGet(0, 32); + switch (choice) { + + case 0: /* Set new size arbitrarily */ + newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz); + break; + case 1 ... 4: /* Increase size by a small value */ + newsz = oldsz + (ssize_t)util_rndGet(0, 8); + break; + case 5: /* Increase size by a larger value */ + newsz = oldsz + (ssize_t)util_rndGet(9, 128); + break; + case 6 ... 9: /* Decrease size by a small value */ + newsz = oldsz - (ssize_t)util_rndGet(0, 8); + break; + case 10: /* Decrease size by a larger value */ + newsz = oldsz - (ssize_t)util_rndGet(9, 128); + break; + case 11 ... 32: /* Do nothing */ + newsz = oldsz; + break; + default: + LOG_F("Illegal value from util_rndGet: %" PRIu64, choice); + break; + + } + + if (newsz < 1) { newsz = 1; } + if (newsz > (ssize_t)run->global->mutate.maxInputSz) { + + newsz = run->global->mutate.maxInputSz; + + } + + input_setSize(run, (size_t)newsz); + if (newsz > oldsz) { + + if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); } + + } + +} + +void mangle_mangleContent(run_t *run, int speed_factor) { + + static void (*const mangleFuncs[])(run_t * run, bool printable) = { + + mangle_Shrink, mangle_Expand, mangle_Bit, + mangle_IncByte, mangle_DecByte, mangle_NegByte, + mangle_AddSub, mangle_MemSet, mangle_MemClr, + mangle_MemSwap, mangle_MemCopy, mangle_Bytes, + mangle_ASCIINum, mangle_ASCIINumChange, mangle_ByteRepeat, + mangle_Magic, mangle_StaticDict, mangle_ConstFeedbackDict, + mangle_RandomBuf, mangle_Splice, + + }; + + if (run->mutationsPerRun == 0U) { return; } + if (run->dynfile->size == 0U) { + + mangle_Resize(run, /* printable= */ run->global->cfg.only_printable); + + } + + uint64_t changesCnt = run->global->mutate.mutationsPerRun; + + if (speed_factor < 5) { + + changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun); + + } else if (speed_factor < 10) { + + changesCnt = run->global->mutate.mutationsPerRun; + + } else { + + changesCnt = HF_MIN(speed_factor, 10); + changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5)); + + } + + /* If last coverage acquisition was more than 5 secs ago, use splicing more + * frequently */ + if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) { + + if (util_rnd64() & 0x1) { + + mangle_Splice(run, run->global->cfg.only_printable); + } - uint64_t changesCnt = run->global->mutate.mutationsPerRun; + } + + for (uint64_t x = 0; x < changesCnt; x++) { + + if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { + + /* + * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback + * dictionary exists. If so, give it 50% chance of being used among all + * mangling functions. + */ + mangle_ConstFeedbackDict( + run, /* printable= */ run->global->cfg.only_printable); - if (speed_factor < 5) { - changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun); - } else if (speed_factor < 10) { - changesCnt = run->global->mutate.mutationsPerRun; } else { - changesCnt = HF_MIN(speed_factor, 10); - changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5)); - } - /* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */ - if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) { - if (util_rnd64() & 0x1) { - mangle_Splice(run, run->global->cfg.only_printable); - } - } + uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); + mangleFuncs[choice](run, + /* printable= */ run->global->cfg.only_printable); - for (uint64_t x = 0; x < changesCnt; x++) { - if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { - /* - * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary - * exists. If so, give it 50% chance of being used among all mangling functions. - */ - mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable); - } else { - uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); - mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable); - } } - wmb(); + } + + wmb(); + } + diff --git a/custom_mutators/radamsa/radamsa-mutator.c b/custom_mutators/radamsa/radamsa-mutator.c index 624ace3d..466bb5c3 100644 --- a/custom_mutators/radamsa/radamsa-mutator.c +++ b/custom_mutators/radamsa/radamsa-mutator.c @@ -1,6 +1,5 @@ // This simple example just creates random buffer <= 100 filled with 'A' // needs -I /path/to/AFLplusplus/include -//#include "custom_mutator_helpers.h" #include #include @@ -8,19 +7,17 @@ #include #include "radamsa.h" -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" typedef struct my_mutator { - afl_t *afl; - - u8 *mutator_buf; - + afl_state_t *afl; + u8 *mutator_buf; unsigned int seed; } my_mutator_t; -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { srand(seed); my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); -- cgit 1.4.1 From 2e23418a09e6c610288414d4ab6841b6f39513af Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 14:55:31 +0200 Subject: remove symlinks --- custom_mutators/honggfuzz/custom_mutator_helpers.h | 22 ---------------------- custom_mutators/radamsa/custom_mutator_helpers.h | 1 - 2 files changed, 23 deletions(-) delete mode 100644 custom_mutators/honggfuzz/custom_mutator_helpers.h delete mode 120000 custom_mutators/radamsa/custom_mutator_helpers.h (limited to 'custom_mutators') diff --git a/custom_mutators/honggfuzz/custom_mutator_helpers.h b/custom_mutators/honggfuzz/custom_mutator_helpers.h deleted file mode 100644 index 57754697..00000000 --- a/custom_mutators/honggfuzz/custom_mutator_helpers.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include "afl-fuzz.h" -#include - -#define INITIAL_GROWTH_SIZE (64) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this filles in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h deleted file mode 120000 index f7532ef9..00000000 --- a/custom_mutators/radamsa/custom_mutator_helpers.h +++ /dev/null @@ -1 +0,0 @@ -../examples/custom_mutator_helpers.h \ No newline at end of file -- cgit 1.4.1 From 396157dedae2049f830c49eb81ef9617275333ee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 May 2023 13:52:54 +0200 Subject: tritondse custom mutator attempt --- custom_mutators/aflpp_tritondse/README.md | 17 ++++ custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 106 +++++++++++++++++++++ src/afl-fuzz-one.c | 16 ++-- 3 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 custom_mutators/aflpp_tritondse/README.md create mode 100644 custom_mutators/aflpp_tritondse/aflpp_tritondse.py (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md new file mode 100644 index 00000000..8a5dd02b --- /dev/null +++ b/custom_mutators/aflpp_tritondse/README.md @@ -0,0 +1,17 @@ +# An AFL++ custom mutator using TritonDSE + +## Installing the requirements + +`pip3 install tritondse` + +## How to run with an example + +``` +../../afl-cc -o ../../test-instr ../../test-instr.c +mkdir -p in +echo aaaa > in/in +TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr +``` + +Note that this custom mutator works differently, new finds are synced +after 10-60 seconds to the fuzzing instance. diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py new file mode 100644 index 00000000..33bf8a9f --- /dev/null +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -0,0 +1,106 @@ +import sys +import os +import logging + +from tritondse import Config +from tritondse import CoverageStrategy +from tritondse import ProcessState +from tritondse import Program +from tritondse import Seed +from tritondse import SeedFormat +from tritondse import SymbolicExecutor +from tritondse import SymbolicExplorator + + +#logging.basicConfig(level=logging.INFO) + +is_debug = False +out_path = "out/tritondse/queue" +input_file = None +prog = None +config = None +dse = None +cycle = 0 +count = 0 +hashes = set() + +def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): + #logging.info(f"[PRE-EXEC] Processing seed: {se.seed.hash}, \ + # ({repr(se.seed.content)})") + global count + global hasshes + if se.seed.hash not in hashes: + hashes.add(se.seed.hash) + filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash + if not os.path.exists(filename): + with open(filename, 'wb') as file: + file.write(se.seed.content) + count += 1 + if input_file: + with open(input_file, 'wb') as file: + file.write(se.seed.content) + + +def init(seed): + global prog + global config + global dse + global input_file + global is_debug + # Load the program (LIEF-based program loader). + prog = Program(os.environ['TRITON_DSE_TARGET']) + # Set the configuration. + argv = None + try: + foo = os.environ['AFL_DEBUG'] + is_debug = True + except KeyError: + pass + try: + argv_list = os.environ['TRITON_DSE_TARGET_ARGV'] + argv = argv_list.split() + except KeyError: + pass + try: + foo = os.environ['TRITON_DSE_TARGET_INPUT'] + input_file = foo + except KeyError: + pass + config = Config(coverage_strategy = CoverageStrategy.PATH, + debug = is_debug, + pipe_stdout = is_debug, + pipe_stderr = is_debug, + execution_timeout = 1, + program_argv = argv, + smt_timeout= 50, + seed_format = SeedFormat.RAW) + # Create an instance of the Symbolic Explorator + dse = SymbolicExplorator(config, prog) + # Add callbacks. + dse.callback_manager.register_pre_execution_callback(pre_exec_hook) + # Create the output directory + os.makedirs(out_path, exist_ok=True) + + +#def fuzz(buf, add_buf, max_size): +# return b"" + + +def queue_new_entry(filename_new_queue, filename_orig_queue): + global dse + global cycle + # Add seed to the worklist. + with open(filename_new_queue, "rb") as file: + seed = file.read() + seed = Seed(seed) + dse.add_input_seed(seed) + if is_debug: + print("NEW FILE " + filename_new_queue + " count " + str(cycle)) + cycle += 1 + # Start exploration! + #dse.step() + dse.explore() + pass + +def splice_optout(): + pass diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a9902087..c6e9a295 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2048,20 +2048,22 @@ custom_mutator_stage: afl->queue_cur->stats_mutated += afl->stage_max; #endif - if (likely(afl->custom_only)) { + /**************** + * RANDOM HAVOC * + ****************/ + +havoc_stage: + + if (unlikely(afl->custom_only)) { + /* Force UI update */ + show_stats(afl); /* Skip other stages */ ret_val = 0; goto abandon_entry; } - /**************** - * RANDOM HAVOC * - ****************/ - -havoc_stage: - afl->stage_cur_byte = -1; /* The havoc stage mutation code is also invoked when splicing files; if the -- cgit 1.4.1 From f585f262669c14d8b7037d4a34eaa9eb7aef38c5 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 May 2023 14:04:53 +0200 Subject: tritondse fixes --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index 33bf8a9f..49f67d75 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -1,6 +1,7 @@ import sys import os import logging +import hashlib from tritondse import Config from tritondse import CoverageStrategy @@ -92,14 +93,17 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): # Add seed to the worklist. with open(filename_new_queue, "rb") as file: seed = file.read() - seed = Seed(seed) - dse.add_input_seed(seed) - if is_debug: - print("NEW FILE " + filename_new_queue + " count " + str(cycle)) - cycle += 1 - # Start exploration! - #dse.step() - dse.explore() + hash = hashlib.md5(seed).hexdigest() + if hash not in hashes: + hashes.add(hash) + if is_debug: + print("NEW FILE " + filename_new_queue + " hash " + hash + " count " + str(cycle)) + cycle += 1 + seed = Seed(seed) + dse.add_input_seed(seed) + # Start exploration! + #dse.step() + dse.explore() pass def splice_optout(): -- cgit 1.4.1 From 70da0c2e405102dc044cb4bed0f4f1e847c90d0b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 10 May 2023 16:09:18 +0200 Subject: better tritondse support --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 54 ++++++++++--- docs/custom_mutators.md | 28 +++++++ include/envs.h | 4 + src/afl-fuzz.c | 91 ++++++++++++++++------ 4 files changed, 145 insertions(+), 32 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index 49f67d75..9584b368 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -7,6 +7,7 @@ from tritondse import Config from tritondse import CoverageStrategy from tritondse import ProcessState from tritondse import Program +from tritondse import CleLoader from tritondse import Seed from tritondse import SeedFormat from tritondse import SymbolicExecutor @@ -16,7 +17,7 @@ from tritondse import SymbolicExplorator #logging.basicConfig(level=logging.INFO) is_debug = False -out_path = "out/tritondse/queue" +out_path = "" input_file = None prog = None config = None @@ -29,28 +30,38 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): #logging.info(f"[PRE-EXEC] Processing seed: {se.seed.hash}, \ # ({repr(se.seed.content)})") global count - global hasshes + global hashes + print('DEBUG - prehook') if se.seed.hash not in hashes: hashes.add(se.seed.hash) filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash if not os.path.exists(filename): + if is_debug: + print('Creating queue input ' + filename) with open(filename, 'wb') as file: file.write(se.seed.content) count += 1 + else: + print('has hash: ' + se.seed.hash) if input_file: + if is_debug: + print('Writing to ' + input_file + ' the content: ' + str(se.seed.content)) with open(input_file, 'wb') as file: file.write(se.seed.content) + else: + print('no input!') def init(seed): global prog global config global dse + global out_path global input_file global is_debug # Load the program (LIEF-based program loader). - prog = Program(os.environ['TRITON_DSE_TARGET']) - # Set the configuration. + prog = CleLoader(os.environ['AFL_CUSTOM_INFO_PROGRAM']) + # Process other configuration environment variables. argv = None try: foo = os.environ['AFL_DEBUG'] @@ -58,15 +69,42 @@ def init(seed): except KeyError: pass try: - argv_list = os.environ['TRITON_DSE_TARGET_ARGV'] - argv = argv_list.split() + foo = os.environ['AFL_CUSTOM_INFO_OUT'] + out_path = foo + '/../tritondse/queue' except KeyError: pass try: - foo = os.environ['TRITON_DSE_TARGET_INPUT'] + foo = os.environ['AFL_CUSTOM_INFO_PROGRAM_INPUT'] input_file = foo except KeyError: pass + try: + argv_list = os.environ['AFL_CUSTOM_INFO_PROGRAM_ARGV'] + argv_tmp = [ os.environ['AFL_CUSTOM_INFO_PROGRAM'] ] + argv_tmp += argv_list.split() + argv = [] + # now check for @@ + for item in argv_tmp: + if "@@" in item: + input_file = out_path + '/../.input' + argv.append(input_file) + else: + argv.append(item) + except KeyError: + pass + # Create the output directory + os.makedirs(out_path, exist_ok=True) + # Debug + if is_debug: + print('DEBUG target: ' + os.environ['AFL_CUSTOM_INFO_PROGRAM']) + if argv: + print('DEBUG argv: ') + print(argv) + if input_file: + print('DEBUG input_file: ' + input_file) + print('DEBUG out_path: ' + out_path) + print('') + # Now set up TritonDSE config = Config(coverage_strategy = CoverageStrategy.PATH, debug = is_debug, pipe_stdout = is_debug, @@ -79,8 +117,6 @@ def init(seed): dse = SymbolicExplorator(config, prog) # Add callbacks. dse.callback_manager.register_pre_execution_callback(pre_exec_hook) - # Create the output directory - os.makedirs(out_path, exist_ok=True) #def fuzz(buf, add_buf, max_size): diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index a1de479e..3f7e9e6e 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -304,6 +304,34 @@ Note: for some distributions, you might also need the package `python[3]-apt`. In case your setup is different, set the necessary variables like this: `PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`. +### Helpers + +For C/C++ custom mutators you get a pointer to `afl_state_t *afl` in the +`afl_custom_init()` which contains all information that you need. +Note that if you access it, you need to recompile your custom mutator if +you update AFL++ because the structure might have changed! + +For mutators written in Python, Rust, GO, etc. there are a few environment +variables set to help you to get started: + +`AFL_CUSTOM_INFO_PROGRAM` - the program name of the target that is executed. +If your custom mutator is used with modes like Qemu (`-Q`), this will still +contain the target program, not afl-qemu-trace. + +`AFL_CUSTOM_INFO_PROGRAM_INPUT` - if the `-f` parameter is used with afl-fuzz +then this value is found in this environment variable. + +`AFL_CUSTOM_INFO_PROGRAM_ARGV` - this contains the parameters given to the +target program and still has the `@@` identifier in there. + +Note: If `AFL_CUSTOM_INFO_PROGRAM_INPUT` is empty and `AFL_CUSTOM_INFO_PROGRAM_ARGV` +is either empty or does not contain `@@` then the target gets the input via +`stdin`. + +`AFL_CUSTOM_INFO_OUT` - This is the output directory for this fuzzer instance, +so if `afl-fuzz` was called with `-o out -S foobar`, then this will be set to +`out/foobar`. + ### Custom Mutator Preparation For C/C++ mutators, the source code must be compiled as a shared object: diff --git a/include/envs.h b/include/envs.h index fe5ee0e3..edfd06e4 100644 --- a/include/envs.h +++ b/include/envs.h @@ -37,6 +37,10 @@ static char *afl_environment_variables[] = { "AFL_CRASH_EXITCODE", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", + "AFL_CUSTOM_INFO_PROGRAM", + "AFL_CUSTOM_INFO_PROGRAM_ARGV", + "AFL_CUSTOM_INFO_PROGRAM_INPUT", + "AFL_CUSTOM_INFO_OUT", "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f982258f..4339ddd2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1530,29 +1530,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->limit_time_sig > 0 && afl->custom_mutators_count) { - - if (afl->custom_only) { - - FATAL("Custom mutators are incompatible with MOpt (-L)"); - - } - - u32 custom_fuzz = 0; - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - - if (el->afl_custom_fuzz) { custom_fuzz = 1; } - - }); - - if (custom_fuzz) { - - WARNF("afl_custom_fuzz is incompatible with MOpt (-L)"); - - } - - } - if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); @@ -1827,8 +1804,76 @@ int main(int argc, char **argv_orig, char **envp) { printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536)); #endif + if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) { + + setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1); + + } + + if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) { + + setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1); + + } + + { + + u8 envbuf[8096] = "", tmpbuf[8096] = ""; + for (s32 i = optind + 1; i < argc; ++i) { + + strcpy(tmpbuf, envbuf); + if (strchr(argv[i], ' ') && !strchr(argv[i], '"') && + !strchr(argv[i], '\'')) { + + if (!strchr(argv[i], '\'')) { + + snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]); + + } else { + + snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]); + + } + + } else { + + snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]); + + } + + } + + setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1); + + } + + setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + setup_custom_mutators(afl); + if (afl->limit_time_sig > 0 && afl->custom_mutators_count) { + + if (afl->custom_only) { + + FATAL("Custom mutators are incompatible with MOpt (-L)"); + + } + + u32 custom_fuzz = 0; + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_fuzz) { custom_fuzz = 1; } + + }); + + if (custom_fuzz) { + + WARNF("afl_custom_fuzz is incompatible with MOpt (-L)"); + + } + + } + write_setup_file(afl, argc, argv); setup_cmdline_file(afl, argv + optind); -- cgit 1.4.1 From eaf59d5a194f5e5469a86158aeb0e936111ad790 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 11 May 2023 07:55:17 +0200 Subject: next steps for tritondse --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 50 +++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index 9584b368..e0219f0b 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -3,19 +3,17 @@ import os import logging import hashlib +from tritondse import CleLoader +from tritondse import CompositeData from tritondse import Config from tritondse import CoverageStrategy from tritondse import ProcessState from tritondse import Program -from tritondse import CleLoader from tritondse import Seed from tritondse import SeedFormat from tritondse import SymbolicExecutor from tritondse import SymbolicExplorator - -#logging.basicConfig(level=logging.INFO) - is_debug = False out_path = "" input_file = None @@ -25,13 +23,11 @@ dse = None cycle = 0 count = 0 hashes = set() +format = SeedFormat.RAW def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): - #logging.info(f"[PRE-EXEC] Processing seed: {se.seed.hash}, \ - # ({repr(se.seed.content)})") global count global hashes - print('DEBUG - prehook') if se.seed.hash not in hashes: hashes.add(se.seed.hash) filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash @@ -39,26 +35,26 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): if is_debug: print('Creating queue input ' + filename) with open(filename, 'wb') as file: - file.write(se.seed.content) + if input_file: + file.write(se.seed.content.files[input_file]) + else: + file.write(se.seed.content) count += 1 - else: - print('has hash: ' + se.seed.hash) - if input_file: - if is_debug: - print('Writing to ' + input_file + ' the content: ' + str(se.seed.content)) - with open(input_file, 'wb') as file: - file.write(se.seed.content) - else: - print('no input!') + #if input_file: + # if is_debug: + # print('Writing to ' + input_file + ' the content: ' + str(se.seed.content)) + # with open(input_file, 'wb') as file: + # file.write(se.seed.content) def init(seed): - global prog global config global dse - global out_path + global format global input_file global is_debug + global out_path + global prog # Load the program (LIEF-based program loader). prog = CleLoader(os.environ['AFL_CUSTOM_INFO_PROGRAM']) # Process other configuration environment variables. @@ -104,6 +100,8 @@ def init(seed): print('DEBUG input_file: ' + input_file) print('DEBUG out_path: ' + out_path) print('') + if input_file: + format = SeedFormat.COMPOSITE # Now set up TritonDSE config = Config(coverage_strategy = CoverageStrategy.PATH, debug = is_debug, @@ -112,7 +110,7 @@ def init(seed): execution_timeout = 1, program_argv = argv, smt_timeout= 50, - seed_format = SeedFormat.RAW) + seed_format = format) # Create an instance of the Symbolic Explorator dse = SymbolicExplorator(config, prog) # Add callbacks. @@ -124,18 +122,22 @@ def init(seed): def queue_new_entry(filename_new_queue, filename_orig_queue): - global dse global cycle + global dse # Add seed to the worklist. with open(filename_new_queue, "rb") as file: - seed = file.read() - hash = hashlib.md5(seed).hexdigest() + data = file.read() + hash = hashlib.md5(data).hexdigest() if hash not in hashes: hashes.add(hash) if is_debug: print("NEW FILE " + filename_new_queue + " hash " + hash + " count " + str(cycle)) cycle += 1 - seed = Seed(seed) + if input_file: + seed = Seed(CompositeData(files={"stdin": b"", # nothing on stdin + input_file: data})) + else: + seed = Seed(data) dse.add_input_seed(seed) # Start exploration! #dse.step() -- cgit 1.4.1 From 1ad63a6a32d966f1ac05ff40163ef7f747011307 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 16 May 2023 12:20:58 +0200 Subject: fix tritondse --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 68 +++++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index e0219f0b..48367bc7 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -22,14 +22,17 @@ config = None dse = None cycle = 0 count = 0 +finding = 0 hashes = set() format = SeedFormat.RAW def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): global count global hashes + global finding if se.seed.hash not in hashes: hashes.add(se.seed.hash) + finding = 1 filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash if not os.path.exists(filename): if is_debug: @@ -47,6 +50,59 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): # file.write(se.seed.content) +#def rtn_open(se: SymbolicExecutor, pstate: ProcessState, pc): +# """ +# The open behavior. +# """ +# logging.debug('open hooked') +# +# # Get arguments +# arg0 = pstate.get_argument_value(0) # const char *pathname +# flags = pstate.get_argument_value(1) # int flags +# mode = pstate.get_argument_value(2) # int mode +# arg0s = pstate.memory.read_string(arg0) +# +# # Concretize the whole path name +# pstate.concretize_memory_bytes(arg0, len(arg0s)+1) # Concretize the whole string + \0 +# +# # We use flags as concrete value +# pstate.concretize_argument(1) +# +# # Use the flags to open the file in the write mode. +# mode = "" +# if (flags & 0xFF) == 0x00: # O_RDONLY +# mode = "r" +# elif (flags & 0xFF) == 0x01: # O_WRONLY +# mode = "w" +# elif (flags & 0xFF) == 0x02: # O_RDWR +# mode = "r+" +# +# if (flags & 0x0100): # O_CREAT +# mode += "x" +# if (flags & 0x0200): # O_APPEND +# mode = "a" # replace completely value +# +# if se.seed.is_file_defined(arg0s) and "r" in mode: # input file and opened in reading +# logging.info(f"opening an input file: {arg0s}") +# # Program is opening an input +# data = se.seed.get_file_input(arg0s) +# filedesc = pstate.create_file_descriptor(arg0s, io.BytesIO(data)) +# fd = filedesc.id +# else: +# # Try to open it as a regular file +# try: +# fd = open(arg0s, mode) # use the mode here +# filedesc = pstate.create_file_descriptor(arg0s, fd) +# fd = filedesc.id +# except Exception as e: +# logging.debug(f"Failed to open {arg0s} {e}") +# fd = pstate.minus_one +# +# pstate.write_register("rax", fd) # write the return value +# pstate.cpu.program_counter = pstate.pop_stack_value() # pop the return value +# se.skip_instruction() # skip the current instruction so that the engine go straight fetching the next instruction + + def init(seed): global config global dse @@ -115,10 +171,16 @@ def init(seed): dse = SymbolicExplorator(config, prog) # Add callbacks. dse.callback_manager.register_pre_execution_callback(pre_exec_hook) + #dse.callback_manager.register_function_callback("open", rtn_open) -#def fuzz(buf, add_buf, max_size): -# return b"" +def fuzz(buf, add_buf, max_size): + global finding + finding = 1 + while finding == 1: + finding = 0 + dse.step() + return b"" def queue_new_entry(filename_new_queue, filename_orig_queue): @@ -141,7 +203,7 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): dse.add_input_seed(seed) # Start exploration! #dse.step() - dse.explore() + #dse.explore() pass def splice_optout(): -- cgit 1.4.1 From 49997e60cba8dc260d45cc0ce68fa810588e2f23 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 16 May 2023 12:33:58 +0200 Subject: fix --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index 48367bc7..cef28f34 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -206,5 +206,11 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): #dse.explore() pass + +# we simulate just doing one single fuzz in the custom mutator +def fuzz_count(buf): + return 1 + + def splice_optout(): pass -- cgit 1.4.1 From 1d0694df86a3ce70ffac2846f36605eac9300abe Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 17 May 2023 15:25:26 +0200 Subject: add symqemu custom mutator --- custom_mutators/symcc/README.md | 2 + custom_mutators/symqemu/Makefile | 14 ++ custom_mutators/symqemu/README.md | 11 + custom_mutators/symqemu/symqemu.c | 446 ++++++++++++++++++++++++++++++++++++++ docs/Changelog.md | 3 + instrumentation/afl-llvm-common.h | 2 +- test-instr.c | 9 +- 7 files changed, 483 insertions(+), 4 deletions(-) create mode 100644 custom_mutators/symqemu/Makefile create mode 100644 custom_mutators/symqemu/README.md create mode 100644 custom_mutators/symqemu/symqemu.c (limited to 'custom_mutators') diff --git a/custom_mutators/symcc/README.md b/custom_mutators/symcc/README.md index 364a348e..a6839a37 100644 --- a/custom_mutators/symcc/README.md +++ b/custom_mutators/symcc/README.md @@ -5,6 +5,8 @@ This uses the symcc to find new paths into the target. Note that this is a just a proof of concept example! It is better to use the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this. +Also the symqemu custom mutator is better than this. + To use this custom mutator follow the steps in the symcc repository [https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/) on how to build symcc and how to instrument a target binary (the same target diff --git a/custom_mutators/symqemu/Makefile b/custom_mutators/symqemu/Makefile new file mode 100644 index 00000000..3361ab0f --- /dev/null +++ b/custom_mutators/symqemu/Makefile @@ -0,0 +1,14 @@ + +ifdef DEBUG + CFLAGS += -DDEBUG +endif + +all: symqemu-mutator.so + +CFLAGS += -O3 -funroll-loops + +symqemu-mutator.so: symqemu.c + $(CC) $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c + +clean: + rm -f symqemu-mutator.so *.o *~ core diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md new file mode 100644 index 00000000..0d5cd4d7 --- /dev/null +++ b/custom_mutators/symqemu/README.md @@ -0,0 +1,11 @@ +# custum mutator: symqemu + +This uses the symcc to find new paths into the target. + +To use this custom mutator follow the steps in the symqemu repository +[https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/) +on how to build symqemu-x86_x64 and put it in your `PATH`. + +just type `make` to build this custom mutator. + +```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_SYNC_TIME=1 afl-fuzz ...``` diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c new file mode 100644 index 00000000..9030397b --- /dev/null +++ b/custom_mutators/symqemu/symqemu.c @@ -0,0 +1,446 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "debug.h" +#include "afl-fuzz.h" +#include "common.h" + +afl_state_t *afl_struct; +static u32 debug = 0; + +#define DBG(x...) \ + if (debug) { fprintf(stderr, x); } + +typedef struct my_mutator { + + afl_state_t *afl; + u8 *mutator_buf; + u8 *out_dir; + u8 *queue_dir; + u8 *target; + u8 *symqemu; + u8 *input_file; + u32 counter; + u32 seed; + u32 argc; + u8 **argv; + +} my_mutator_t; + +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { + + if (getenv("AFL_DEBUG")) debug = 1; + + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + char *path = getenv("PATH"); + char *exec_name = "symqemu-x86_64"; + char *token = strtok(path, ":"); + char exec_path[4096]; + + while (token != NULL && data->symqemu == NULL) { + + snprintf(exec_path, sizeof(exec_path), "%s/%s", token, exec_name); + if (access(exec_path, X_OK) == 0) { + + data->symqemu = (u8 *)strdup(exec_path); + break; + + } + + token = strtok(NULL, ":"); + + } + + if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name); + DBG("Found %s\n", data->symqemu); + + if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) + FATAL("the symqemu module cannot be used with AFL_CUSTOM_MUTATOR_ONLY."); + + if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) { + + free(data); + perror("mutator_buf alloc"); + return NULL; + + } + + data->target = getenv("AFL_CUSTOM_INFO_PROGRAM"); + + u8 *path_tmp = getenv("AFL_CUSTOM_INFO_OUT"); + u32 len = strlen(path_tmp) + 32; + u8 *symqemu_path = malloc(len); + data->out_dir = malloc(len); + data->queue_dir = malloc(len); + snprintf(symqemu_path, len, "%s/../symqemu", path_tmp); + snprintf(data->out_dir, len, "%s/../symqemu/out", path_tmp); + snprintf(data->queue_dir, len, "%s/../symqemu/queue", path_tmp); + + mkdir(symqemu_path, 0755); + mkdir(data->out_dir, 0755); + mkdir(data->queue_dir, 0755); + + setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1); + + data->input_file = getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT"); + + u8 *tmp = NULL; + if ((tmp = getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) && *tmp) { + + int argc = 0, index = 2; + for (u32 i = 0; i < strlen(tmp); ++i) + if (isspace(tmp[i])) ++argc; + + data->argv = (u8 **)malloc((argc + 4) * sizeof(u8 **)); + u8 *p = strdup(tmp); + + do { + + data->argv[index] = p; + while (*p && !isspace(*p)) + ++p; + if (*p) { + + *p++ = 0; + while (isspace(*p)) + ++p; + + } + + if (strcmp(data->argv[index], "@@") == 0) { + + if (!data->input_file) { + + u32 ilen = strlen(symqemu_path) + 32; + data->input_file = malloc(ilen); + snprintf(data->input_file, ilen, "%s/.input", symqemu_path); + + } + + data->argv[index] = data->input_file; + + } + + DBG("%d: %s\n", index, data->argv[index]); + index++; + + } while (*p); + + data->argv[index] = NULL; + data->argc = index; + + } else { + + data->argv = (u8 **)malloc(8 * sizeof(u8 **)); + data->argc = 2; + data->argv[2] = NULL; + + } + + data->argv[0] = data->symqemu; + data->argv[1] = data->target; + + DBG("out_dir=%s, queue_dir=%s, target=%s, input_file=%s, argc=%u\n", + data->out_dir, data->queue_dir, data->target, + data->input_file ? (char *)data->input_file : (char *)"", + data->argc); + + if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); } + + data->afl = afl; + data->seed = seed; + afl_struct = afl; + + if (debug) { + + fprintf(stderr, "["); + for (u32 i = 0; i <= data->argc; ++i) + fprintf(stderr, " \"%s\"", + data->argv[i] ? (char *)data->argv[i] : ""); + fprintf(stderr, " ]\n"); + + } + + OKF("Custom mutator symqemu loaded - note that the initial startup of " + "afl-fuzz will be delayed the more starting seeds are present. This is " + "fine, do not worry!"); + + return data; + +} + +/* When a new queue entry is added we run this input with the symqemu + instrumented binary */ +uint8_t afl_custom_queue_new_entry(my_mutator_t *data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { + + int pipefd[2]; + struct stat st; + if (data->afl->afl_env.afl_no_ui) + ACTF("Sending to symqemu: %s", filename_new_queue); + u8 *fn = alloc_printf("%s", filename_new_queue); + if (!(stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size)) { + + ck_free(fn); + PFATAL("Couldn't find enqueued file: %s", fn); + + } + + if (afl_struct->fsrv.use_stdin) { + + if (pipe(pipefd) == -1) { + + ck_free(fn); + PFATAL( + "Couldn't create a pipe for interacting with symqemu child process"); + + } + + } + + int fd = open(fn, O_RDONLY); + if (fd < 0) return 0; + ssize_t r = read(fd, data->mutator_buf, MAX_FILE); + DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r); + ck_free(fn); + close(fd); + + if (data->input_file) { + + fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + ssize_t s = write(fd, data->mutator_buf, r); + close(fd); + DBG("wrote %zd/%zd to %s\n", s, r, data->input_file); + + } + + int pid = fork(); + + if (pid == -1) return 0; + + if (pid) { + + if (!data->input_file || afl_struct->fsrv.use_stdin) { + + close(pipefd[0]); + + if (fd >= 0) { + + if (r <= 0) { + + close(pipefd[1]); + return 0; + + } + + if (r > fcntl(pipefd[1], F_GETPIPE_SZ)) + fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE); + ck_write(pipefd[1], data->mutator_buf, r, filename_new_queue); + + } else { + + ck_free(fn); + close(pipefd[1]); + PFATAL( + "Something happened to the enqueued file before sending its " + "contents to symqemu binary"); + + } + + close(pipefd[1]); + + } + + pid = waitpid(pid, NULL, 0); + DBG("symqemu finished executing!\n"); + + // At this point we need to transfer files to output dir, since their names + // collide and symqemu will just overwrite them + + struct dirent **nl; + int32_t items = scandir(data->out_dir, &nl, NULL, NULL); + u8 *origin_name = basename(filename_new_queue); + u8 source_name[4096], destination_name[4096]; + int32_t i; + + if (items > 0) { + + for (i = 0; i < (u32)items; ++i) { + + // symqemu output files start with a digit + if (!isdigit(nl[i]->d_name[0])) continue; + + struct stat st; + snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, + nl[i]->d_name); + DBG("file=%s\n", source_name); + + if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + + snprintf(destination_name, sizeof(destination_name), "%s/id:%06u,%s", + data->queue_dir, data->counter++, nl[i]->d_name); + DBG("src=%s dst=%s\n", source_name, destination_name); + rename(source_name, destination_name); + + } + + free(nl[i]); + + } + + free(nl); + + } + + DBG("Done!\n"); + + } else /* (pid == 0) */ { // child + + if (afl_struct->fsrv.use_stdin) { + + close(pipefd[1]); + dup2(pipefd[0], 0); + + } + + DBG("exec=%s\n", data->target); + if (!debug) { + + close(1); + close(2); + dup2(afl_struct->fsrv.dev_null_fd, 1); + dup2(afl_struct->fsrv.dev_null_fd, 2); + + } + + execvp((char *)data->argv[0], (char **)data->argv); + fprintf(stderr, "Executing: ["); + for (u32 i = 0; i <= data->argc; ++i) + fprintf(stderr, " \"%s\"", + data->argv[i] ? (char *)data->argv[i] : ""); + fprintf(stderr, " ]\n"); + FATAL("Failed to execute %s %s\n", data->argv[0], data->argv[1]); + exit(-1); + + } + + return 0; + +} + +/* +uint32_t afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, + size_t buf_size) { + + uint32_t count = 0, i; + struct dirent **nl; + int32_t items = scandir(data->out_dir, &nl, NULL, NULL); + + if (items > 0) { + + for (i = 0; i < (u32)items; ++i) { + + struct stat st; + u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); + DBG("test=%s\n", fn); + if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + + DBG("found=%s\n", fn); + count++; + + } + + ck_free(fn); + free(nl[i]); + + } + + free(nl); + + } + + DBG("dir=%s, count=%u\n", data->out_dir, count); + return count; + +} + +*/ + +// here we actually just read the files generated from symqemu +/* +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, + size_t max_size) { + + struct dirent **nl; + int32_t i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL); + ssize_t size = 0; + + if (items <= 0) return 0; + + for (i = 0; i < (u32)items; ++i) { + + struct stat st; + u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); + + if (done == 0) { + + if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + + int fd = open(fn, O_RDONLY); + + if (fd >= 0) { + + size = read(fd, data->mutator_buf, max_size); + *out_buf = data->mutator_buf; + + close(fd); + done = 1; + + } + + } + + unlink(fn); + + } + + ck_free(fn); + free(nl[i]); + + } + + free(nl); + DBG("FUZZ size=%lu\n", size); + return (uint32_t)size; + +} + +*/ + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->mutator_buf); + free(data); + +} + diff --git a/docs/Changelog.md b/docs/Changelog.md index 3602af50..e99747f6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -23,6 +23,9 @@ - qemu_mode: - Persistent mode +QASAN support for ppc32 tragets by @worksbutnottested - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! + - two new custom mutators are now available: + - TritonDSE in custom_mutators/aflpp_tritondse + - SymQEMU in custom_mutators/symqemu ### Version ++4.06c (release) diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h index c9324460..23f67179 100644 --- a/instrumentation/afl-llvm-common.h +++ b/instrumentation/afl-llvm-common.h @@ -23,7 +23,7 @@ typedef long double max_align_t; #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #if LLVM_VERSION_MAJOR < 17 -#include "llvm/Transforms/IPO/PassManagerBuilder.h" + #include "llvm/Transforms/IPO/PassManagerBuilder.h" #endif #if LLVM_VERSION_MAJOR > 3 || \ diff --git a/test-instr.c b/test-instr.c index 1d9f2e6e..eda5189c 100644 --- a/test-instr.c +++ b/test-instr.c @@ -24,7 +24,7 @@ int main(int argc, char **argv) { - int fd = 0; + int fd = 0, cnt; char buff[8]; char *buf = buff; @@ -32,7 +32,6 @@ int main(int argc, char **argv) { if (argc == 2) { buf = argv[1]; - printf("Input %s - ", buf); } else { @@ -47,15 +46,19 @@ int main(int argc, char **argv) { } - if (read(fd, buf, sizeof(buf)) < 1) { + if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) { printf("Hum?\n"); return 1; } + buf[cnt] = 0; + } + if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf); + // we support three input cases (plus a 4th if stdin is used but there is no // input) switch (buf[0]) { -- cgit 1.4.1 From 3e3adb4d377dcfa1e878ab00f061a894923bd642 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 17 May 2023 18:39:54 +0200 Subject: enforce python setting detection --- GNUmakefile | 34 +++++++++++++++++----------------- custom_mutators/symqemu/README.md | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'custom_mutators') diff --git a/GNUmakefile b/GNUmakefile index 31374c10..bfc2aa03 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -180,13 +180,13 @@ AFL_FUZZ_FILES = $(wildcard src/afl-fuzz*.c) ifneq "$(shell command -v python3m 2>/dev/null)" "" ifneq "$(shell command -v python3m-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python3m-config --includes) - PYTHON_VERSION ?= $(strip $(shell python3m --version 2>&1)) + PYTHON_INCLUDE := $(shell python3m-config --includes) + PYTHON_VERSION := $(strip $(shell python3m --version 2>&1)) # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag. ifeq "$(shell python3m-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1" - PYTHON_LIB ?= $(shell python3m-config --libs --embed --ldflags) + PYTHON_LIB := $(shell python3m-config --libs --embed --ldflags) else - PYTHON_LIB ?= $(shell python3m-config --ldflags) + PYTHON_LIB := $(shell python3m-config --ldflags) endif endif endif @@ -194,13 +194,13 @@ endif ifeq "$(PYTHON_INCLUDE)" "" ifneq "$(shell command -v python3 2>/dev/null)" "" ifneq "$(shell command -v python3-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python3-config --includes) - PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1)) + PYTHON_INCLUDE := $(shell python3-config --includes) + PYTHON_VERSION := $(strip $(shell python3 --version 2>&1)) # Starting with python3.8, we need to pass the `embed` flag. Earlier versions didn't know this flag. ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1" - PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags) + PYTHON_LIB := $(shell python3-config --libs --embed --ldflags) else - PYTHON_LIB ?= $(shell python3-config --ldflags) + PYTHON_LIB := $(shell python3-config --ldflags) endif endif endif @@ -209,9 +209,9 @@ endif ifeq "$(PYTHON_INCLUDE)" "" ifneq "$(shell command -v python 2>/dev/null)" "" ifneq "$(shell command -v python-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python-config --includes) - PYTHON_LIB ?= $(shell python-config --ldflags) - PYTHON_VERSION ?= $(strip $(shell python --version 2>&1)) + PYTHON_INCLUDE := $(shell python-config --includes) + PYTHON_LIB := $(shell python-config --ldflags) + PYTHON_VERSION := $(strip $(shell python --version 2>&1)) endif endif endif @@ -220,9 +220,9 @@ endif ifeq "$(PYTHON_INCLUDE)" "" ifneq "$(shell command -v python3.7 2>/dev/null)" "" ifneq "$(shell command -v python3.7-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python3.7-config --includes) - PYTHON_LIB ?= $(shell python3.7-config --ldflags) - PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1)) + PYTHON_INCLUDE := $(shell python3.7-config --includes) + PYTHON_LIB := $(shell python3.7-config --ldflags) + PYTHON_VERSION := $(strip $(shell python3.7 --version 2>&1)) endif endif endif @@ -231,9 +231,9 @@ endif ifeq "$(PYTHON_INCLUDE)" "" ifneq "$(shell command -v python2.7 2>/dev/null)" "" ifneq "$(shell command -v python2.7-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python2.7-config --includes) - PYTHON_LIB ?= $(shell python2.7-config --ldflags) - PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1)) + PYTHON_INCLUDE := $(shell python2.7-config --includes) + PYTHON_LIB := $(shell python2.7-config --ldflags) + PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1)) endif endif endif diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md index 0d5cd4d7..55ce05c5 100644 --- a/custom_mutators/symqemu/README.md +++ b/custom_mutators/symqemu/README.md @@ -8,4 +8,4 @@ on how to build symqemu-x86_x64 and put it in your `PATH`. just type `make` to build this custom mutator. -```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_SYNC_TIME=1 afl-fuzz ...``` +```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_SYNC_TIME=1 AFL_DISABLE_TRIM=1 afl-fuzz ...``` -- cgit 1.4.1 From abd6eace9d767e4db6019e8eb69080d2352015c9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 10:32:15 +0200 Subject: improved symqemu custom mutator --- custom_mutators/symqemu/README.md | 2 +- custom_mutators/symqemu/symqemu.c | 239 +++++++++++++++----------------------- include/afl-fuzz.h | 1 + src/afl-fuzz-one.c | 1 + 4 files changed, 98 insertions(+), 145 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md index 55ce05c5..b7702c06 100644 --- a/custom_mutators/symqemu/README.md +++ b/custom_mutators/symqemu/README.md @@ -8,4 +8,4 @@ on how to build symqemu-x86_x64 and put it in your `PATH`. just type `make` to build this custom mutator. -```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_SYNC_TIME=1 AFL_DISABLE_TRIM=1 afl-fuzz ...``` +```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...``` diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c index 9030397b..163ae240 100644 --- a/custom_mutators/symqemu/symqemu.c +++ b/custom_mutators/symqemu/symqemu.c @@ -13,6 +13,9 @@ afl_state_t *afl_struct; static u32 debug = 0; +static u32 found_items = 0; + +#define SYMQEMU_LOCATION "symqemu" #define DBG(x...) \ if (debug) { fprintf(stderr, x); } @@ -22,7 +25,6 @@ typedef struct my_mutator { afl_state_t *afl; u8 *mutator_buf; u8 *out_dir; - u8 *queue_dir; u8 *target; u8 *symqemu; u8 *input_file; @@ -67,8 +69,13 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name); DBG("Found %s\n", data->symqemu); - if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) - FATAL("the symqemu module cannot be used with AFL_CUSTOM_MUTATOR_ONLY."); + if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) { + + WARNF( + "the symqemu module is not very effective with " + "AFL_CUSTOM_MUTATOR_ONLY."); + + } if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) { @@ -84,14 +91,11 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { u32 len = strlen(path_tmp) + 32; u8 *symqemu_path = malloc(len); data->out_dir = malloc(len); - data->queue_dir = malloc(len); - snprintf(symqemu_path, len, "%s/../symqemu", path_tmp); - snprintf(data->out_dir, len, "%s/../symqemu/out", path_tmp); - snprintf(data->queue_dir, len, "%s/../symqemu/queue", path_tmp); + snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION); + snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp); - mkdir(symqemu_path, 0755); - mkdir(data->out_dir, 0755); - mkdir(data->queue_dir, 0755); + (void)mkdir(symqemu_path, 0755); + (void)mkdir(data->out_dir, 0755); setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1); @@ -153,8 +157,8 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { data->argv[0] = data->symqemu; data->argv[1] = data->target; - DBG("out_dir=%s, queue_dir=%s, target=%s, input_file=%s, argc=%u\n", - data->out_dir, data->queue_dir, data->target, + DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir, + data->target, data->input_file ? (char *)data->input_file : (char *)"", data->argc); @@ -174,29 +178,39 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { } - OKF("Custom mutator symqemu loaded - note that the initial startup of " - "afl-fuzz will be delayed the more starting seeds are present. This is " - "fine, do not worry!"); - return data; } -/* When a new queue entry is added we run this input with the symqemu - instrumented binary */ -uint8_t afl_custom_queue_new_entry(my_mutator_t *data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { +/* No need to receive a splicing item */ +void afl_custom_splice_optout(void *data) { + + (void)(data); + +} + +u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) { + + if (likely(!afl_struct->queue_cur->favored || + afl_struct->queue_cur->was_fuzzed)) { + + return 0; + + } int pipefd[2]; struct stat st; - if (data->afl->afl_env.afl_no_ui) - ACTF("Sending to symqemu: %s", filename_new_queue); - u8 *fn = alloc_printf("%s", filename_new_queue); - if (!(stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size)) { - ck_free(fn); - PFATAL("Couldn't find enqueued file: %s", fn); + if (afl_struct->afl_env.afl_no_ui) { + + ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname); + + } + + if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) && + st.st_size)) { + + PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname); } @@ -204,7 +218,6 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, if (pipe(pipefd) == -1) { - ck_free(fn); PFATAL( "Couldn't create a pipe for interacting with symqemu child process"); @@ -212,19 +225,12 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, } - int fd = open(fn, O_RDONLY); - if (fd < 0) return 0; - ssize_t r = read(fd, data->mutator_buf, MAX_FILE); - DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r); - ck_free(fn); - close(fd); - if (data->input_file) { - fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); - ssize_t s = write(fd, data->mutator_buf, r); + int fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + ssize_t s = write(fd, buf, buf_size); close(fd); - DBG("wrote %zd/%zd to %s\n", s, r, data->input_file); + DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file); } @@ -232,35 +238,20 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, if (pid == -1) return 0; - if (pid) { + if (likely(pid)) { if (!data->input_file || afl_struct->fsrv.use_stdin) { close(pipefd[0]); - if (fd >= 0) { - - if (r <= 0) { - - close(pipefd[1]); - return 0; - - } + if (fcntl(pipefd[1], F_GETPIPE_SZ)) { - if (r > fcntl(pipefd[1], F_GETPIPE_SZ)) - fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE); - ck_write(pipefd[1], data->mutator_buf, r, filename_new_queue); - - } else { - - ck_free(fn); - close(pipefd[1]); - PFATAL( - "Something happened to the enqueued file before sending its " - "contents to symqemu binary"); + fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE); } + ck_write(pipefd[1], buf, buf_size, data->input_file); + close(pipefd[1]); } @@ -268,46 +259,6 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, pid = waitpid(pid, NULL, 0); DBG("symqemu finished executing!\n"); - // At this point we need to transfer files to output dir, since their names - // collide and symqemu will just overwrite them - - struct dirent **nl; - int32_t items = scandir(data->out_dir, &nl, NULL, NULL); - u8 *origin_name = basename(filename_new_queue); - u8 source_name[4096], destination_name[4096]; - int32_t i; - - if (items > 0) { - - for (i = 0; i < (u32)items; ++i) { - - // symqemu output files start with a digit - if (!isdigit(nl[i]->d_name[0])) continue; - - struct stat st; - snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, - nl[i]->d_name); - DBG("file=%s\n", source_name); - - if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - - snprintf(destination_name, sizeof(destination_name), "%s/id:%06u,%s", - data->queue_dir, data->counter++, nl[i]->d_name); - DBG("src=%s dst=%s\n", source_name, destination_name); - rename(source_name, destination_name); - - } - - free(nl[i]); - - } - - free(nl); - - } - - DBG("Done!\n"); - } else /* (pid == 0) */ { // child if (afl_struct->fsrv.use_stdin) { @@ -338,33 +289,31 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, } - return 0; - -} - -/* -uint32_t afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, - size_t buf_size) { + /* back in mother process */ - uint32_t count = 0, i; struct dirent **nl; - int32_t items = scandir(data->out_dir, &nl, NULL, NULL); + s32 i, items = scandir(data->out_dir, &nl, NULL, NULL); + found_items = 0; + char source_name[4096]; if (items > 0) { for (i = 0; i < (u32)items; ++i) { + // symqemu output files start with a digit + if (!isdigit(nl[i]->d_name[0])) continue; + struct stat st; - u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); - DBG("test=%s\n", fn); - if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, + nl[i]->d_name); + DBG("file=%s\n", source_name); + + if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - DBG("found=%s\n", fn); - count++; + ++found_items; } - ck_free(fn); free(nl[i]); } @@ -373,65 +322,67 @@ uint32_t afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, } - DBG("dir=%s, count=%u\n", data->out_dir, count); - return count; + DBG("Done, found %u items!\n", found_items); -} + return found_items; -*/ +} -// here we actually just read the files generated from symqemu -/* -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, +size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, u8 *add_buf, size_t add_buf_size, size_t max_size) { struct dirent **nl; - int32_t i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL); - ssize_t size = 0; + s32 done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL); + char source_name[4096]; - if (items <= 0) return 0; + if (items > 0) { - for (i = 0; i < (u32)items; ++i) { + for (i = 0; i < (u32)items; ++i) { - struct stat st; - u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); + // symqemu output files start with a digit + if (!isdigit(nl[i]->d_name[0])) continue; - if (done == 0) { + struct stat st; + snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, + nl[i]->d_name); + DBG("file=%s\n", source_name); - if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - int fd = open(fn, O_RDONLY); + int fd = open(source_name, O_RDONLY); + if (fd < 0) { goto got_an_issue; } - if (fd >= 0) { + ssize_t r = read(fd, data->mutator_buf, MAX_FILE); + close(fd); - size = read(fd, data->mutator_buf, max_size); - *out_buf = data->mutator_buf; + DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r); - close(fd); - done = 1; + if (r < 1) { goto got_an_issue; } - } + done = 1; + --found_items; + unlink(source_name); + + *out_buf = data->mutator_buf; + return (u32)r; } - unlink(fn); + free(nl[i]); } - ck_free(fn); - free(nl[i]); + free(nl); } - free(nl); - DBG("FUZZ size=%lu\n", size); - return (uint32_t)size; +got_an_issue: + *out_buf = NULL; + return 0; } -*/ - /** * Deinitialize everything * diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8fb7ecb1..beb2de2a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -184,6 +184,7 @@ struct queue_entry { handicap, /* Number of queue cycles behind */ depth, /* Path depth */ exec_cksum, /* Checksum of the execution trace */ + custom, /* Marker for custom mutators */ stats_mutated; /* stats: # of mutations performed */ u8 *trace_mini; /* Trace bytes, if kept */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c6e9a295..5c71fc59 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1912,6 +1912,7 @@ custom_mutator_stage: afl->stage_name = "custom mutator"; afl->stage_short = "custom"; + afl->stage_cur = 0; afl->stage_val_type = STAGE_VAL_NONE; bool has_custom_fuzz = false; u32 shift = unlikely(afl->custom_only) ? 7 : 8; -- cgit 1.4.1 From 401d7617efbd2f38d9132eabfd1b1152abceda52 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 10:50:10 +0200 Subject: symqemu mutator options --- custom_mutators/aflpp_tritondse/README.md | 7 +++-- custom_mutators/symqemu/README.md | 10 ++++++- custom_mutators/symqemu/symqemu.c | 44 +++++++++++++++++++++++++------ src/afl-common.c | 2 +- 4 files changed, 51 insertions(+), 12 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md index 8a5dd02b..608c2624 100644 --- a/custom_mutators/aflpp_tritondse/README.md +++ b/custom_mutators/aflpp_tritondse/README.md @@ -10,8 +10,11 @@ ../../afl-cc -o ../../test-instr ../../test-instr.c mkdir -p in echo aaaa > in/in -TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr +AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr ``` Note that this custom mutator works differently, new finds are synced -after 10-60 seconds to the fuzzing instance. +after 10-60 seconds to the fuzzing instance. This is necessary because only +C/C++ mutators have access to the internal AFL++ state. + +Hence the symqemu customer mutator is more effective. diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md index b7702c06..c3071afc 100644 --- a/custom_mutators/symqemu/README.md +++ b/custom_mutators/symqemu/README.md @@ -2,10 +2,18 @@ This uses the symcc to find new paths into the target. +## How to build and use + To use this custom mutator follow the steps in the symqemu repository [https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/) on how to build symqemu-x86_x64 and put it in your `PATH`. -just type `make` to build this custom mutator. +Just type `make` to build this custom mutator. ```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...``` + +## Options + +`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones. + +`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes. diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c index 163ae240..e2b07af6 100644 --- a/custom_mutators/symqemu/symqemu.c +++ b/custom_mutators/symqemu/symqemu.c @@ -23,6 +23,8 @@ static u32 found_items = 0; typedef struct my_mutator { afl_state_t *afl; + u32 all; + u32 late; u8 *mutator_buf; u8 *out_dir; u8 *target; @@ -156,18 +158,19 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { data->argv[0] = data->symqemu; data->argv[1] = data->target; + data->afl = afl; + data->seed = seed; + afl_struct = afl; + + if (getenv("SYMQEMU_ALL")) { data->all = 1; } + if (getenv("SYMQEMU_LATE")) { data->late = 1; } + if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); } DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir, data->target, data->input_file ? (char *)data->input_file : (char *)"", data->argc); - if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); } - - data->afl = afl; - data->seed = seed; - afl_struct = afl; - if (debug) { fprintf(stderr, "["); @@ -189,15 +192,40 @@ void afl_custom_splice_optout(void *data) { } +/* Get unix time in milliseconds */ + +inline u64 get_cur_time(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + +} + u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) { - if (likely(!afl_struct->queue_cur->favored || - afl_struct->queue_cur->was_fuzzed)) { + if (likely((!afl_struct->queue_cur->favored || + afl_struct->queue_cur->was_fuzzed) && + !data->all)) { return 0; } + if (likely(data->late)) { + + if (unlikely(get_cur_time() - afl_struct->last_find_time <= + 10 * 60 * 1000)) { + + return 0; + + } + + } + int pipefd[2]; struct stat st; diff --git a/src/afl-common.c b/src/afl-common.c index a5c48e80..84ddefd8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -949,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { /* Get unix time in milliseconds */ -u64 get_cur_time(void) { +inline u64 get_cur_time(void) { struct timeval tv; struct timezone tz; -- cgit 1.4.1 From eec2c38a6891ea317a287498ce1da2f2c8f6f9ff Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 12:29:43 +0200 Subject: symqemu fix --- custom_mutators/symqemu/symqemu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c index e2b07af6..73a1640a 100644 --- a/custom_mutators/symqemu/symqemu.c +++ b/custom_mutators/symqemu/symqemu.c @@ -207,9 +207,8 @@ inline u64 get_cur_time(void) { u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) { - if (likely((!afl_struct->queue_cur->favored || - afl_struct->queue_cur->was_fuzzed) && - !data->all)) { + if (likely((!afl_struct->queue_cur->favored && !data->all) || + afl_struct->queue_cur->was_fuzzed)) { return 0; -- cgit 1.4.1 From 9a6c0ec0c0af42d33e4350ee2958b58fef1c39dd Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 May 2023 13:04:17 +0200 Subject: make AFL_CUSTOM_INFO overridable --- custom_mutators/symqemu/Makefile | 2 +- src/afl-fuzz.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/symqemu/Makefile b/custom_mutators/symqemu/Makefile index 3361ab0f..958aec19 100644 --- a/custom_mutators/symqemu/Makefile +++ b/custom_mutators/symqemu/Makefile @@ -8,7 +8,7 @@ all: symqemu-mutator.so CFLAGS += -O3 -funroll-loops symqemu-mutator.so: symqemu.c - $(CC) $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c + $(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c clean: rm -f symqemu-mutator.so *.o *~ core diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e2d8dea5..a61718a7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1833,7 +1833,7 @@ int main(int argc, char **argv_orig, char **envp) { } - { + if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) { u8 envbuf[8096] = "", tmpbuf[8096] = ""; for (s32 i = optind + 1; i < argc; ++i) { @@ -1864,7 +1864,11 @@ int main(int argc, char **argv_orig, char **envp) { } - setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + if (!getenv("AFL_CUSTOM_INFO_OUT") { + + setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + + } setup_custom_mutators(afl); -- cgit 1.4.1 From 1416fea1604a19408554678d7c9fb35b67da302b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 May 2023 14:49:24 +0200 Subject: cleaner tritondse --- custom_mutators/aflpp_tritondse/README.md | 6 ++++-- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'custom_mutators') diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md index 608c2624..033655d2 100644 --- a/custom_mutators/aflpp_tritondse/README.md +++ b/custom_mutators/aflpp_tritondse/README.md @@ -15,6 +15,8 @@ AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=a Note that this custom mutator works differently, new finds are synced after 10-60 seconds to the fuzzing instance. This is necessary because only -C/C++ mutators have access to the internal AFL++ state. +C/C++ custom mutators have access to the internal AFL++ state. -Hence the symqemu customer mutator is more effective. +Note that you should run first with `AFL_DEBUG` for 5-10 minutes and see if +all important libraries and syscalls are hooked (look at `WARNING` and `CRITICAL` +output during the run, best use with `AFL_NO_UI=1`) diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index cef28f34..58b506b6 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -120,6 +120,10 @@ def init(seed): is_debug = True except KeyError: pass + if is_debug: + logging.basicConfig(level=logging.WARNING) + else: + logging.basicConfig(level=logging.CRITICAL) try: foo = os.environ['AFL_CUSTOM_INFO_OUT'] out_path = foo + '/../tritondse/queue' -- cgit 1.4.1