aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--custom_mutators/examples/custom_post_run.c53
-rw-r--r--custom_mutators/examples/example.py5
-rw-r--r--include/afl-fuzz.h12
-rw-r--r--src/afl-fuzz-mutators.c12
-rw-r--r--src/afl-fuzz-one.c1
-rw-r--r--src/afl-fuzz-python.c30
-rw-r--r--src/afl-fuzz-run.c14
-rw-r--r--src/afl-fuzz-stats.c50
8 files changed, 152 insertions, 25 deletions
diff --git a/custom_mutators/examples/custom_post_run.c b/custom_mutators/examples/custom_post_run.c
new file mode 100644
index 00000000..828216ea
--- /dev/null
+++ b/custom_mutators/examples/custom_post_run.c
@@ -0,0 +1,53 @@
+//
+// This is an example on how to use afl_custom_post_run
+// It executes custom code each time after AFL++ executes the target
+//
+// cc -O3 -fPIC -shared -g -o custom_post_run.so -I../../include custom_post_run.c
+// cd ../..
+// afl-cc -o test-instr test-instr.c
+// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_post_run.so \
+// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
+//
+
+
+#include "afl-fuzz.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+typedef struct my_mutator {
+
+ afl_state_t *afl;
+
+} my_mutator_t;
+
+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) {
+
+ perror("afl_custom_init alloc");
+ return NULL;
+
+ }
+
+ data->afl = afl;
+
+ return data;
+
+}
+
+void afl_custom_post_run(my_mutator_t *data) {
+
+ printf("hello from afl_custom_post_run\n");
+ return;
+}
+
+
+void afl_custom_deinit(my_mutator_t *data) {
+
+ free(data);
+
+} \ No newline at end of file
diff --git a/custom_mutators/examples/example.py b/custom_mutators/examples/example.py
index 3a6d22e4..830f302f 100644
--- a/custom_mutators/examples/example.py
+++ b/custom_mutators/examples/example.py
@@ -133,6 +133,11 @@ def fuzz(buf, add_buf, max_size):
# @return: The buffer containing the test case after
# '''
# return buf
+# def post_run():
+# '''
+# Called after each time the execution of the target program by AFL++
+# '''
+# pass
#
# def havoc_mutation(buf, max_size):
# '''
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 8112d430..f1813df6 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -345,6 +345,7 @@ enum {
/* 13 */ PY_FUNC_DESCRIBE,
/* 14 */ PY_FUNC_FUZZ_SEND,
/* 15 */ PY_FUNC_SPLICE_OPTOUT,
+ /* 16 */ PY_FUNC_POST_RUN,
PY_FUNC_COUNT
};
@@ -1021,6 +1022,16 @@ struct custom_mutator {
void (*afl_custom_fuzz_send)(void *data, const u8 *buf, size_t buf_size);
/**
+ * This method can be used if you want to run some code or scripts each time
+ * AFL++ executes the target with afl-fuzz.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init by this custom mutator
+ */
+ void (*afl_custom_post_run)(void *data);
+
+ /**
* Allow for additional analysis (e.g. calling a different tool that does a
* different kind of coverage and saves this for the custom mutator).
*
@@ -1075,6 +1086,7 @@ void finalize_py_module(void *);
u32 fuzz_count_py(void *, const u8 *, size_t);
void fuzz_send_py(void *, const u8 *, size_t);
+void post_run_py(void *);
size_t post_process_py(void *, u8 *, size_t, u8 **);
s32 init_trim_py(void *, u8 *, size_t);
s32 post_trim_py(void *, u8);
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 64dbe7c6..17fb9368 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -397,6 +397,18 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
}
+ /* "afl_custom_post_run", optional */
+ mutator->afl_custom_post_run = dlsym(dh, "afl_custom_post_run");
+ if (!mutator->afl_custom_post_run) {
+
+ ACTF("optional symbol 'afl_custom_post_run' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_post_run'.");
+
+ }
+
/* "afl_custom_queue_new_entry", optional */
mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
if (!mutator->afl_custom_queue_new_entry) {
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 67dafda8..01e34b69 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -1894,6 +1894,7 @@ custom_mutator_stage:
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
if (el->afl_custom_fuzz) {
+
havoc_queued = afl->queued_items;
afl->current_custom_fuzz = el;
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 7dad0770..4c7da774 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -249,6 +249,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "queue_get");
py_functions[PY_FUNC_FUZZ_SEND] =
PyObject_GetAttrString(py_module, "fuzz_send");
+ py_functions[PY_FUNC_POST_RUN] =
+ PyObject_GetAttrString(py_module, "post_run");
py_functions[PY_FUNC_SPLICE_OPTOUT] =
PyObject_GetAttrString(py_module, "splice_optout");
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
@@ -468,6 +470,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
}
+ if (py_functions[PY_FUNC_POST_RUN]) {
+
+ mutator->afl_custom_post_run = post_run_py;
+
+ }
+
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) {
mutator->afl_custom_splice_optout = splice_optout_py;
@@ -925,6 +933,28 @@ void fuzz_send_py(void *py_mutator, const u8 *buf, size_t buf_size) {
}
+void post_run_py(void *py_mutator) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_RUN], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ Py_DECREF(py_value);
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
const u8 *filename_orig_queue) {
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index ac4fb4a9..ae7969a6 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -60,6 +60,19 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+ /* If post_run() function is defined in custom mutator, the function will be
+ called each time after AFL++ executes the target program. */
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_run) { el->afl_custom_post_run(el->data); }
+
+ });
+
+ }
+
#ifdef PROFILING
clock_gettime(CLOCK_REALTIME, &spec);
time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec;
@@ -1110,4 +1123,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
return 0;
}
-
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index f212a4b8..deb28b7a 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -138,7 +138,7 @@ void load_stats_file(afl_state_t *afl) {
FILE *f;
u8 buf[MAX_LINE];
- u8 * lptr;
+ u8 *lptr;
u8 fn[PATH_MAX];
u32 lineno = 0;
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
@@ -421,7 +421,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
void write_queue_stats(afl_state_t *afl) {
FILE *f;
- u8 * fn = alloc_printf("%s/queue_data", afl->out_dir);
+ u8 *fn = alloc_printf("%s/queue_data", afl->out_dir);
if ((f = fopen(fn, "w")) != NULL) {
u32 id;
@@ -857,8 +857,9 @@ void show_stats_normal(afl_state_t *afl) {
/* Since `total_crashes` does not get reloaded from disk on restart,
it indicates if we found crashes this round already -> paint red.
If it's 0, but `saved_crashes` is set from a past run, paint in yellow. */
- char *crash_color =
- afl->total_crashes ? cLRD : afl->saved_crashes ? cYEL : cRST;
+ char *crash_color = afl->total_crashes ? cLRD
+ : afl->saved_crashes ? cYEL
+ : cRST;
/* Lord, forgive me this. */
@@ -881,26 +882,26 @@ void show_stats_normal(afl_state_t *afl) {
} else
- /* Subsequent cycles, but we're still making finds. */
- if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
- strcpy(tmp, cYEL);
+ strcpy(tmp, cYEL);
- } else
+ } else
/* No finds for a long time and no test cases to try. */
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
min_wo_finds > 120) {
- strcpy(tmp, cLGN);
+ strcpy(tmp, cLGN);
- /* Default: cautiously OK to stop? */
+ /* Default: cautiously OK to stop? */
- } else {
+ } else {
- strcpy(tmp, cLBL);
+ strcpy(tmp, cLBL);
- }
+ }
}
@@ -1666,8 +1667,9 @@ void show_stats_pizza(afl_state_t *afl) {
/* Since `total_crashes` does not get reloaded from disk on restart,
it indicates if we found crashes this round already -> paint red.
If it's 0, but `saved_crashes` is set from a past run, paint in yellow. */
- char *crash_color =
- afl->total_crashes ? cLRD : afl->saved_crashes ? cYEL : cRST;
+ char *crash_color = afl->total_crashes ? cLRD
+ : afl->saved_crashes ? cYEL
+ : cRST;
/* Lord, forgive me this. */
@@ -1690,26 +1692,26 @@ void show_stats_pizza(afl_state_t *afl) {
} else
- /* Subsequent cycles, but we're still making finds. */
- if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
+ /* Subsequent cycles, but we're still making finds. */
+ if (afl->cycles_wo_finds < 25 || min_wo_finds < 30) {
- strcpy(tmp, cYEL);
+ strcpy(tmp, cYEL);
- } else
+ } else
/* No finds for a long time and no test cases to try. */
if (afl->cycles_wo_finds > 100 && !afl->pending_not_fuzzed &&
min_wo_finds > 120) {
- strcpy(tmp, cLGN);
+ strcpy(tmp, cLGN);
- /* Default: cautiously OK to stop? */
+ /* Default: cautiously OK to stop? */
- } else {
+ } else {
- strcpy(tmp, cLBL);
+ strcpy(tmp, cLBL);
- }
+ }
}