From 0d55feb11db1f79ee92db5f44ed04277388c933d Mon Sep 17 00:00:00 2001 From: Your Date: Tue, 31 Jan 2023 06:49:32 +0000 Subject: Add support for disabling branch suppression --- frida_mode/src/js/js_api.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 01bba4ff..2e996c1c 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -289,6 +289,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_cache_size( } +__attribute__((visibility("default"))) void +js_api_set_instrument_suppress_disable(void) { + + instrument_suppress = false; + +} + __attribute__((visibility("default"))) void js_api_set_js_main_hook( const js_main_hook_t hook) { -- cgit 1.4.1 From 30495e6bfe4119c9be6597ad0def01e7e0cb8a67 Mon Sep 17 00:00:00 2001 From: eleguevel Date: Fri, 21 Apr 2023 12:00:56 +0200 Subject: frida mode: add dynamic loaded code exclusion Add the AFL_FRIDA_INST_NO_DYNAMIC_LOAD environment variable and its associated JS function setInstrumentNoDynamicLoad to prevent the instrumentation of late dynamic loaded code. Resolve #1708 --- docs/env_variables.md | 2 ++ frida_mode/README.md | 4 +++- frida_mode/Scripting.md | 6 ++++++ frida_mode/frida.map | 1 + frida_mode/include/ranges.h | 1 + frida_mode/src/js/api.js | 7 +++++++ frida_mode/src/js/js_api.c | 7 +++++++ frida_mode/src/ranges.c | 39 ++++++++++++++++++++++++++++++++++++--- frida_mode/ts/lib/afl.ts | 12 ++++++++++++ include/envs.h | 1 + 10 files changed, 76 insertions(+), 4 deletions(-) (limited to 'frida_mode/src/js/js_api.c') diff --git a/docs/env_variables.md b/docs/env_variables.md index a6a0ae44..c5995d13 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -677,6 +677,8 @@ support. * `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled code. Code is considered to be JIT if the executable segment is not backed by a file. +* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at + runtime. Strictly limits instrumentation to what has been included. * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. diff --git a/frida_mode/README.md b/frida_mode/README.md index aac13153..49a1fe38 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -178,11 +178,13 @@ Default is 256Mb. * `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled code. Code is considered to be JIT if the executable segment is not backed by a file. +* `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` - Don't instrument the code loaded late at + runtime. Strictly limits instrumentation to what has been included. * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use + `AFL_FRIDA_INST_TRACE`. * `AFL_FRIDA_INST_REGS_FILE` - File to write raw register contents at the start of each block. - `AFL_FRIDA_INST_TRACE`. * `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to instrumented address block translations. * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md index 023e4a19..dfd09e7b 100644 --- a/frida_mode/Scripting.md +++ b/frida_mode/Scripting.md @@ -844,6 +844,12 @@ class Afl { static setInstrumentLibraries() { Afl.jsApiSetInstrumentLibraries(); } + /** + * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` + */ + static setInstrumentNoDynamicLoad() { + Afl.jsApiSetInstrumentNoDynamicLoad(); + } /** * See `AFL_FRIDA_INST_NO_OPTIMIZE` */ diff --git a/frida_mode/frida.map b/frida_mode/frida.map index baf067ab..a98c2096 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -19,6 +19,7 @@ js_api_set_instrument_jit; js_api_set_instrument_libraries; js_api_set_instrument_instructions; + js_api_set_instrument_no_dynamic_load; js_api_set_instrument_no_optimize; js_api_set_instrument_regs_file; js_api_set_instrument_seed; diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index 3bd9eaa6..ca28acd9 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -6,6 +6,7 @@ extern gboolean ranges_debug_maps; extern gboolean ranges_inst_libs; extern gboolean ranges_inst_jit; +extern gboolean ranges_inst_dynamic_load; void ranges_config(void); void ranges_init(void); diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index f9ea1ffb..a65d32df 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -150,6 +150,12 @@ class Afl { static setInstrumentLibraries() { Afl.jsApiSetInstrumentLibraries(); } + /** + * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` + */ + static setInstrumentNoDynamicLoad() { + Afl.jsApiSetInstrumentNoDynamicLoad(); + } /** * See `AFL_FRIDA_INST_NO_OPTIMIZE` */ @@ -342,6 +348,7 @@ Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_de Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []); Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []); Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []); +Afl.jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction("js_api_set_instrument_no_dynamic_load", "void", []); Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []); Afl.jsApiSetInstrumentRegsFile = Afl.jsApiGetFunction("js_api_set_instrument_regs_file", "void", ["pointer"]); Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 2e996c1c..00278082 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -156,6 +156,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions( } +__attribute__((visibility("default"))) void js_api_set_instrument_no_dynamic_load( + void) { + + ranges_inst_dynamic_load = FALSE; + +} + __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( void) { diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 72cb9730..e9fc3b4e 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -18,6 +18,7 @@ typedef struct { gboolean ranges_debug_maps = FALSE; gboolean ranges_inst_libs = FALSE; gboolean ranges_inst_jit = FALSE; +gboolean ranges_inst_dynamic_load = TRUE; static GArray *module_ranges = NULL; static GArray *libs_ranges = NULL; @@ -25,6 +26,7 @@ static GArray *jit_ranges = NULL; static GArray *include_ranges = NULL; static GArray *exclude_ranges = NULL; static GArray *ranges = NULL; +static GArray *whole_memory_ranges = NULL; static void convert_address_token(gchar *token, GumMemoryRange *range) { @@ -387,6 +389,21 @@ static GArray *collect_jit_ranges(void) { } +static GArray *collect_whole_mem_ranges(void) { + + GArray *result; + GumMemoryRange range; + result = g_array_new(false, false, sizeof(GumMemoryRange)); + + range.base_address = 0; + range.size = G_MAXULONG; + + g_array_append_val(result, range); + + return result; + +} + static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra, GumMemoryRange *rb) { @@ -574,11 +591,17 @@ void ranges_config(void) { if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; } if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; } if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; } + if (getenv("AFL_FRIDA_INST_NO_DYNAMIC_LOAD") != NULL) { + + ranges_inst_dynamic_load = FALSE; + + } if (ranges_debug_maps) { ranges_print_debug_maps(); } include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); + whole_memory_ranges = collect_whole_mem_ranges(); } @@ -628,10 +651,20 @@ void ranges_init(void) { print_ranges("step4", step4); /* - * After step4, we have the total ranges to be instrumented, we now subtract - * that from the original ranges of the modules to configure stalker. + * After step 4 we have the total ranges to be instrumented, we now subtract + * that either from the original ranges of the modules or from the whole + * memory if AFL_INST_NO_DYNAMIC_LOAD to configure the stalker. */ - step5 = subtract_ranges(module_ranges, step4); + if (ranges_inst_dynamic_load) { + + step5 = subtract_ranges(module_ranges, step4); + + } else { + + step5 = subtract_ranges(whole_memory_ranges, step4); + + } + print_ranges("step5", step5); ranges = merge_ranges(step5); diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 6a2350e7..7d1fac6b 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -178,6 +178,13 @@ class Afl { Afl.jsApiSetInstrumentLibraries(); } + /** + * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD` + */ + public static setInstrumentNoDynamicLoad(): void { + Afl.jsApiSetInstrumentNoDynamicLoad(); + } + /** * See `AFL_FRIDA_INST_NO_OPTIMIZE` */ @@ -443,6 +450,11 @@ class Afl { "void", []); + private static readonly jsApiSetInstrumentNoDynamicLoad = Afl.jsApiGetFunction( + "js_api_set_instrument_no_dynamic_load", + "void", + []); + private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction( "js_api_set_instrument_no_optimize", "void", diff --git a/include/envs.h b/include/envs.h index 066921b9..41eabf60 100644 --- a/include/envs.h +++ b/include/envs.h @@ -65,6 +65,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_CACHE", + "AFL_FRIDA_INST_NO_DYNAMIC_LOAD", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH", -- 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 'frida_mode/src/js/js_api.c') 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