aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2023-04-22 11:40:50 +0200
committerGitHub <noreply@github.com>2023-04-22 11:40:50 +0200
commitdbb317162415a28e3fd2ff4c574292c924493a00 (patch)
tree190be094155fbdc8bf642f3b84942c4ad1808060
parenta326c23210dc2ace37bf1cadcc4521cf5d0b58cb (diff)
parent6bd48a48cbed1f923ff0999ea24af1f548c2e2bc (diff)
downloadafl++-dbb317162415a28e3fd2ff4c574292c924493a00.tar.gz
Merge pull request #1712 from AFLplusplus/dev
push to stable
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--GNUmakefile6
-rw-r--r--TODO.md4
-rwxr-xr-xafl-cmin2
-rwxr-xr-xafl-cmin.bash2
-rw-r--r--custom_mutators/README.md33
-rw-r--r--custom_mutators/atnwalk/README.md45
-rw-r--r--custom_mutators/atnwalk/atnwalk.c539
-rw-r--r--docs/Changelog.md9
-rw-r--r--docs/env_variables.md2
-rw-r--r--frida_mode/README.md4
-rw-r--r--frida_mode/Scripting.md6
-rw-r--r--frida_mode/frida.map1
-rw-r--r--frida_mode/include/ranges.h1
-rw-r--r--frida_mode/src/js/api.js7
-rw-r--r--frida_mode/src/js/js_api.c7
-rw-r--r--frida_mode/src/ranges.c39
-rw-r--r--frida_mode/ts/lib/afl.ts12
-rw-r--r--include/afl-fuzz.h11
-rw-r--r--include/config.h2
-rw-r--r--include/envs.h2
-rw-r--r--src/afl-fuzz-run.c26
-rw-r--r--src/afl-fuzz-state.c7
-rw-r--r--src/afl-fuzz.c4
-rw-r--r--src/afl-showmap.c127
25 files changed, 871 insertions, 29 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ed1f3228..03e4151d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: "${{ matrix.os }}"
strategy:
matrix:
- os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04]
+ os: [ubuntu-22.04, ubuntu-20.04]
env:
AFL_SKIP_CPUFREQ: 1
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
diff --git a/GNUmakefile b/GNUmakefile
index 5bc3f9d5..23cae65d 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -286,6 +286,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
IN_REPO=1
endif
+CCVER=$(shell cc -v 2>&1|tail -n 1)
+
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
@@ -431,7 +433,7 @@ endif
.PHONY: ready
ready:
- @echo "[+] Everything seems to be working, ready to compile."
+ @echo "[+] Everything seems to be working, ready to compile. ($(CCVER))"
afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS)
@@ -453,7 +455,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
diff --git a/TODO.md b/TODO.md
index e7789cf6..dba75070 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,14 +3,14 @@
## Should
- splicing selection weighted?
- - support afl_custom_{send,post_process}, persistent and deferred fork
- server in afl-showmap
+ - support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt
- afl-plot to support multiple plot_data
- parallel builds for source-only targets
- get rid of check_binary, replace with more forkserver communication
- first fuzzer should be a main automatically? not sure.
+ - reload fuzz binary on signal
## Maybe
diff --git a/afl-cmin b/afl-cmin
index c5e64410..e2c26d91 100755
--- a/afl-cmin
+++ b/afl-cmin
@@ -133,6 +133,8 @@ function usage() {
"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \
"printed to stdout\n" \
"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n"
+"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n"
+"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n"
exit 1
}
diff --git a/afl-cmin.bash b/afl-cmin.bash
index bcf62eba..5258758e 100755
--- a/afl-cmin.bash
+++ b/afl-cmin.bash
@@ -151,6 +151,8 @@ AFL_KEEP_TRACES: leave the temporary <out_dir>\.traces directory
AFL_NO_FORKSRV: run target via execve instead of using the forkserver
AFL_PATH: last resort location to find the afl-showmap binary
AFL_SKIP_BIN_CHECK: skip check for target binary
+AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)
+AFL_PYTHON_MODULE: custom mutator library (post_process and send)
_EOF_
exit 1
fi
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/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)"
+```
diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c
new file mode 100644
index 00000000..c3a2cd95
--- /dev/null
+++ b/custom_mutators/atnwalk/atnwalk.c
@@ -0,0 +1,539 @@
+#include "afl-fuzz.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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
+#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;
+const uint8_t SERVER_YES_I_AM_ALIVE = 42;
+
+// control bits
+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 {
+
+ 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 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);
+
+}
+
+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
+ *
+ * @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->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;
+
+}
+
+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
+ *
+ * (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;
+ 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
+ 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;
+ 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);
+
+ }
+
+ // 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);
+
+ }
+
+ }
+
+ // 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);
+
+ }
+
+ *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
+ * 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) {
+
+ 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);
+
+ }
+
+ // 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 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
+ *
+ * @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);
+
+}
+
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 587fb64c..f33acff9 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -3,6 +3,15 @@
This is the list of all noteworthy changes made in every public
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)
- afl-fuzz:
- ensure temporary file descriptor is closed when not used
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
@@ -845,6 +845,12 @@ class Afl {
Afl.jsApiSetInstrumentLibraries();
}
/**
+ * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
+ */
+ static setInstrumentNoDynamicLoad() {
+ Afl.jsApiSetInstrumentNoDynamicLoad();
+ }
+ /**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
static setInstrumentNoOptimize() {
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
@@ -151,6 +151,12 @@ class Afl {
Afl.jsApiSetInstrumentLibraries();
}
/**
+ * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
+ */
+ static setInstrumentNoDynamicLoad() {
+ Afl.jsApiSetInstrumentNoDynamicLoad();
+ }
+ /**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
static setInstrumentNoOptimize() {
@@ -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..288aec95 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
@@ -179,6 +179,13 @@ class Afl {
}
/**
+ * See `AFL_FRIDA_INST_NO_DYNAMIC_LOAD`
+ */
+ public static setInstrumentNoDynamicLoad(): void {
+ Afl.jsApiSetInstrumentNoDynamicLoad();
+ }
+
+ /**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
public static setInstrumentNoOptimize(): void {
@@ -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/afl-fuzz.h b/include/afl-fuzz.h
index 8b6502b4..831a0dbc 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -399,7 +399,8 @@ typedef struct afl_env_vars {
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_no_crash_readme, afl_ignore_timeouts,
- afl_no_startup_calibration, afl_no_warn_instability;
+ afl_no_startup_calibration, afl_no_warn_instability,
+ afl_post_process_keep_original;
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
@@ -1103,7 +1104,6 @@ u32 count_bits(afl_state_t *, u8 *);
u32 count_bytes(afl_state_t *, u8 *);
u32 count_non_255_bytes(afl_state_t *, u8 *);
void simplify_trace(afl_state_t *, u8 *);
-void classify_counts(afl_forkserver_t *);
#ifdef WORD_SIZE_64
void discover_word(u8 *ret, u64 *current, u64 *virgin);
#else
@@ -1117,6 +1117,9 @@ u8 *describe_op(afl_state_t *, u8, size_t);
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
u8 has_new_bits(afl_state_t *, u8 *);
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
+#ifndef AFL_SHOWMAP
+void classify_counts(afl_forkserver_t *);
+#endif
/* Extras */
@@ -1192,11 +1195,13 @@ void fix_up_sync(afl_state_t *);
void check_asan_opts(afl_state_t *);
void check_binary(afl_state_t *, u8 *);
void check_if_tty(afl_state_t *);
-void setup_signal_handlers(void);
void save_cmdline(afl_state_t *, u32, char **);
void read_foreign_testcases(afl_state_t *, int);
void write_crash_readme(afl_state_t *afl);
u8 check_if_text_buf(u8 *buf, u32 len);
+#ifndef AFL_SHOWMAP
+void setup_signal_handlers(void);
+#endif
/* CmpLog */
diff --git a/include/config.h b/include/config.h
index b6249a0f..764c29dc 100644
--- a/include/config.h
+++ b/include/config.h
@@ -26,7 +26,7 @@
/* Version string: */
// c = release, a = volatile github dev, e = experimental branch
-#define VERSION "++4.06c"
+#define VERSION "++4.07a"
/******************************************************
* *
diff --git a/include/envs.h b/include/envs.h
index 066921b9..23599b26 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",
@@ -186,6 +187,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 4d56f3a7..ac4fb4a9 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -135,10 +135,19 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
if (new_mem != *mem && new_mem != NULL && new_size > 0) {
- u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
+ new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
if (unlikely(!new_buf)) { PFATAL("alloc"); }
+ memcpy(new_buf, new_mem, new_size);
+
+ /* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory
+ prior post-processing in new_mem to restore it later */
+ if (unlikely(afl->afl_env.afl_post_process_keep_original)) {
+
+ new_mem = *mem;
+
+ }
+
*mem = new_buf;
- memcpy(*mem, new_mem, new_size);
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
}
@@ -162,7 +171,18 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
/* everything as planned. use the potentially new data. */
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
- len = new_size;
+
+ if (likely(!afl->afl_env.afl_post_process_keep_original)) {
+
+ len = new_size;
+
+ } else {
+
+ /* restore the original memory which was saved in new_mem */
+ *mem = new_mem;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+
+ }
}
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 46b67def..5e736029 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -394,6 +394,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 f6628851..ebdbb3fa 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -292,6 +292,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"
@@ -326,7 +328,7 @@ static void usage(u8 *argv0, int more_help) {
}
#ifdef USE_PYTHON
- SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
+ SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION);
#else
SAYF("Compiled without Python module support.\n");
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index df030672..0b9fc211 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -30,8 +30,10 @@
*/
#define AFL_MAIN
+#define AFL_SHOWMAP
#include "config.h"
+#include "afl-fuzz.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
@@ -62,6 +64,8 @@
#include <sys/types.h>
#include <sys/resource.h>
+static afl_state_t *afl;
+
static char *stdin_file; /* stdin file */
static u8 *in_dir = NULL, /* input folder */
@@ -136,7 +140,39 @@ static void kill_child() {
}
-static void classify_counts(afl_forkserver_t *fsrv) {
+/* dummy functions */
+u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
+
+ (void)afl;
+ (void)mem;
+ return a + b;
+
+}
+
+void show_stats(afl_state_t *afl) {
+
+ (void)afl;
+
+}
+
+void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
+
+ (void)afl;
+ (void)q;
+
+}
+
+fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
+ u32 i) {
+
+ (void)afl;
+ (void)fsrv;
+ (void)i;
+ return 0;
+
+}
+
+void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits;
const u8 *map = binary_mode ? count_class_binary : count_class_human;
@@ -308,12 +344,73 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
}
+void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) {
+
+ static u8 buf[MAX_FILE];
+ u32 sent = 0;
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ ssize_t new_size = len;
+ u8 *new_mem = mem;
+ u8 *new_buf = NULL;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ new_size =
+ el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
+
+ if (unlikely(!new_buf || new_size <= 0)) {
+
+ return;
+
+ } else {
+
+ new_mem = new_buf;
+ len = new_size;
+
+ }
+
+ }
+
+ });
+
+ if (new_mem != mem && new_mem != NULL) {
+
+ mem = buf;
+ memcpy(mem, new_mem, new_size);
+
+ }
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz_send) {
+
+ el->afl_custom_fuzz_send(el->data, mem, len);
+ sent = 1;
+
+ }
+
+ });
+
+ }
+
+ }
+
+ if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); }
+
+}
+
/* Execute target application. */
static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
u32 len) {
- afl_fsrv_write_to_testcase(fsrv, mem, len);
+ pre_afl_fsrv_write_to_testcase(fsrv, mem, len);
if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
@@ -835,6 +932,10 @@ static void usage(u8 *argv0) {
"This tool displays raw tuple data captured by AFL instrumentation.\n"
"For additional help, consult %s/README.md.\n\n"
+ "If you use -i mode, then custom mutator post_process send send "
+ "functionality\n"
+ "is supported.\n\n"
+
"Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
@@ -1266,6 +1367,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ afl = calloc(1, sizeof(afl_state_t));
+
if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
@@ -1382,6 +1485,26 @@ int main(int argc, char **argv_orig, char **envp) {
if (in_dir) {
+ afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+ afl->afl_env.afl_custom_mutator_library =
+ getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
+ afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
+ setup_custom_mutators(afl);
+
+ } else {
+
+ if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) {
+
+ WARNF(
+ "Custom mutator environment detected, this is only supported in -i "
+ "mode!\n");
+
+ }
+
+ }
+
+ if (in_dir) {
+
DIR *dir_in, *dir_out = NULL;
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;