From 84f0b4f1874a9c3a5f2da4056f974df8273093d9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 7 Feb 2021 08:27:35 +0100 Subject: persistent replay env setup --- include/afl-fuzz.h | 2 +- include/envs.h | 1 + include/forkserver.h | 3 +++ src/afl-forkserver.c | 2 +- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 6 ++++++ 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c3a8c2ee..3b6f2285 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal; + *afl_testcache_entries, *afl_kill_signal, *afl_persistent_replay; } afl_env_vars_t; diff --git a/include/envs.h b/include/envs.h index 210b34a6..f82bb803 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,6 +123,7 @@ static char *afl_environment_variables[] = { "AFL_MAX_DET_EXTRAS", "AFL_PATH", "AFL_PERFORMANCE_FILE", + "AFL_PERSISTEN_REPLAY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", diff --git a/include/forkserver.h b/include/forkserver.h index ac027f81..a0a60e0f 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -55,6 +55,9 @@ typedef struct afl_forkserver { u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ u32 snapshot; /* is snapshot feature used */ + u32 persistent_replay; /* persistent replay setting */ + u32 persistent_replay_idx; /* persistent replay cache ptr */ + u32 persistent_replay_cnt; /* persistent replay counter */ u64 mem_limit; /* Memory cap for child (MB) */ u64 total_execs; /* How often run_target was called */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 9ee59822..7968f69c 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -126,7 +126,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->last_run_timed_out = 0; fsrv_to->init_child_func = from->init_child_func; - // Note: do not copy ->add_extra_func + // Note: do not copy ->add_extra_func or ->persistent_replay* list_append(&fsrv_list, fsrv_to); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 5040e3ef..075aef1e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -292,6 +292,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_autoresume = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_PERSISTENT_REPLAY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_persistent_replay = + get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a579a8f5..77e6e2ce 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1239,6 +1239,12 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_persistent_replay) { + + afl->fsrv.persistent_replay = atoi(afl->afl_env.afl_persistent_replay); + + } + if (afl->afl_env.afl_crash_exitcode) { long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10); -- cgit 1.4.1 From 81442ba3f953c939e2cde9c16b9cd0d5fe7f12b5 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 15:48:49 +0100 Subject: implementation without testing --- include/forkserver.h | 11 ++++++--- src/afl-forkserver.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/afl-fuzz.c | 3 ++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/include/forkserver.h b/include/forkserver.h index a0a60e0f..ddbc36ef 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -55,9 +55,6 @@ typedef struct afl_forkserver { u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ u32 snapshot; /* is snapshot feature used */ - u32 persistent_replay; /* persistent replay setting */ - u32 persistent_replay_idx; /* persistent replay cache ptr */ - u32 persistent_replay_cnt; /* persistent replay counter */ u64 mem_limit; /* Memory cap for child (MB) */ u64 total_execs; /* How often run_target was called */ @@ -97,6 +94,14 @@ typedef struct afl_forkserver { char *cmplog_binary; /* the name of the cmplog binary */ + /* persistent mode replay functionality */ + u32 persistent_replay; /* persistent replay setting */ + u32 persistent_replay_idx; /* persistent replay cache ptr */ + u32 persistent_replay_cnt; /* persistent replay counter */ + u8 * persistent_replay_dir; + u8 ** persistent_replay_data; + u32 **persistent_replay_len; + /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 7968f69c..05aba2e5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -364,6 +364,21 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the fork server..."); } + if (unlikely(fsrv->persistent_replay)) { + + fsrv->persistent_replay_data = + (u8 **)ck_alloc(fsrv->persistent_replay * sizeof(size_t)); + fsrv->persistent_replay_len = + (u32 **)ck_alloc(fsrv->persistent_replay * sizeof(u32)); + + if (!fsrv->persistent_replay_data || !fsrv->persistent_replay_len) { + + FATAL("Unable to allocate memory for persistent replay."); + + } + + } + if (fsrv->use_fauxsrv) { /* TODO: Come up with some nice way to initialize this all */ @@ -998,6 +1013,29 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { + if (unlikely(fsrv->persistent_replay)) { + + *fsrv->persistent_replay_len[fsrv->persistent_replay_idx] = len; + fsrv->persistent_replay_data[fsrv->persistent_replay_idx] = afl_realloc( + (void **)&fsrv->persistent_replay_data[fsrv->persistent_replay_idx], + len); + + if (unlikely(!fsrv->persistent_replay_data[fsrv->persistent_replay_idx])) { + + FATAL("allocating replay memory failed."); + + } + + memcpy(fsrv->persistent_replay_data[fsrv->persistent_replay_idx], buf, len); + + if (unlikely(++fsrv->persistent_replay_idx >= fsrv->persistent_replay)) { + + fsrv->persistent_replay_idx = 0; + + } + + } + if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; @@ -1208,6 +1246,36 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { + if (unlikely(fsrv->persistent_replay)) { + + char fn[4096]; + u32 i, writecnt = 0; + for (i = 0; i < fsrv->persistent_replay; ++i) { + + u32 entry = (i + fsrv->persistent_replay_idx) % fsrv->persistent_replay; + u8 *data = fsrv->persistent_replay_data[entry]; + u32 *len = fsrv->persistent_replay_len[entry]; + if (likely(len && *len && data)) { + + snprintf(fn, sizeof(fn), "%s/replay_%u_%u.bin", + fsrv->persistent_replay_dir, fsrv->persistent_replay_cnt, + writecnt++); + int fd = open(fn, O_WRONLY, 0644); + if (fd >= 0) { + + ck_write(fd, data, *len, fn); + close(fd); + + } + + } + + } + + ++fsrv->persistent_replay_cnt; + + } + /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ fsrv->last_kill_signal = WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 77e6e2ce..f3aea2c7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1239,9 +1239,10 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->afl_env.afl_persistent_replay) { + if (unlikely(afl->afl_env.afl_persistent_replay)) { afl->fsrv.persistent_replay = atoi(afl->afl_env.afl_persistent_replay); + afl->fsrv.persistent_replay_dir = alloc_printf("%s/crashes", afl->out_dir); } -- cgit 1.4.1 From 4a0d4c50fc8bec11a090156ab970414d4897ea6c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 19:12:25 +0100 Subject: complete implemenation, still no test --- include/afl-fuzz.h | 2 +- include/forkserver.h | 13 ++++++----- src/afl-forkserver.c | 63 +++++++++++++++++++++++++++++++++------------------- src/afl-fuzz-state.c | 4 ++-- src/afl-fuzz.c | 22 +++++++++++++++--- 5 files changed, 69 insertions(+), 35 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3b6f2285..b1fba884 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal, *afl_persistent_replay; + *afl_testcache_entries, *afl_kill_signal, *afl_persistent_record; } afl_env_vars_t; diff --git a/include/forkserver.h b/include/forkserver.h index ddbc36ef..850c5b0d 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -95,12 +95,13 @@ typedef struct afl_forkserver { char *cmplog_binary; /* the name of the cmplog binary */ /* persistent mode replay functionality */ - u32 persistent_replay; /* persistent replay setting */ - u32 persistent_replay_idx; /* persistent replay cache ptr */ - u32 persistent_replay_cnt; /* persistent replay counter */ - u8 * persistent_replay_dir; - u8 ** persistent_replay_data; - u32 **persistent_replay_len; + u32 persistent_record; /* persistent replay setting */ + u32 persistent_record_idx; /* persistent replay cache ptr */ + u32 persistent_record_cnt; /* persistent replay counter */ + u8 * persistent_record_dir; + u8 ** persistent_record_data; + u32 **persistent_record_len; + s32 persistent_record_pid; /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 05aba2e5..78e5efe7 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -126,7 +126,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->last_run_timed_out = 0; fsrv_to->init_child_func = from->init_child_func; - // Note: do not copy ->add_extra_func or ->persistent_replay* + // Note: do not copy ->add_extra_func or ->persistent_record* list_append(&fsrv_list, fsrv_to); @@ -364,14 +364,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the fork server..."); } - if (unlikely(fsrv->persistent_replay)) { + if (unlikely(fsrv->persistent_record)) { - fsrv->persistent_replay_data = - (u8 **)ck_alloc(fsrv->persistent_replay * sizeof(size_t)); - fsrv->persistent_replay_len = - (u32 **)ck_alloc(fsrv->persistent_replay * sizeof(u32)); + fsrv->persistent_record_data = + (u8 **)ck_alloc(fsrv->persistent_record * sizeof(size_t)); + fsrv->persistent_record_len = + (u32 **)ck_alloc(fsrv->persistent_record * sizeof(u32)); - if (!fsrv->persistent_replay_data || !fsrv->persistent_replay_len) { + if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) { FATAL("Unable to allocate memory for persistent replay."); @@ -1013,24 +1013,24 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { - if (unlikely(fsrv->persistent_replay)) { + if (unlikely(fsrv->persistent_record)) { - *fsrv->persistent_replay_len[fsrv->persistent_replay_idx] = len; - fsrv->persistent_replay_data[fsrv->persistent_replay_idx] = afl_realloc( - (void **)&fsrv->persistent_replay_data[fsrv->persistent_replay_idx], + *fsrv->persistent_record_len[fsrv->persistent_record_idx] = len; + fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc( + (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx], len); - if (unlikely(!fsrv->persistent_replay_data[fsrv->persistent_replay_idx])) { + if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) { FATAL("allocating replay memory failed."); } - memcpy(fsrv->persistent_replay_data[fsrv->persistent_replay_idx], buf, len); + memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len); - if (unlikely(++fsrv->persistent_replay_idx >= fsrv->persistent_replay)) { + if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) { - fsrv->persistent_replay_idx = 0; + fsrv->persistent_record_idx = 0; } @@ -1148,6 +1148,23 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } + // end of persistent loop? + if (unlikely(fsrv->persistent_record && + fsrv->persistent_record_pid != fsrv->child_pid)) { + + fsrv->persistent_record_pid = fsrv->child_pid; + u32 idx, val; + if (unlikely(!fsrv->persistent_record_idx)) + idx = fsrv->persistent_record - 1; + else + idx = fsrv->persistent_record_idx - 1; + val = *fsrv->persistent_record_len[idx]; + memset((void *)fsrv->persistent_record_len, 0, + fsrv->persistent_record * sizeof(u32)); + *fsrv->persistent_record_len[idx] = val; + + } + if (fsrv->child_pid <= 0) { if (*stop_soon_p) { return 0; } @@ -1246,19 +1263,19 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { - if (unlikely(fsrv->persistent_replay)) { + if (unlikely(fsrv->persistent_record)) { char fn[4096]; u32 i, writecnt = 0; - for (i = 0; i < fsrv->persistent_replay; ++i) { + for (i = 0; i < fsrv->persistent_record; ++i) { - u32 entry = (i + fsrv->persistent_replay_idx) % fsrv->persistent_replay; - u8 *data = fsrv->persistent_replay_data[entry]; - u32 *len = fsrv->persistent_replay_len[entry]; + u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record; + u8 *data = fsrv->persistent_record_data[entry]; + u32 *len = fsrv->persistent_record_len[entry]; if (likely(len && *len && data)) { - snprintf(fn, sizeof(fn), "%s/replay_%u_%u.bin", - fsrv->persistent_replay_dir, fsrv->persistent_replay_cnt, + snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u", + fsrv->persistent_record_dir, fsrv->persistent_record_cnt, writecnt++); int fd = open(fn, O_WRONLY, 0644); if (fd >= 0) { @@ -1272,7 +1289,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - ++fsrv->persistent_replay_cnt; + ++fsrv->persistent_record_cnt; } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 075aef1e..514414f3 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -292,11 +292,11 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_autoresume = get_afl_env(afl_environment_variables[i]) ? 1 : 0; - } else if (!strncmp(env, "AFL_PERSISTENT_REPLAY", + } else if (!strncmp(env, "AFL_PERSISTENT_RECORD", afl_environment_variable_len)) { - afl->afl_env.afl_persistent_replay = + afl->afl_env.afl_persistent_record = get_afl_env(afl_environment_variables[i]); } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f3aea2c7..afaa8f5f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1239,10 +1239,26 @@ int main(int argc, char **argv_orig, char **envp) { } - if (unlikely(afl->afl_env.afl_persistent_replay)) { + if (unlikely(afl->afl_env.afl_persistent_record)) { - afl->fsrv.persistent_replay = atoi(afl->afl_env.afl_persistent_replay); - afl->fsrv.persistent_replay_dir = alloc_printf("%s/crashes", afl->out_dir); + afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); + afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); + + if (afl->fsrv.persistent_record < 2) { + + FATAL( + "AFL_PERSISTENT_RECORD vallue must be be at least 2, recommended is " + "100 or 1000."); + + } + + if (!getenv(PERSIST_ENV_VAR)) { + + FATAL( + "Target binary is not compiled in persistent mode, " + "AFL_PERSISTENT_RECORD makes no sense."); + + } } -- cgit 1.4.1 From 99b4c3f3624db9300c175936aff22535db6eef67 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 22:19:56 +0100 Subject: fix --- src/afl-forkserver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 78e5efe7..a6128220 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -367,7 +368,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (unlikely(fsrv->persistent_record)) { fsrv->persistent_record_data = - (u8 **)ck_alloc(fsrv->persistent_record * sizeof(size_t)); + (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *)); fsrv->persistent_record_len = (u32 **)ck_alloc(fsrv->persistent_record * sizeof(u32)); @@ -1265,7 +1266,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (unlikely(fsrv->persistent_record)) { - char fn[4096]; + char fn[PATH_MAX]; u32 i, writecnt = 0; for (i = 0; i < fsrv->persistent_record; ++i) { -- cgit 1.4.1 From 7f062524c97ab18306d42e59ab0223e04ff78f24 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 23:01:13 +0100 Subject: fixes --- include/envs.h | 2 +- include/forkserver.h | 2 +- src/afl-forkserver.c | 14 +++++++------- src/afl-fuzz.c | 50 +++++++++++++++++++++++++++----------------------- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/include/envs.h b/include/envs.h index f82bb803..6ba69f26 100644 --- a/include/envs.h +++ b/include/envs.h @@ -123,7 +123,7 @@ static char *afl_environment_variables[] = { "AFL_MAX_DET_EXTRAS", "AFL_PATH", "AFL_PERFORMANCE_FILE", - "AFL_PERSISTEN_REPLAY", + "AFL_PERSISTENT_RECORD", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", diff --git a/include/forkserver.h b/include/forkserver.h index 850c5b0d..c894ad80 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -100,7 +100,7 @@ typedef struct afl_forkserver { u32 persistent_record_cnt; /* persistent replay counter */ u8 * persistent_record_dir; u8 ** persistent_record_data; - u32 **persistent_record_len; + u32 * persistent_record_len; s32 persistent_record_pid; /* Function to kick off the forkserver child */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a6128220..e6738a71 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -370,7 +370,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, fsrv->persistent_record_data = (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *)); fsrv->persistent_record_len = - (u32 **)ck_alloc(fsrv->persistent_record * sizeof(u32)); + (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32)); if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) { @@ -1016,7 +1016,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { if (unlikely(fsrv->persistent_record)) { - *fsrv->persistent_record_len[fsrv->persistent_record_idx] = len; + fsrv->persistent_record_len[fsrv->persistent_record_idx] = len; fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc( (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx], len); @@ -1159,10 +1159,10 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, idx = fsrv->persistent_record - 1; else idx = fsrv->persistent_record_idx - 1; - val = *fsrv->persistent_record_len[idx]; + val = fsrv->persistent_record_len[idx]; memset((void *)fsrv->persistent_record_len, 0, fsrv->persistent_record * sizeof(u32)); - *fsrv->persistent_record_len[idx] = val; + fsrv->persistent_record_len[idx] = val; } @@ -1272,8 +1272,8 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record; u8 *data = fsrv->persistent_record_data[entry]; - u32 *len = fsrv->persistent_record_len[entry]; - if (likely(len && *len && data)) { + u32 len = fsrv->persistent_record_len[entry]; + if (likely(len && data)) { snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u", fsrv->persistent_record_dir, fsrv->persistent_record_cnt, @@ -1281,7 +1281,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, int fd = open(fn, O_WRONLY, 0644); if (fd >= 0) { - ck_write(fd, data, *len, fn); + ck_write(fd, data, len, fn); close(fd); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index afaa8f5f..4ee71120 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -986,6 +986,21 @@ int main(int argc, char **argv_orig, char **envp) { } + if (unlikely(afl->afl_env.afl_persistent_record)) { + + afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); + afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); + + if (afl->fsrv.persistent_record < 2) { + + FATAL( + "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is " + "100 or 1000."); + + } + + } + if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { u8 *preload = getenv("AFL_PRELOAD"); @@ -1239,29 +1254,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (unlikely(afl->afl_env.afl_persistent_record)) { - - afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); - afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); - - if (afl->fsrv.persistent_record < 2) { - - FATAL( - "AFL_PERSISTENT_RECORD vallue must be be at least 2, recommended is " - "100 or 1000."); - - } - - if (!getenv(PERSIST_ENV_VAR)) { - - FATAL( - "Target binary is not compiled in persistent mode, " - "AFL_PERSISTENT_RECORD makes no sense."); - - } - - } - if (afl->afl_env.afl_crash_exitcode) { long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10); @@ -1531,6 +1523,18 @@ int main(int argc, char **argv_orig, char **envp) { check_binary(afl, argv[optind]); + if (unlikely(afl->fsrv.persistent_record)) { + + if (!getenv(PERSIST_ENV_VAR)) { + + FATAL( + "Target binary is not compiled in persistent mode, " + "AFL_PERSISTENT_RECORD makes no sense."); + + } + + } + if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); } afl->start_time = get_cur_time(); -- cgit 1.4.1 From 517db1b8dc1b310b82a73e3878285ca03249f3e4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 23:12:44 +0100 Subject: fixes --- src/afl-forkserver.c | 2 +- src/afl-fuzz.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index e6738a71..2ab1304e 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1278,7 +1278,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u", fsrv->persistent_record_dir, fsrv->persistent_record_cnt, writecnt++); - int fd = open(fn, O_WRONLY, 0644); + int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (fd >= 0) { ck_write(fd, data, len, fn); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 4ee71120..267ab075 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -989,7 +989,6 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->afl_env.afl_persistent_record)) { afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); - afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); if (afl->fsrv.persistent_record < 2) { @@ -1533,6 +1532,8 @@ int main(int argc, char **argv_orig, char **envp) { } + afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir); + } if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); } -- cgit 1.4.1 From d3f69ab4c6d4f1e2eb3349eec3f1cb9313081151 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 7 Mar 2021 08:43:01 +0100 Subject: documentation for AFL_PERSISTENT_RECORD --- docs/env_variables.md | 9 +++++++++ src/afl-fuzz.c | 1 + 2 files changed, 10 insertions(+) diff --git a/docs/env_variables.md b/docs/env_variables.md index 4c3b1cfb..41733f1b 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -400,6 +400,15 @@ checks or alter some of the more exotic semantics of the tool: - Setting `AFL_FORCE_UI` will force painting the UI on the screen even if no valid terminal was detected (for virtual consoles) + - If you are using persistent mode (you should, see [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md)) + some targets keep inherent state due which a detected crash testcase does + not crash the target again when the testcase is given. To be able to still + re-trigger these crashes you can use the `AFL_PERSISTENT_RECORD` variable + with a value of how many previous fuzz cases to keep prio a crash. + if set to e.g. 10, then the 9 previous inputs are written to + out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 + and RECORD:000000,cnt:000009 being the crash case. + - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`. Others need not apply. diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 267ab075..b2c81580 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -218,6 +218,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_PATH: path to AFL support binaries\n" "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_QUIET: suppress forkserver status messages\n" + "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in out/crashes\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" -- cgit 1.4.1 From 1ab125de63627855752d28abf847b3cc0bdf8582 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:18:41 -0400 Subject: afl-cmin: Allow @@ to be part of an arg The previous implementation of "@@ handling" in afl-cmin differed greatly from how it was handled in afl-fuzz and how the documentation presented it. It used to require that the @@ be its own argument separated by whitespace and could not be used in situations like "--file=@@". This change standardizes it to just look for @@ to be *in* an argument in the same manner that afl-cmin.bash does, so that it will have the expected and documented behavior. --- afl-cmin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afl-cmin b/afl-cmin index 778d7487..a1fc6f21 100755 --- a/afl-cmin +++ b/afl-cmin @@ -243,7 +243,7 @@ BEGIN { if (!stdin_file) { found_atat = 0 for (prog_args_ind in prog_args) { - if ("@@" == prog_args[prog_args_ind]) { + if (match(prog_args[prog_args_ind], "@@") != 0) { found_atat = 1 break } -- cgit 1.4.1 From 70403f7e1b586bf23eebb131d5db2397d708abf0 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:09:54 -0400 Subject: triage_crashes.sh: Allow @@ to be part of an arg --- utils/crash_triage/triage_crashes.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh index bf763cba..42cf8158 100755 --- a/utils/crash_triage/triage_crashes.sh +++ b/utils/crash_triage/triage_crashes.sh @@ -90,8 +90,9 @@ for crash in $DIR/crashes/id:*; do for a in $@; do - if [ "$a" = "@@" ] ; then - use_args="$use_args $crash" + if echo "$a" | grep -qF '@@'; then + escaped_fname=`echo $crash | sed 's:/:\\\\/:g'` + use_args="$use_args `echo $a | sed "s/@@/$escaped_fname/g"`" unset use_stdio else use_args="$use_args $a" -- cgit 1.4.1 From b289e7ad073d4affae76de3da5d1faeba0f8a07e Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:09:03 -0400 Subject: triage_crashes.sh: Fix error reporting --- utils/crash_triage/triage_crashes.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh index 42cf8158..c9ca1f79 100755 --- a/utils/crash_triage/triage_crashes.sh +++ b/utils/crash_triage/triage_crashes.sh @@ -60,12 +60,12 @@ if fi if [ ! -f "$BIN" -o ! -x "$BIN" ]; then - echo "[-] Error: binary '$2' not found or is not executable." 1>&2 + echo "[-] Error: binary '$BIN' not found or is not executable." 1>&2 exit 1 fi if [ ! -d "$DIR/queue" ]; then - echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2 + echo "[-] Error: directory '$DIR' not found or not created by afl-fuzz." 1>&2 exit 1 fi -- cgit 1.4.1 From 27c048086659808bc1e6742023d4e89330283e02 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Mon, 15 Mar 2021 13:12:11 -0400 Subject: afl-showmap: Allow @@ to be part of an arg The previous implementation of "@@ handling" in afl-showmap differed greatly from how it was handled in afl-fuzz and how the documentation presented it. It used to require that the @@ be its own argument separated by whitespace and could not be used in situations like "--file=@@". This change standardizes it to use detect_file_args() like everybody else does, so that it will have the expected and documented behavior. --- src/afl-common.c | 27 +++++++++++---------------- src/afl-showmap.c | 54 ++++++++++++++++++++++-------------------------------- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/afl-common.c b/src/afl-common.c index 9f6eb564..55564554 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -70,31 +70,26 @@ void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) { *use_stdin = false; - if (prog_in[0] != 0) { // not afl-showmap special case + /* Be sure that we're always using fully-qualified paths. */ - u8 *n_arg; + *aa_loc = 0; - /* Be sure that we're always using fully-qualified paths. */ + /* Construct a replacement argv value. */ + u8 *n_arg; - *aa_loc = 0; + if (prog_in[0] == '/') { - /* Construct a replacement argv value. */ + n_arg = alloc_printf("%s%s%s", argv[i], prog_in, aa_loc + 2); - if (prog_in[0] == '/') { - - n_arg = alloc_printf("%s%s%s", argv[i], prog_in, aa_loc + 2); - - } else { - - n_arg = alloc_printf("%s%s/%s%s", argv[i], cwd, prog_in, aa_loc + 2); - - } + } else { - ck_free(argv[i]); - argv[i] = n_arg; + n_arg = alloc_printf("%s%s/%s%s", argv[i], cwd, prog_in, aa_loc + 2); } + ck_free(argv[i]); + argv[i] = n_arg; + } i++; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0fc76193..2627f491 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -72,8 +72,7 @@ static u8 *in_data, /* Input data */ static u64 total; /* tuple content information */ static u32 tcnt, highest; /* tuple content information */ -static u32 in_len, /* Input data length */ - arg_offset; /* Total number of execs */ +static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; @@ -738,7 +737,7 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; + s32 opt; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; char **use_argv; @@ -986,7 +985,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_DEBUG")) { DEBUGF(""); - for (i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) SAYF(" %s", argv[i]); SAYF("\n"); @@ -1012,12 +1011,30 @@ int main(int argc, char **argv_orig, char **envp) { } + if (in_dir) { - detect_file_args(argv + optind, "", &fsrv->use_stdin); + /* If we don't have a file name chosen yet, use a safe default. */ + u8 *use_dir = "."; + + if (access(use_dir, R_OK | W_OK | X_OK)) { + + use_dir = get_afl_env("TMPDIR"); + if (!use_dir) { use_dir = "/tmp"; } + + } + + stdin_file = at_file ? strdup(at_file) + : (char *)alloc_printf("%s/.afl-showmap-temp-%u", + use_dir, (u32)getpid()); + unlink(stdin_file); + + // If @@ are in the target args, replace them and also set use_stdin=false. + detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin); } else { + // If @@ are in the target args, replace them and also set use_stdin=false. detect_file_args(argv + optind, at_file, &fsrv->use_stdin); } @@ -1042,14 +1059,6 @@ int main(int argc, char **argv_orig, char **envp) { } - i = 0; - while (use_argv[i] != NULL && !arg_offset) { - - if (strcmp(use_argv[i], "@@") == 0) { arg_offset = i; } - i++; - - } - shm_fuzz = ck_alloc(sizeof(sharedmem_t)); /* initialize cmplog_mode */ @@ -1160,30 +1169,11 @@ int main(int argc, char **argv_orig, char **envp) { } - u8 *use_dir = "."; - - if (access(use_dir, R_OK | W_OK | X_OK)) { - - use_dir = get_afl_env("TMPDIR"); - if (!use_dir) { use_dir = "/tmp"; } - - } - - stdin_file = at_file ? strdup(at_file) - : (char *)alloc_printf("%s/.afl-showmap-temp-%u", - use_dir, (u32)getpid()); - unlink(stdin_file); atexit(at_exit_handler); fsrv->out_file = stdin_file; fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600); if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } - if (arg_offset && use_argv[arg_offset] != stdin_file) { - - use_argv[arg_offset] = strdup(stdin_file); - - } - if (get_afl_env("AFL_DEBUG")) { int j = optind; -- cgit 1.4.1 From 62f067ec71aff384a197511b33142002ca284c66 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:04:10 -0700 Subject: afl-showmap: Unwind a change to keep it pre-C99 compatible --- src/afl-showmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 2627f491..29b8456f 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -737,7 +737,7 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt; + s32 opt, i; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; char **use_argv; @@ -985,7 +985,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_DEBUG")) { DEBUGF(""); - for (int i = 0; i < argc; i++) + for (i = 0; i < argc; i++) SAYF(" %s", argv[i]); SAYF("\n"); -- cgit 1.4.1 From ee5078f43c44a022831cf83b6963930975188168 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 11:22:37 +0100 Subject: v3.13a init --- docs/Changelog.md | 3 +++ include/config.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 5b7d6ab6..6b7ebf15 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.13a (development) + - ... + ### Version ++3.12c (release) - afl-fuzz: - added AFL_TARGET_ENV variable to pass extra env vars to the target diff --git a/include/config.h b/include/config.h index c93a6d51..8ac74c45 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 "++3.12c" +#define VERSION "++3.13a" /****************************************************** * * -- cgit 1.4.1 From 958436be4ba057e8409787e7ff4ddcfa095c46da Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:18:05 +0100 Subject: ifdef for record --- include/config.h | 9 +++++++++ src/afl-forkserver.c | 8 ++++++++ src/afl-fuzz.c | 30 +++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/include/config.h b/include/config.h index 60872785..f6dbfae0 100644 --- a/include/config.h +++ b/include/config.h @@ -60,6 +60,15 @@ /* Now non-cmplog configuration options */ + +/* If a persistent target keeps state and found crashes are not reproducable + then enable this option and set the AFL_PERSISTENT_RECORD env variable + to a number. These number of testcases prior the crash will be kept and + also written to the crash/ directory */ + +#define AFL_PERSISTENT_RECORD + + /* console output colors: There are three ways to configure its behavior * 1. default: colored outputs fixed on: defined USE_COLOR && defined * ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 2ab1304e..4e4f92d6 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -365,6 +365,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the fork server..."); } +#ifdef AFL_PERSISTENT_RECORD if (unlikely(fsrv->persistent_record)) { fsrv->persistent_record_data = @@ -379,6 +380,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } } +#endif if (fsrv->use_fauxsrv) { @@ -1014,6 +1016,7 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { +#ifdef AFL_PERSISTENT_RECORD if (unlikely(fsrv->persistent_record)) { fsrv->persistent_record_len[fsrv->persistent_record_idx] = len; @@ -1036,6 +1039,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } } +#endif if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { @@ -1149,6 +1153,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } +#ifdef AFL_PERSISTENT_RECORD // end of persistent loop? if (unlikely(fsrv->persistent_record && fsrv->persistent_record_pid != fsrv->child_pid)) { @@ -1165,6 +1170,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, fsrv->persistent_record_len[idx] = val; } +#endif if (fsrv->child_pid <= 0) { @@ -1264,6 +1270,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { +#ifdef AFL_PERSISTENT_RECORD if (unlikely(fsrv->persistent_record)) { char fn[PATH_MAX]; @@ -1293,6 +1300,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, ++fsrv->persistent_record_cnt; } +#endif /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ fsrv->last_kill_signal = diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b2c81580..d622db71 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -218,7 +218,9 @@ static void usage(u8 *argv0, int more_help) { "AFL_PATH: path to AFL support binaries\n" "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_QUIET: suppress forkserver status messages\n" +#ifdef AFL_PERSISTENT_RECORD "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in out/crashes\n" +#endif "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" @@ -249,7 +251,13 @@ static void usage(u8 *argv0, int more_help) { SAYF("Compiled with %s module support, see docs/custom_mutator.md\n", (char *)PYTHON_VERSION); #else - SAYF("Compiled without python module support\n"); + SAYF("Compiled without python module support.\n"); +#endif + +#ifdef AFL_PERSISTENT_RECORD + SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n"); +#else + SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n"); #endif #ifdef USEMMAP @@ -259,27 +267,27 @@ static void usage(u8 *argv0, int more_help) { #endif #ifdef ASAN_BUILD - SAYF("Compiled with ASAN_BUILD\n\n"); + SAYF("Compiled with ASAN_BUILD.\n"); #endif #ifdef NO_SPLICING - SAYF("Compiled with NO_SPLICING\n\n"); + SAYF("Compiled with NO_SPLICING.\n"); #endif #ifdef PROFILING - SAYF("Compiled with PROFILING\n\n"); + SAYF("Compiled with PROFILING.\n"); #endif #ifdef INTROSPECTION - SAYF("Compiled with INTROSPECTION\n\n"); + SAYF("Compiled with INTROSPECTION.\n"); #endif #ifdef _DEBUG - SAYF("Compiled with _DEBUG\n\n"); + SAYF("Compiled with _DEBUG.\n"); #endif #ifdef _AFL_DOCUMENT_MUTATIONS - SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS\n\n"); + SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n"); #endif SAYF("For additional help please consult %s/README.md :)\n\n", doc_path); @@ -989,6 +997,8 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->afl_env.afl_persistent_record)) { +#ifdef AFL_PERSISTENT_RECORD + afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); if (afl->fsrv.persistent_record < 2) { @@ -999,6 +1009,12 @@ int main(int argc, char **argv_orig, char **envp) { } +#else + + FATAL("afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in config.h!"); + +#endif + } if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { -- cgit 1.4.1 From 836aeef595462a37f6be4665a5a6123002423b41 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:22:50 +0100 Subject: changelog info --- docs/Changelog.md | 7 ++++++- docs/env_variables.md | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6b7ebf15..caa06ffd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,12 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) - - ... + - afl-fuzz: + - added patch by @realmadsci to support @@ as part of command line + options, e.g. `afl-fuzz ... -- ./target --infile=@@` + - add recording of previous fuzz attempts for persistent mode + to allow replay of non-reproducable crashes, see + AFL_PERSISTENT_RECORD in config.h and docs/envs.h ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index de6b4bd8..6d3d1714 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -432,6 +432,7 @@ checks or alter some of the more exotic semantics of the tool: if set to e.g. 10, then the 9 previous inputs are written to out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 and RECORD:000000,cnt:000009 being the crash case. + NOTE: This option needs to be enabled in config.h first! - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`. Others need not apply, unless they also want to disable the -- cgit 1.4.1 From 55224e5150b3acfc4c1db3975ef6a2b5e173f626 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:24:52 +0100 Subject: AFL_PERSISTENT_RECORD not a default --- include/config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/config.h b/include/config.h index ab4c49f2..4691624a 100644 --- a/include/config.h +++ b/include/config.h @@ -71,16 +71,16 @@ /* Maximum allowed fails per CMP value. Default: 128 */ #define CMPLOG_FAIL_MAX 96 +/* -------------------------------------*/ /* Now non-cmplog configuration options */ - +/* -------------------------------------*/ /* If a persistent target keeps state and found crashes are not reproducable then enable this option and set the AFL_PERSISTENT_RECORD env variable to a number. These number of testcases prior the crash will be kept and also written to the crash/ directory */ -#define AFL_PERSISTENT_RECORD - +//#define AFL_PERSISTENT_RECORD /* console output colors: There are three ways to configure its behavior * 1. default: colored outputs fixed on: defined USE_COLOR && defined -- cgit 1.4.1 From e1384b5086e918350426cd0ece7dbe9c451f771f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 18 Mar 2021 09:11:00 +0000 Subject: Add support for FRIDA mode --- .gitignore | 1 + frida_mode/.gitignore | 5 + frida_mode/Makefile | 310 +++++++++++++++++++++++++++++++++ frida_mode/README.md | 48 ++++++ frida_mode/inc/instrument.h | 7 + frida_mode/inc/interceptor.h | 4 + frida_mode/inc/prefetch.h | 5 + frida_mode/inc/ranges.h | 6 + frida_mode/src/instrument.c | 265 +++++++++++++++++++++++++++++ frida_mode/src/interceptor.c | 16 ++ frida_mode/src/main.c | 149 ++++++++++++++++ frida_mode/src/prefetch.c | 121 +++++++++++++ frida_mode/src/ranges.c | 395 +++++++++++++++++++++++++++++++++++++++++++ frida_mode/test/testinstr.c | 105 ++++++++++++ frida_mode/test/testinstr.py | 32 ++++ include/envs.h | 7 + include/forkserver.h | 2 + src/afl-analyze.c | 50 +++++- src/afl-fuzz-init.c | 7 +- src/afl-fuzz.c | 54 +++++- src/afl-showmap.c | 47 ++++- src/afl-tmin.c | 49 +++++- 22 files changed, 1668 insertions(+), 17 deletions(-) create mode 100644 frida_mode/.gitignore create mode 100644 frida_mode/Makefile create mode 100644 frida_mode/README.md create mode 100644 frida_mode/inc/instrument.h create mode 100644 frida_mode/inc/interceptor.h create mode 100644 frida_mode/inc/prefetch.h create mode 100644 frida_mode/inc/ranges.h create mode 100644 frida_mode/src/instrument.c create mode 100644 frida_mode/src/interceptor.c create mode 100644 frida_mode/src/main.c create mode 100644 frida_mode/src/prefetch.c create mode 100644 frida_mode/src/ranges.c create mode 100644 frida_mode/test/testinstr.c create mode 100755 frida_mode/test/testinstr.py diff --git a/.gitignore b/.gitignore index 3f440730..2aaaf9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,4 @@ libAFLDriver.a libAFLQemuDriver.a test/.afl_performance gmon.out +afl-frida-trace.so diff --git a/frida_mode/.gitignore b/frida_mode/.gitignore new file mode 100644 index 00000000..956b9911 --- /dev/null +++ b/frida_mode/.gitignore @@ -0,0 +1,5 @@ +build/ +frida_test.dat +qemu_test.dat +frida_out/** +qemu_out/** diff --git a/frida_mode/Makefile b/frida_mode/Makefile new file mode 100644 index 00000000..73a4142c --- /dev/null +++ b/frida_mode/Makefile @@ -0,0 +1,310 @@ +PWD:=$(shell pwd)/ +INC_DIR:=$(PWD)inc/ +SRC_DIR:=$(PWD)src/ +INCLUDES:=$(wildcard $(INC_DIR)*.h) +SOURCES:=$(wildcard $(SRC_DIR)*.c) +BUILD_DIR:=$(PWD)build/ +CFLAGS:= $(CFLAGS) \ + -fPIC \ + -D_GNU_SOURCE + +FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ +FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" +ARCH:=arm64 +TESTINSTR_BASE:=0x0000aaaaaaaaa000 +endif + +ifeq "$(ARCH)" "x86_64" +TESTINSTR_BASE:=0x0000555555554000 +endif + +ifeq "$(shell uname)" "Darwin" +OS:=macos +AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF +CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations +TEST_LDFLAGS:=-undefined dynamic_lookup +endif +ifeq "$(shell uname)" "Linux" +OS:=linux +AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) +CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor +TEST_LDFLAGS:= +endif + +ifndef OS +$(error "Operating system unsupported") +endif + +VERSION=14.2.13 +GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz +GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)" +GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) +GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a +GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h + +TEST_BUILD_DIR:=$(BUILD_DIR)test/ + +LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz +LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz +LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/ +LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile +LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a + +HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc +PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o +PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" + +TEST_BIN:=$(TEST_BUILD_DIR)pngtest + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)test/testinstr.c + +TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/ + +TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat +FRIDA_OUT:=$(PWD)frida_out +QEMU_OUT:=$(PWD)qemu_out + +.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone + +all: $(FRIDA_TRACE) + +frida: $(FRIDA_TRACE) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# FRIDA ############################################ +$(FRIDA_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) + wget -O $@ $(GUM_DEVKIT_URL) + +$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR) + $(CC) -shared \ + $(CFLAGS) \ + -o $@ $(SOURCES) \ + $(GUM_DEVIT_LIBRARY) \ + -I $(FRIDA_BUILD_DIR) \ + -I .. \ + -I ../include \ + -I $(INC_DIR) \ + ../instrumentation/afl-compiler-rt.o.c \ + -lpthread -ldl -lresolv + + cp -v $(FRIDA_TRACE) ../ + +############################# TEST ############################################# + +test: $(TEST_BIN) + +$(TEST_BUILD_DIR): $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) -o $@ -c $< + +$(PNGTEST_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(PNGTEST_URL) + +$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) + $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + +$(LIBPNG_FILE): | $(TEST_BUILD_DIR) + wget -O $@ $(LIBPNG_URL) + +$(LIBPNG_DIR): $(LIBPNG_FILE) + tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR) + +$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) + cd $(LIBPNG_DIR) && ./configure + +$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) + make -C $(LIBPNG_DIR) + +$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) + $(CXX) \ + -o $@ \ + $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ + -lz \ + $(TEST_LDFLAGS) + +############################# TESTINSR ######################################### +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< + +testinstr: $(TESTINSTBIN) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd .. && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i + cd .. && ./.custom-format.py -i $(TESTINSTSRC) + +############################# RUN ############################################# + +# Add the environment variable AFL_DEBUG_CHILD=1 to show printf's from the target + +png_frida: $(FRIDA_TRACE) $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +png_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-fuzz \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +compare: $(FRIDA_TRACE) $(TEST_BIN) + cd .. && \ + ./afl-fuzz \ + -V30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + cd .. && \ + ./afl-fuzz \ + -V30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + cat frida_out/default/fuzzer_stats + cat qemu_out/default/fuzzer_stats + +testinstr_qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + make -C .. + cd .. && \ + AFL_QEMU_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + ./afl-fuzz \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +testinstr_frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + make -C .. + cd .. && \ + AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + AFL_FRIDA_INST_NO_OPTIMIZE=1 \ + AFL_FRIDA_INST_NO_PREFETCH=1 \ + AFL_FRIDA_INST_STRICT=1 \ + ./afl-fuzz \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +standalone: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + cd .. && \ + AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + AFL_DEBUG_CHILD=1 \ + AFL_FRIDA_DEBUG_MAPS=1 \ + AFL_FRIDA_INST_NO_OPTIMIZE=1 \ + AFL_FRIDA_INST_NO_PREFETCH=1 \ + AFL_FRIDA_INST_TRACE=1 \ + AFL_FRIDA_INST_STRICT=1 \ + LD_PRELOAD=$(FRIDA_TRACE) \ + DYLD_INSERT_LIBRARIES=$(FRIDA_TRACE) \ + $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + +tmin_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-tmin \ + -Q \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -o $(QEMU_OUT)/qemu-min-basn0g01.png \ + -- \ + $(TEST_BIN) @@ + +tmin_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-tmin \ + -O \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -o $(FRIDA_OUT)/qemu-min-basn0g01.png \ + -- \ + $(TEST_BIN) + +showmap_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-showmap \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +showmap_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-showmap \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +analyze_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-analyze \ + -Q \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -- \ + $(TEST_BIN) @@ + +analyze_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-analyze \ + -O \ + -i $(TEST_DATA_DIR)basn0g01.png \ + -- \ + $(TEST_BIN) @@ \ No newline at end of file diff --git a/frida_mode/README.md b/frida_mode/README.md new file mode 100644 index 00000000..c5436e8b --- /dev/null +++ b/frida_mode/README.md @@ -0,0 +1,48 @@ +# FRIDA MODE +The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL +just like that provided by QEMU mode. The intention is to provide a very similar +user experience, right down to the options provided through environment variables. + +Additionally, the intention is to be able to make a direct performance comparison +between the two approaches. Hopefully, we should also be able to leverage the same +approaches for adding features which QEMU uses, possibly even sharing code. + +## Limitations +The current focus is on x64 support for Intel. Although parts may be architecturally +dependent, the approach itself should remain architecture agnostic. + +## Usage +FRIDA mode requires some small modifications to the afl-fuzz and similar tools in +AFLplusplus. The intention is that it behaves identically to QEMU, but uses the 'O' +switch rather than 'Q'. + +## Design +AFL Frida works by means of a shared library injected into a binary program using +LD_PRELOAD, similar to the way which other fuzzing features are injected into targets. + +## Testing +Alongside the FRIDA mode, we also include a test program for fuzzing. This test +program is built using the libpng benchmark from fuzz-bench and integrating the +StandaloneFuzzTargetMain from the llvm project. This is built and linked without +any special modifications to suit FRIDA or QEMU. However, at present we don't have +a representative corpus. + +## Getting Started +To build everything run `make`. + +To run the benchmark sample with qemu run `make test_qemu`. +To run the benchmark sample with frida run `make test_frida`. + +# Configuration options +* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` +* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` +* `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_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. +* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` +* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into excluded regions and generate both instrumented blocks and coverage data (e.g. indirect calls on x86). The excluded block is generally honoured as soon as another function is called within the excluded region. The overhead of generating, running and instrumenting these few additional blocks is likely to be fairly small, but it may hinder you when checking that the correct number of paths are found for testing purposes or similar. There is a performance penatly for this option during block compilation where we check the block isn't in a list of excluded ranges. +* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. + +# TODO +* Add AARCH64 inline assembly optimization from libFuzz +* Fix issues running on OSX +* Identify cause of erroneous additional paths diff --git a/frida_mode/inc/instrument.h b/frida_mode/inc/instrument.h new file mode 100644 index 00000000..ff71bed4 --- /dev/null +++ b/frida_mode/inc/instrument.h @@ -0,0 +1,7 @@ +#include "frida-gum.h" + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); + +void instrument_init(); + diff --git a/frida_mode/inc/interceptor.h b/frida_mode/inc/interceptor.h new file mode 100644 index 00000000..5ed3cf49 --- /dev/null +++ b/frida_mode/inc/interceptor.h @@ -0,0 +1,4 @@ +#include "frida-gum.h" + +void intercept(void *address, gpointer replacement, gpointer user_data); + diff --git a/frida_mode/inc/prefetch.h b/frida_mode/inc/prefetch.h new file mode 100644 index 00000000..b7f25a97 --- /dev/null +++ b/frida_mode/inc/prefetch.h @@ -0,0 +1,5 @@ +void prefetch_init(); +void prefetch_start(GumStalker *stalker); +void prefetch_write(void *addr); +void prefetch_read(GumStalker *stalker); + diff --git a/frida_mode/inc/ranges.h b/frida_mode/inc/ranges.h new file mode 100644 index 00000000..b9394dbc --- /dev/null +++ b/frida_mode/inc/ranges.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +void ranges_init(GumStalker *stalker); + +gboolean range_is_excluded(gpointer address); + diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c new file mode 100644 index 00000000..042fdab8 --- /dev/null +++ b/frida_mode/src/instrument.c @@ -0,0 +1,265 @@ +#include "frida-gum.h" +#include "config.h" +#include "debug.h" +#include "prefetch.h" +#include "ranges.h" +#include "unistd.h" + +extern uint8_t *__afl_area_ptr; +extern u32 __afl_map_size; + +uint64_t __thread previous_pc = 0; +GumAddress current_log_impl = GUM_ADDRESS(0); + +static gboolean tracing = false; +static gboolean optimize = false; +static gboolean strict = false; + +#if defined(__x86_64__) +static const guint8 afl_log_code[] = { + + 0x9c, /* pushfq */ + 0x50, /* push rax */ + 0x51, /* push rcx */ + 0x52, /* push rdx */ + + 0x48, 0x8d, 0x05, 0x27, + 0x00, 0x00, 0x00, /* lea rax, sym._afl_area_ptr_ptr */ + 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ + 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ + 0x48, 0x8d, 0x0d, 0x22, + 0x00, 0x00, 0x00, /* lea rcx, sym.previous_pc */ + 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ + 0x48, 0x8b, 0x12, /* mov rdx, qword [rdx] */ + 0x48, 0x31, 0xfa, /* xor rdx, rdi */ + 0xfe, 0x04, 0x10, /* inc byte [rax + rdx] */ + 0x48, 0xd1, 0xef, /* shr rdi, 1 */ + 0x48, 0x8b, 0x01, /* mov rax, qword [rcx] */ + 0x48, 0x89, 0x38, /* mov qword [rax], rdi */ + + 0x5a, /* pop rdx */ + 0x59, /* pop rcx */ + 0x58, /* pop rax */ + 0x9d, /* popfq */ + + 0xc3, /* ret */ + + /* Read-only data goes here: */ + /* uint8_t** afl_area_ptr_ptr */ + /* uint64_t* afl_prev_loc_ptr */ + +}; + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -GUM_RED_ZONE_SIZE); + gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + GUM_RED_ZONE_SIZE); + +} + +#elif defined(__aarch64__) +static const guint8 afl_log_code[] = { + + // __afl_area_ptr[current_pc ^ previous_pc]++; + // previous_pc = current_pc >> 1; + 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! + 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! + + // x0 = current_pc + 0xc1, 0x01, 0x00, 0x58, // ldr x1, #0x38, =&__afl_area_ptr + 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) + + 0xc2, 0x01, 0x00, 0x58, // ldr x2, #0x38, =&previous_pc + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) + + // __afl_area_ptr[current_pc ^ previous_pc]++; + 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 + 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] + 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 + 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] + + // previous_pc = current_pc >> 1; + 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 + 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc + 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] + + 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 + 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 + 0xC0, 0x03, 0x5F, 0xD6, // ret + + // &afl_area_ptr_ptr + // &afl_prev_loc_ptr + +}; + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumArm64Writer *cw = output->writer.arm64; + + if (current_log_impl == 0 || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, + current_log_impl) || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_arm64_writer_put_b_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_arm64_writer_put_label(cw, after_log_impl); + + } + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); + gum_arm64_writer_put_bl_imm(cw, current_log_impl); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); + +} + +#endif + +static void on_basic_block(GumCpuContext *context, gpointer user_data) { + + /* Avoid stack operations in potentially performance critical code */ + static char buffer[200]; + int len; + guint64 current_pc = (guint64)user_data; + if (tracing) { + + /* Avoid any functions which may cause an allocation since the target app + * may already be running inside malloc and it isn't designed to be + * re-entrant on a single thread */ + len = snprintf(buffer, sizeof(buffer), + "current_pc: 0x%016" G_GINT64_MODIFIER + "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", + current_pc, previous_pc); + + write(STDOUT_FILENO, buffer, len + 1); + + } + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + __afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data) { + + const cs_insn *instr; + gboolean begin = TRUE; + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (begin) { + + prefetch_write((void *)instr->address); + if (!strict || !range_is_excluded((void *)instr->address)) { + + if (optimize) { + + instrument_coverage_optimize(instr, output); + + } else { + + gum_stalker_iterator_put_callout(iterator, on_basic_block, + (gpointer)instr->address, NULL); + + } + + } + + begin = FALSE; + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +void instrument_init() { + + optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); + tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + strict = (getenv("AFL_FRIDA_INST_STRICT") != NULL); + +#if !defined(__x86_64__) && !defined(__aarch64__) + optimize = false; +#endif + + OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); + OKF("Instrumentation - strict [%c]", strict ? 'X' : ' '); + + if (tracing && optimize) { + + FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); + + } + + if (__afl_map_size != 0x10000) { + + FATAL("Bad map size: 0x%08x", __afl_map_size); + + } + +} + diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c new file mode 100644 index 00000000..ba05a80a --- /dev/null +++ b/frida_mode/src/interceptor.c @@ -0,0 +1,16 @@ +#include "frida-gum.h" +#include "debug.h" + +#include "interceptor.h" + +void intercept(void *address, gpointer replacement, gpointer user_data) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + gum_interceptor_begin_transaction(interceptor); + GumReplaceReturn ret = + gum_interceptor_replace(interceptor, address, replacement, user_data); + if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); } + gum_interceptor_end_transaction(interceptor); + +} + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c new file mode 100644 index 00000000..444c9583 --- /dev/null +++ b/frida_mode/src/main.c @@ -0,0 +1,149 @@ +#include +#include + +#ifdef __APPLE__ + #include + #include +#else + #include + #include +#endif + +#include "frida-gum.h" +#include "config.h" +#include "debug.h" + +#include "interceptor.h" +#include "instrument.h" +#include "prefetch.h" +#include "ranges.h" + +#ifdef __APPLE__ +extern mach_port_t mach_task_self(); +extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); +#else +extern int __libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)); +#endif + +typedef int *(*main_fn_t)(int argc, char **argv, char **envp); + +static main_fn_t main_fn = NULL; +static GumStalker * stalker = NULL; +static GumMemoryRange code_range = {0}; + +extern void __afl_manual_init(); +extern __thread uint64_t previous_pc; + +static int on_fork() { + + prefetch_read(stalker); + return fork(); + +} + +#ifdef __APPLE__ +static void on_main_os(int argc, char **argv, char **envp) { + +} + +#else +static void on_main_os(int argc, char **argv, char **envp) { + + /* Personality doesn't affect the current process, it only takes effect on + * evec */ + int persona = personality(ADDR_NO_RANDOMIZE); + if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); } + + GumInterceptor *interceptor = gum_interceptor_obtain(); + + gum_interceptor_begin_transaction(interceptor); + gum_interceptor_revert(interceptor, __libc_start_main); + gum_interceptor_end_transaction(interceptor); + gum_interceptor_flush(interceptor); + +} + +#endif + +static int *on_main(int argc, char **argv, char **envp) { + + on_main_os(argc, argv, envp); + + stalker = gum_stalker_new(); + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + + gum_stalker_set_trust_threshold(stalker, 0); + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + + instrument_init(); + prefetch_init(); + ranges_init(stalker); + + intercept(fork, on_fork, stalker); + + gum_stalker_follow_me(stalker, transformer, NULL); + gum_stalker_deactivate(stalker); + + __afl_manual_init(); + + /* Child here */ + previous_pc = 0; + prefetch_start(stalker); + main_fn(argc, argv, envp); + _exit(0); + +} + +#ifdef __APPLE__ +static void intercept_main() { + + mach_port_t task = mach_task_self(); + OKF("Task Id: %u", task); + GumAddress entry = gum_darwin_find_entrypoint(task); + OKF("Entry Point: 0x%016" G_GINT64_MODIFIER "x", entry); + void *main = GSIZE_TO_POINTER(entry); + main_fn = main; + intercept(main, on_main, NULL); + +} + +#else +static int on_libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)) { + + main_fn = main; + intercept(main, on_main, NULL); + return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, + stack_end); + +} + +static void intercept_main() { + + intercept(__libc_start_main, on_libc_start_main, NULL); + +} + +#endif + +__attribute__((constructor)) static void init() { + + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + FATAL("Failed to initialize embedded"); + + } + + intercept_main(); + +} + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c new file mode 100644 index 00000000..64633c1c --- /dev/null +++ b/frida_mode/src/prefetch.c @@ -0,0 +1,121 @@ +#include +#include +#include + +#include "frida-gum.h" +#include "prefetch.h" +#include "debug.h" + +#define TRUST 0 +#define PREFETCH_SIZE 65536 +#define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) + +typedef struct { + + size_t count; + void * entry[PREFETCH_ENTRIES]; + +} prefetch_data_t; + +static prefetch_data_t *prefetch_data = NULL; + +static int prefetch_shm_id = -1; + +/* + * We do this from the transformer since we need one anyway for coverage, this + * saves the need to use an event sink. + */ +void prefetch_write(void *addr) { + + /* Bail if we aren't initialized */ + if (prefetch_data == NULL) return; + + /* + * Our shared memory IPC is large enough for about 1000 entries, we can fine + * tune this if we need to. But if we have more new blocks that this in a + * single run then we ignore them and we'll pick them up next time. + */ + if (prefetch_data->count >= PREFETCH_ENTRIES) return; + + /* + * Write the block address to the SHM IPC and increment the number of entries. + */ + + prefetch_data->entry[prefetch_data->count] = addr; + prefetch_data->count++; + +} + +/* + * Read the IPC region one block at the time and prefetch it + */ +void prefetch_read(GumStalker *stalker) { + + if (prefetch_data == NULL) return; + + for (size_t i = 0; i < prefetch_data->count; i++) { + + void *addr = prefetch_data->entry[i]; + gum_stalker_prefetch(stalker, addr, 1); + + } + + /* + * Reset the entry count to indicate we have finished with it and it can be + * refilled by the child. + */ + prefetch_data->count = 0; + +} + +void prefetch_init() { + + g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); + gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); + + OKF("Instrumentation - prefetch [%c]", prefetch ? 'X' : ' '); + + if (!prefetch) { return; } + /* + * Make our shared memory, we can attach before we fork, just like AFL does + * with the coverage bitmap region and fork will take care of ensuring both + * the parent and child see the same consistent memory region. + */ + prefetch_shm_id = + shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600); + if (prefetch_shm_id < 0) { + + FATAL("prefetch_shm_id < 0 - errno: %d\n", errno); + + } + + prefetch_data = shmat(prefetch_shm_id, NULL, 0); + g_assert(prefetch_data != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) { + + FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); + + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(prefetch_data, '\0', sizeof(prefetch_data_t)); + +} + +__attribute__((noinline)) static void prefetch_activation() { + + asm volatile(""); + +} + +void prefetch_start(GumStalker *stalker) { + + gum_stalker_activate(stalker, prefetch_activation); + prefetch_activation(); + +} + diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c new file mode 100644 index 00000000..fc14710f --- /dev/null +++ b/frida_mode/src/ranges.c @@ -0,0 +1,395 @@ +// 0x123-0x321 +// module.so + +#include "ranges.h" +#include "debug.h" + +#define MAX_RANGES 20 + +typedef struct { + + gchar * suffix; + GumMemoryRange *range; + gboolean done; + +} convert_name_ctx_t; + +typedef struct { + + GumStalker *stalker; + GArray * array; + +} include_range_ctx_t; + +GArray * ranges = NULL; +gboolean exclude_ranges = false; + +static void convert_address_token(gchar *token, GumMemoryRange *range) { + + gchar **tokens; + int token_count; + tokens = g_strsplit(token, "-", 2); + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + if (token_count != 2) { + + FATAL("Invalid range (should have two addresses seperated by a '-'): %s\n", + token); + + } + + gchar *from_str = tokens[0]; + gchar *to_str = tokens[1]; + + if (!g_str_has_prefix(from_str, "0x")) { + + FATAL("Invalid range: %s - Start address should have 0x prefix: %s\n", + token, from_str); + + } + + if (!g_str_has_prefix(to_str, "0x")) { + + FATAL("Invalid range: %s - End address should have 0x prefix: %s\n", token, + to_str); + + } + + from_str = &from_str[2]; + to_str = &to_str[2]; + + for (char *c = from_str; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid range: %s - Start address not formed of hex digits: %s\n", + token, from_str); + + } + + } + + for (char *c = to_str; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid range: %s - End address not formed of hex digits: %s\n", + token, to_str); + + } + + } + + guint64 from = g_ascii_strtoull(from_str, NULL, 16); + if (from == 0) { + + FATAL("Invalid range: %s - Start failed hex conversion: %s\n", token, + from_str); + + } + + guint64 to = g_ascii_strtoull(to_str, NULL, 16); + if (to == 0) { + + FATAL("Invalid range: %s - End failed hex conversion: %s\n", token, to_str); + + } + + if (from >= to) { + + FATAL("Invalid range: %s - Start (0x%016" G_GINT64_MODIFIER + "x) must be less than end " + "(0x%016" G_GINT64_MODIFIER "x)\n", + token, from, to); + + } + + range->base_address = from; + range->size = to - from; + + g_strfreev(tokens); + +} + +static gboolean convert_name_token_for_module(const GumModuleDetails *details, + gpointer user_data) { + + convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data; + if (details->path == NULL) { return true; }; + + if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; }; + + OKF("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x %s", + ctx->suffix, details->range->base_address, + details->range->base_address + details->range->size, details->path); + + *ctx->range = *details->range; + ctx->done = true; + return false; + +} + +static void convert_name_token(gchar *token, GumMemoryRange *range) { + + gchar * suffix = g_strconcat("/", token, NULL); + convert_name_ctx_t ctx = {.suffix = suffix, .range = range, .done = false}; + + gum_process_enumerate_modules(convert_name_token_for_module, &ctx); + if (!ctx.done) { FATAL("Failed to resolve module: %s\n", token); } + g_free(suffix); + +} + +static void convert_token(gchar *token, GumMemoryRange *range) { + + if (g_strrstr(token, "-")) { + + convert_address_token(token, range); + + } else { + + convert_name_token(token, range); + + } + + OKF("Converted token: %s -> 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x\n", + token, range->base_address, range->base_address + range->size); + +} + +static gboolean include_ranges(const GumRangeDetails *details, + gpointer user_data) { + + include_range_ctx_t *ctx = (include_range_ctx_t *)user_data; + GArray * array = (GArray *)ctx->array; + GumAddress base = details->range->base_address; + GumAddress limit = details->range->base_address + details->range->size; + + OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + base, limit); + + for (int i = 0; i < array->len; i++) { + + GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i); + GumAddress range_base = range->base_address; + GumAddress range_limit = range->base_address + range->size; + + /* Before the region */ + if (range_limit < base) { continue; } + + /* After the region */ + if (range_base > limit) { + + GumMemoryRange exclude = {.base_address = base, .size = limit - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER + "x", + base, limit); + gum_stalker_exclude(ctx->stalker, &exclude); + return true; + + } + + /* Overlap the start of the region */ + if (range_base < base) { + + /* Range contains the region */ + if (range_limit > limit) { + + return true; + + } else { + + base = range_limit; + continue; + + } + + /* Overlap the end of the region */ + + } else { + + GumMemoryRange exclude = {.base_address = base, + .size = range_base - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER + "x", + base, range_base); + gum_stalker_exclude(ctx->stalker, &exclude); + /* Extend past the end of the region */ + if (range_limit >= limit) { + + return true; + + /* Contained within the region */ + + } else { + + base = range_limit; + continue; + + } + + } + + } + + GumMemoryRange exclude = {.base_address = base, .size = limit - base}; + OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", + base, limit); + gum_stalker_exclude(ctx->stalker, &exclude); + return true; + +} + +gint range_sort(gconstpointer a, gconstpointer b) { + + return ((GumMemoryRange *)a)->base_address - + ((GumMemoryRange *)b)->base_address; + +} + +static gboolean print_ranges(const GumRangeDetails *details, + gpointer user_data) { + + if (details->file == NULL) { + + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", + details->range->base_address, + details->range->base_address + details->range->size); + + } else { + + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER + "X %s(0x%016" G_GINT64_MODIFIER "x)", + details->range->base_address, + details->range->base_address + details->range->size, + details->file->path, details->file->offset); + + } + + return true; + +} + +void ranges_init(GumStalker *stalker) { + + char * showmaps; + char * include; + char * exclude; + char * list; + gchar ** tokens; + int token_count; + GumMemoryRange range; + + int i; + + showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); + include = getenv("AFL_FRIDA_INST_RANGES"); + exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES"); + + if (showmaps) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL); + + } + + if (include != NULL && exclude != NULL) { + + FATAL( + "Cannot specifify both AFL_FRIDA_INST_RANGES and " + "AFL_FRIDA_EXCLUDE_RANGES"); + + } + + if (include == NULL && exclude == NULL) { return; } + + list = include == NULL ? exclude : include; + exclude_ranges = include == NULL ? true : false; + + tokens = g_strsplit(list, ",", MAX_RANGES); + + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count); + + for (i = 0; i < token_count; i++) { + + convert_token(tokens[i], &range); + g_array_append_val(ranges, range); + + } + + g_array_sort(ranges, range_sort); + + /* Check for overlaps */ + for (i = 1; i < token_count; i++) { + + GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { + + FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + prev->base_address, prev_limit, curr->base_address, curr_limit); + + } + + } + + for (i = 0; i < token_count; i++) { + + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", + i, curr->base_address, curr_limit); + + } + + if (include == NULL) { + + for (i = 0; i < token_count; i++) { + + gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i)); + + } + + } else { + + include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); + + } + + g_strfreev(tokens); + +} + +gboolean range_is_excluded(gpointer address) { + + int i; + GumAddress test = GUM_ADDRESS(address); + + if (ranges == NULL) { return false; } + + for (i = 0; i < ranges->len; i++) { + + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + + if (test < curr->base_address) { return !exclude_ranges; } + + if (test < curr_limit) { return exclude_ranges; } + + } + + return !exclude_ranges; + +} + diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/testinstr.c new file mode 100644 index 00000000..2c3d5144 --- /dev/null +++ b/frida_mode/test/testinstr.c @@ -0,0 +1,105 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +TESTINSTR_SECTION void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/testinstr.py new file mode 100755 index 00000000..8f5fe886 --- /dev/null +++ b/frida_mode/test/testinstr.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, section, base): + with open(file, 'rb') as f: + for sect in ELFFile(f).iter_sections(): + if (sect.name == section): + start = base + sect.header['sh_offset'] + end = start + sect.header['sh_size'] + print ("0x%016x-0x%016x" % (start, end)) + return + + print ("Section '%s' not found in '%s'" % (section, file)) + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--section', dest='section', type=str, + help='elf section name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + process_file (args.file, args.section, args.base) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/include/envs.h b/include/envs.h index d7578045..1e383b0c 100644 --- a/include/envs.h +++ b/include/envs.h @@ -50,6 +50,13 @@ static char *afl_environment_variables[] = { "AFL_EXIT_WHEN_DONE", "AFL_FAST_CAL", "AFL_FORCE_UI", + "AFL_FRIDA_DEBUG_MAPS", + "AFL_FRIDA_EXCLUDE_RANGES", + "AFL_FRIDA_INST_NO_OPTIMIZE", + "AFL_FRIDA_INST_NO_PREFETCH", + "AFL_FRIDA_INST_RANGES", + "AFL_FRIDA_INST_STRICT", + "AFL_FRIDA_INST_TRACE", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", diff --git a/include/forkserver.h b/include/forkserver.h index ac027f81..4709f6a5 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,6 +77,8 @@ typedef struct afl_forkserver { bool qemu_mode; /* if running in qemu mode or not */ + bool frida_mode; /* if running in frida mode or not */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index e106cd31..6ff119ac 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -83,6 +83,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ static u8 *target_path; +static u8 frida_mode; static u8 qemu_mode; static u32 map_size = MAP_SIZE; @@ -717,9 +718,11 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(void) { +static void set_up_environment(char **argv) { - u8 *x; + u8 * x; + char *afl_preload; + char *frida_afl_preload = NULL; dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -824,6 +827,26 @@ static void set_up_environment(void) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -831,8 +854,18 @@ static void set_up_environment(void) { } + } else if (frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -872,6 +905,7 @@ static void usage(u8 *argv0) { " -f file - input file read by the tested program (stdin)\n" " -t msec - timeout for each run (%u ms)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -914,7 +948,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:f:m:t:eQUWh")) > 0) { + while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) { switch (opt) { @@ -1008,6 +1042,14 @@ int main(int argc, char **argv_orig, char **envp) { break; + case 'O': /* FRIDA mode */ + + if (frida_mode) { FATAL("Multiple -O options not supported"); } + + frida_mode = 1; + + break; + case 'Q': if (qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1062,7 +1104,7 @@ int main(int argc, char **argv_orig, char **envp) { atexit(at_exit_handler); setup_signal_handlers(); - set_up_environment(); + set_up_environment(argv); target_path = find_binary(argv[optind]); detect_file_args(argv + optind, prog_in, &use_stdin); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 70a49a6b..cb0190a0 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2692,7 +2692,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { #endif /* ^!__APPLE__ */ - if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && + if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->non_instrumented_mode && !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { @@ -2720,7 +2720,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if ((afl->fsrv.qemu_mode) && + if ((afl->fsrv.qemu_mode || afl->fsrv.frida_mode) && memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST @@ -2757,7 +2757,8 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { + if (afl->fsrv.frida_mode || + memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { OKF(cPIN "Deferred forkserver binary detected."); setenv(DEFER_ENV_VAR, "1", 1); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index d70ffd31..34e9d420 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -109,6 +109,7 @@ static void usage(u8 *argv0, int more_help) { "maximum.\n" " -m megs - memory limit for child process (%u MB, 0 = no limit " "[default])\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -320,6 +321,8 @@ int main(int argc, char **argv_orig, char **envp) { u8 *extras_dir[4]; u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0 /*, have_p = 0*/; + char * afl_preload; + char * frida_afl_preload = NULL; char **use_argv; struct timeval tv; @@ -363,7 +366,7 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { + "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { switch (opt) { @@ -755,6 +758,18 @@ int main(int argc, char **argv_orig, char **envp) { afl->use_banner = optarg; break; + case 'O': /* FRIDA mode */ + + if (afl->fsrv.frida_mode) { + + FATAL("Multiple -O options not supported"); + + } + + afl->fsrv.frida_mode = 1; + + break; + case 'Q': /* QEMU mode */ if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1085,6 +1100,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->non_instrumented_mode) { if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); } + if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); } if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); } if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); } @@ -1289,6 +1305,26 @@ int main(int argc, char **argv_orig, char **envp) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (afl->fsrv.frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -1296,6 +1332,14 @@ int main(int argc, char **argv_orig, char **envp) { } + } else if (afl->fsrv.frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } if (getenv("AFL_LD_PRELOAD")) { @@ -1479,7 +1523,8 @@ int main(int argc, char **argv_orig, char **envp) { } - if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) { + if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && + !afl->non_instrumented_mode) { check_binary(afl, afl->cmplog_binary); @@ -1513,7 +1558,8 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->unicorn_mode) { + if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || + afl->fsrv.frida_mode || afl->unicorn_mode) { map_size = afl->fsrv.map_size = MAP_SIZE; afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size); @@ -2074,6 +2120,8 @@ stop_fuzzing: } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + fclose(afl->fsrv.plot_file); destroy_queue(afl); destroy_extras(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 558665a2..aea90b3b 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -555,8 +555,10 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(afl_forkserver_t *fsrv) { +static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { + char *afl_preload; + char *frida_afl_preload = NULL; setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -600,6 +602,26 @@ static void set_up_environment(afl_forkserver_t *fsrv) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (fsrv->frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -607,8 +629,18 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + } else if (fsrv->frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -655,6 +687,7 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -t msec - timeout for each run (none)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine mode)\n" @@ -723,7 +756,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrsh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { @@ -857,6 +890,14 @@ int main(int argc, char **argv_orig, char **envp) { at_file = optarg; break; + case 'O': /* FRIDA mode */ + + if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } + + fsrv->frida_mode = 1; + + break; + case 'Q': if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -943,7 +984,7 @@ int main(int argc, char **argv_orig, char **envp) { shm.cmplog_mode = 0; setup_signal_handlers(); - set_up_environment(fsrv); + set_up_environment(fsrv, argv); fsrv->target_path = find_binary(argv[optind]); fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index fc974262..68e61109 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -640,9 +640,11 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(afl_forkserver_t *fsrv) { +static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { - u8 *x; + u8 * x; + char *afl_preload; + char *frida_afl_preload = NULL; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -755,6 +757,26 @@ static void set_up_environment(afl_forkserver_t *fsrv) { /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + } else if (fsrv->frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } else { setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); @@ -762,8 +784,18 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + } else if (fsrv->frida_mode) { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); + ck_free(frida_binary); + } + if (frida_afl_preload) { ck_free(frida_afl_preload); } + } /* Setup signal handlers, duh. */ @@ -804,6 +836,7 @@ static void usage(u8 *argv0) { " -f file - input file read by the tested program (stdin)\n" " -t msec - timeout for each run (%u ms)\n" " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " @@ -859,7 +892,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeOQUWHh")) > 0) { switch (opt) { @@ -971,6 +1004,14 @@ int main(int argc, char **argv_orig, char **envp) { break; + case 'O': /* FRIDA mode */ + + if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } + + fsrv->frida_mode = 1; + + break; + case 'Q': if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } @@ -1054,7 +1095,7 @@ int main(int argc, char **argv_orig, char **envp) { atexit(at_exit_handler); setup_signal_handlers(); - set_up_environment(fsrv); + set_up_environment(fsrv, argv); fsrv->target_path = find_binary(argv[optind]); fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); -- cgit 1.4.1 From d319b4a3819052de5bf576c560da6e4687c31de9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 20:02:58 +0100 Subject: support libraries for find_afl_binary --- src/afl-common.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/afl-common.c b/src/afl-common.c index 1f9839a2..087aa113 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -282,12 +282,19 @@ u8 *find_binary(u8 *fname) { u8 *find_afl_binary(u8 *own_loc, u8 *fname) { - u8 *afl_path = NULL, *target_path, *own_copy; + u8 *afl_path = NULL, *target_path, *own_copy, *tmp; + int perm = X_OK; + + if ((tmp = strrchr(fname, '.'))) { + + if (!strcasecmp(tmp, ".so") || !strcasecmp(tmp, ".dylib")) { perm = R_OK; } + + } if ((afl_path = getenv("AFL_PATH"))) { target_path = alloc_printf("%s/%s", afl_path, fname); - if (!access(target_path, X_OK)) { + if (!access(target_path, perm)) { return target_path; @@ -311,7 +318,7 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { target_path = alloc_printf("%s/%s", own_copy, fname); ck_free(own_copy); - if (!access(target_path, X_OK)) { + if (!access(target_path, perm)) { return target_path; @@ -330,7 +337,7 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { } target_path = alloc_printf("%s/%s", BIN_PATH, fname); - if (!access(target_path, X_OK)) { + if (!access(target_path, perm)) { return target_path; @@ -340,7 +347,15 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { } - return find_binary(fname); + if (perm == X_OK) { + + return find_binary(fname); + + } else { + + FATAL("Library '%s' not found", fname); + + } } -- cgit 1.4.1 From ab394836a9fe3faadb9d1af3a7d377bbcf5b5eee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 08:40:33 +0100 Subject: remove warnings --- include/afl-fuzz.h | 3 ++- include/config.h | 5 +++-- include/forkserver.h | 16 +++++++++------- src/afl-forkserver.c | 4 ++++ src/afl-fuzz.c | 13 +++++++++---- src/afl-showmap.c | 1 - 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 691ba148..046b0177 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -390,7 +390,8 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries, *afl_kill_signal, *afl_target_env, *afl_persistent_record; + *afl_testcache_entries, *afl_kill_signal, *afl_target_env, + *afl_persistent_record; } afl_env_vars_t; diff --git a/include/config.h b/include/config.h index 4691624a..75f363f7 100644 --- a/include/config.h +++ b/include/config.h @@ -77,8 +77,9 @@ /* If a persistent target keeps state and found crashes are not reproducable then enable this option and set the AFL_PERSISTENT_RECORD env variable - to a number. These number of testcases prior the crash will be kept and - also written to the crash/ directory */ + to a number. These number of testcases prior and including the crash case + will be kept and written to the crash/ directory as RECORD:... files. + Note that every crash will be written, not only unique ones! */ //#define AFL_PERSISTENT_RECORD diff --git a/include/forkserver.h b/include/forkserver.h index c894ad80..808f6bd2 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -95,13 +95,15 @@ typedef struct afl_forkserver { char *cmplog_binary; /* the name of the cmplog binary */ /* persistent mode replay functionality */ - u32 persistent_record; /* persistent replay setting */ - u32 persistent_record_idx; /* persistent replay cache ptr */ - u32 persistent_record_cnt; /* persistent replay counter */ - u8 * persistent_record_dir; - u8 ** persistent_record_data; - u32 * persistent_record_len; - s32 persistent_record_pid; + u32 persistent_record; /* persistent replay setting */ +#ifdef AFL_PERSISTENT_RECORD + u32 persistent_record_idx; /* persistent replay cache ptr */ + u32 persistent_record_cnt; /* persistent replay counter */ + u8 * persistent_record_dir; + u8 **persistent_record_data; + u32 *persistent_record_len; + s32 persistent_record_pid; +#endif /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 979d7e9e..0037d2d5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -380,6 +380,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } } + #endif if (fsrv->use_fauxsrv) { @@ -1073,6 +1074,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { } } + #endif if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { @@ -1206,6 +1208,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, fsrv->persistent_record_len[idx] = val; } + #endif if (fsrv->child_pid <= 0) { @@ -1336,6 +1339,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, ++fsrv->persistent_record_cnt; } + #endif /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f89c1938..23343ade 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1034,7 +1034,7 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->afl_env.afl_persistent_record)) { -#ifdef AFL_PERSISTENT_RECORD + #ifdef AFL_PERSISTENT_RECORD afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); @@ -1046,11 +1046,13 @@ int main(int argc, char **argv_orig, char **envp) { } -#else + #else - FATAL("afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in config.h!"); + FATAL( + "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in " + "config.h!"); -#endif + #endif } @@ -1520,6 +1522,7 @@ int main(int argc, char **argv_orig, char **envp) { check_binary(afl, argv[optind]); + #ifdef AFL_PERSISTENT_RECORD if (unlikely(afl->fsrv.persistent_record)) { if (!getenv(PERSIST_ENV_VAR)) { @@ -1534,6 +1537,8 @@ int main(int argc, char **argv_orig, char **envp) { } + #endif + if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); } afl->start_time = get_cur_time(); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 558665a2..bedf7806 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -955,7 +955,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { /* If we don't have a file name chosen yet, use a safe default. */ -- cgit 1.4.1 From 90e7543038350fab1496b474c5aabd0b89644bad Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 08:54:47 +0100 Subject: update dynamic list --- README.md | 2 +- dynamic_list.txt | 1 + src/afl-fuzz-state.c | 2 +- src/afl-fuzz.c | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 084971f3..2de35d11 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ sudo apt-get install -y build-essential python3-dev automake git flex bison libg # try to install llvm 11 and install the distro default if that fails sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev -git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus +git clone https://github.com/AFLplusplus/AFLplusplus cd AFLplusplus make distrib sudo make install diff --git a/dynamic_list.txt b/dynamic_list.txt index f0e54d92..d1905d43 100644 --- a/dynamic_list.txt +++ b/dynamic_list.txt @@ -21,6 +21,7 @@ "__afl_coverage_interesting"; "__afl_fuzz_len"; "__afl_fuzz_ptr"; + "__afl_sharedmem_fuzzing"; "__sanitizer_cov_trace_pc_guard"; "__sanitizer_cov_trace_pc_guard_init"; "__cmplog_ins_hook1"; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 10a0b869..f65ff1bb 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -102,7 +102,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; - afl->cmplog_lvl = 1; + afl->cmplog_lvl = 2; #ifndef NO_SPLICING afl->use_splicing = 1; #endif diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 23343ade..75f97719 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -126,7 +126,7 @@ static void usage(u8 *argv0, int more_help) { "it.\n" " if using QEMU, just use -c 0.\n" " -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n" - " 1=small files (default), 2=larger files, 3=all " + " 1=small files, 2=larger files (default), 3=all " "files,\n" " A=arithmetic solving, T=transformational solving.\n\n" "Fuzzing behavior settings:\n" -- cgit 1.4.1 From 447d232caf9fcd9e6e40c24d17000ff9b98ab693 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 08:55:41 +0100 Subject: update changelog --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index caa06ffd..87ac858e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - default cmplog level (-l) is now 2, better efficiency. ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From c89264205779635ec43f2913a94fa3ae5e6a5186 Mon Sep 17 00:00:00 2001 From: Jiangen Jiao Date: Thu, 25 Mar 2021 12:29:27 +0800 Subject: android: support host and target 32bit build --- Android.bp | 144 ++++++++++++++++++++- custom_mutators/Android.bp | 6 + .../libprotobuf-mutator-example/Android.bp | 6 + include/android-ashmem.h | 29 ++--- src/afl-cc.c | 6 +- 5 files changed, 168 insertions(+), 23 deletions(-) diff --git a/Android.bp b/Android.bp index ee076d1e..64794e19 100644 --- a/Android.bp +++ b/Android.bp @@ -1,8 +1,5 @@ cc_defaults { name: "afl-defaults", - sanitize: { - never: true, - }, local_include_dirs: [ "include", @@ -23,18 +20,45 @@ cc_defaults { "-DBIN_PATH=\"out/host/linux-x86/bin\"", "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"", "-D__USE_GNU", - "-D__aarch64__", "-DDEBUG_BUILD", "-U_FORTIFY_SOURCE", "-ggdb3", "-g", "-O0", "-fno-omit-frame-pointer", + "-fPIC", ], + + target: { + android_arm64: { + cflags: [ + "-D__aarch64__", + "-D__ANDROID__", + ], + }, + android_arm: { + cflags: [ + "-D__ANDROID__", + ], + }, + android_x86_64: { + cflags: [ + "-D__ANDROID__", + ], + }, + android_x86: { + cflags: [ + "-D__ANDROID__", + ], + }, + }, } cc_binary { name: "afl-fuzz", + sanitize: { + never: true, + }, host_supported: true, compile_multilib: "64", @@ -128,7 +152,6 @@ cc_binary_host { ], cflags: [ - "-D__ANDROID__", "-DAFL_PATH=\"out/host/linux-x86/lib64\"", "-DAFL_CLANG_FLTO=\"-flto=full\"", "-DUSE_BINDIR=1", @@ -199,6 +222,7 @@ cc_library_headers { export_include_dirs: [ "include", + "instrumentation", ], } @@ -268,6 +292,116 @@ cc_binary { ], } +cc_binary { + name: "afl-fuzz-32", + sanitize: { + never: true, + }, + host_supported: true, + compile_multilib: "32", + + defaults: [ + "afl-defaults", + ], + + srcs: [ + "src/afl-fuzz*.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", + ], +} + +cc_binary_host { + name: "afl-cc-32", + compile_multilib: "32", + static_executable: true, + + defaults: [ + "afl-defaults", + ], + + cflags: [ + "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + "-DAFL_CLANG_FLTO=\"-flto=full\"", + "-DUSE_BINDIR=1", + "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"", + "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"", + "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"", + "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"", + "-DLLVM_LTO=1", + "-DLLVM_MAJOR=11", + "-DLLVM_MINOR=2", + ], + + srcs: [ + "src/afl-cc.c", + "src/afl-common.c", + ], + + symlinks: [ + "afl-clang-fast-32", + "afl-clang-fast++-32", + ], +} + +cc_library_static { + name: "afl-llvm-rt-32", + compile_multilib: "32", + vendor_available: true, + host_supported: true, + recovery_available: true, + sdk_version: "9", + + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", + ], + + defaults: [ + "afl-defaults", + ], + + srcs: [ + "instrumentation/afl-compiler-rt.o.c", + ], +} + +cc_prebuilt_library_static { + name: "libfrida-gum-32", + compile_multilib: "32", + strip: { + none: true, + }, + + srcs: [ + "utils/afl_frida/android/arm/libfrida-gum.a", + ], + + export_include_dirs: [ + "utils/afl_frida/android/arm", + ], +} + subdirs = [ "custom_mutators", ] diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp index 89abc3e9..5c7e06e3 100644 --- a/custom_mutators/Android.bp +++ b/custom_mutators/Android.bp @@ -10,6 +10,8 @@ cc_library_shared { "-fPIC", "-fpermissive", "-std=c++11", + "-Wno-unused-parameter", + "-Wno-unused-variable", ], srcs: [ @@ -77,6 +79,8 @@ cc_library_shared { "-O0", "-funroll-loops", "-fPIC", + "-Wno-unused-parameter", + "-Wno-unused-function", ], srcs: [ @@ -99,6 +103,8 @@ cc_library_shared { "-O0", "-funroll-loops", "-fPIC", + "-Wno-unused-parameter", + "-Wno-pointer-sign", ], srcs: [ diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp index 01f1c23e..4f579735 100644 --- a/custom_mutators/libprotobuf-mutator-example/Android.bp +++ b/custom_mutators/libprotobuf-mutator-example/Android.bp @@ -8,6 +8,7 @@ cc_library_shared { "-O0", "-fPIC", "-Wall", + "-Wno-unused-parameter", ], srcs: [ @@ -29,4 +30,9 @@ cc_binary { srcs: [ "vuln.c", ], + + cflags: [ + "-Wno-unused-result", + "-Wno-unused-parameter", + ], } diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 91699b27..44fe556a 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -2,32 +2,31 @@ #ifndef _ANDROID_ASHMEM_H #define _ANDROID_ASHMEM_H + #define _GNU_SOURCE + #include + #include #include #include #include #include - - #if __ANDROID_API__ >= 26 - #define shmat bionic_shmat - #define shmctl bionic_shmctl - #define shmdt bionic_shmdt - #define shmget bionic_shmget - #endif #include - #undef shmat - #undef shmctl - #undef shmdt - #undef shmget #include - #define ASHMEM_DEVICE "/dev/ashmem" +int shmdt(const void* address) { +#if defined(SYS_shmdt) + return syscall(SYS_shmdt, address); +#else + return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); +#endif +} + int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); @@ -78,6 +77,6 @@ void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { } - #endif /* !_ANDROID_ASHMEM_H */ -#endif /* !__ANDROID__ */ + #endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/src/afl-cc.c b/src/afl-cc.c index 80fc0742..2ee840d7 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -588,9 +588,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD) { #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) - #ifdef __ANDROID__ + #if defined __ANDROID__ || ANDROID cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; - instrument_mode != INSTRUMENT_LLVMNATIVE; + instrument_mode = INSTRUMENT_LLVMNATIVE; #else if (have_instr_list) { @@ -2023,7 +2023,7 @@ int main(int argc, char **argv, char **envp) { if (!be_quiet && cmplog_mode) printf("CmpLog mode by \n"); -#ifndef __ANDROID__ +#if !defined(__ANDROID__) && !defined(ANDROID) ptr = find_object("afl-compiler-rt.o", argv[0]); if (!ptr) { -- cgit 1.4.1 From 0029c1a83ef03825c2d19c73151189f159458496 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 15:35:06 +0100 Subject: remove InsTrim --- GNUmakefile.llvm | 5 +- README.md | 1 - docs/Changelog.md | 2 + docs/PATCHES.md | 43 --- docs/env_variables.md | 27 +- docs/perf_tips.md | 3 - instrumentation/LLVMInsTrim.so.cc | 599 ------------------------------------- instrumentation/MarkNodes.cc | 481 ----------------------------- instrumentation/MarkNodes.h | 12 - instrumentation/README.instrim.md | 30 -- instrumentation/README.llvm.md | 17 +- instrumentation/README.snapshot.md | 2 + src/afl-cc.c | 50 +--- src/afl-ld-lto.c | 20 +- test/test-llvm.sh | 21 -- 15 files changed, 29 insertions(+), 1284 deletions(-) delete mode 100644 docs/PATCHES.md delete mode 100644 instrumentation/LLVMInsTrim.so.cc delete mode 100644 instrumentation/MarkNodes.cc delete mode 100644 instrumentation/MarkNodes.h delete mode 100644 instrumentation/README.instrim.md diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 111a847d..4b5ac520 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -304,7 +304,7 @@ ifeq "$(TEST_MMAP)" "1" endif PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o -PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so +PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so # If prerequisites are not given, warn, do not build anything, and exit with code 0 ifeq "$(LLVMVER)" "" @@ -382,9 +382,6 @@ endif instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h $(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ -./libLLVMInsTrim.so: instrumentation/LLVMInsTrim.so.cc instrumentation/MarkNodes.cc instrumentation/afl-llvm-common.o | test_deps - -$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< instrumentation/MarkNodes.cc -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o - ./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ifeq "$(LLVM_MIN_4_0_1)" "0" $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER)) diff --git a/README.md b/README.md index 2de35d11..3ba05777 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,6 @@ There are many more options and modes available however these are most of the time less effective. See: * [instrumentation/README.ctx.md](instrumentation/README.ctx.md) * [instrumentation/README.ngram.md](instrumentation/README.ngram.md) - * [instrumentation/README.instrim.md](instrumentation/README.instrim.md) afl++ performs "never zero" counting in its bitmap. You can read more about this here: diff --git a/docs/Changelog.md b/docs/Changelog.md index 87ac858e..730791da 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,8 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - afl-cc: + - Removed InsTrim instrumentation as it is not as good as PCGUARD ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/PATCHES.md b/docs/PATCHES.md deleted file mode 100644 index b2cff43a..00000000 --- a/docs/PATCHES.md +++ /dev/null @@ -1,43 +0,0 @@ -# Applied Patches - -The following patches from https://github.com/vanhauser-thc/afl-patches -have been installed or not installed: - - -## INSTALLED -``` -afl-llvm-fix.diff by kcwu(at)csie(dot)org -afl-sort-all_uniq-fix.diff by legarrec(dot)vincent(at)gmail(dot)com -laf-intel.diff by heiko(dot)eissfeldt(at)hexco(dot)de -afl-llvm-optimize.diff by mh(at)mh-sec(dot)de -afl-fuzz-tmpdir.diff by mh(at)mh-sec(dot)de -afl-fuzz-79x24.diff by heiko(dot)eissfeldt(at)hexco(dot)de -afl-fuzz-fileextensionopt.diff tbd -afl-as-AFL_INST_RATIO.diff by legarrec(dot)vincent(at)gmail(dot)com -afl-qemu-ppc64.diff by william(dot)barsse(at)airbus(dot)com -afl-qemu-optimize-entrypoint.diff by mh(at)mh-sec(dot)de -afl-qemu-speed.diff by abiondo on github -afl-qemu-optimize-map.diff by mh(at)mh-sec(dot)de -``` - -+ llvm_mode ngram prev_loc coverage (github.com/adrianherrera/afl-ngram-pass) -+ Custom mutator (native library) (by kyakdan) -+ unicorn_mode (modernized and updated by domenukk) -+ instrim (https://github.com/csienslab/instrim) was integrated -+ MOpt (github.com/puppet-meteor/MOpt-AFL) was imported -+ AFLfast additions (github.com/mboehme/aflfast) were incorporated. -+ Qemu 3.1 upgrade with enhancement patches (github.com/andreafioraldi/afl) -+ Python mutator modules support (github.com/choller/afl) -+ Instrument file list in LLVM mode (github.com/choller/afl) -+ forkserver patch for afl-tmin (github.com/nccgroup/TriforceAFL) - - -## NOT INSTALLED - -``` -afl-fuzz-context_sensitive.diff - changes too much of the behaviour -afl-tmpfs.diff - same as afl-fuzz-tmpdir.diff but more complex -afl-cmin-reduce-dataset.diff - unsure of the impact -afl-llvm-fix2.diff - not needed with the other patches -``` - diff --git a/docs/env_variables.md b/docs/env_variables.md index 6d3d1714..572fad01 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -130,16 +130,15 @@ Then there are a few specific features that are only available in instrumentatio PCGUARD - our own pcgard based instrumentation (default) NATIVE - clang's original pcguard based instrumentation CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default) - CFG - InsTrim instrumentation (see below) LTO - LTO instrumentation (see below) CTX - context sensitive instrumentation (see below) NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) GCC - outdated gcc instrumentation CLANG - outdated clang instrumentation - In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or - NGRAM, seperate the options with a comma "," then, e.g.: - `AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4` - Not that this is a good idea to use both CTX and NGRAM :) + In CLASSIC you can also specify CTX and/or NGRAM, seperate the options + with a comma "," then, e.g.: + `AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4` + Note that this is actually not a good idea to use both CTX and NGRAM :) ### LTO @@ -173,24 +172,6 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information. -### INSTRIM - - This feature increases the speed by ~15% without any disadvantages to the - classic instrumentation. - - Note that there is also an LTO version (if you have llvm 11 or higher) - - that is the best instrumentation we have. Use `afl-clang-lto` to activate. - The InsTrim LTO version additionally has all the options and features of - LTO (see above). - - - Setting `AFL_LLVM_INSTRIM` or `AFL_LLVM_INSTRUMENT=CFG` activates this mode - - - Setting `AFL_LLVM_INSTRIM_LOOPHEAD=1` expands on INSTRIM to optimize loops. - afl-fuzz will only be able to see the path the loop took, but not how - many times it was called (unless it is a complex loop). - - See [instrumentation/README.instrim.md](../instrumentation/README.instrim.md) - ### NGRAM - Setting `AFL_LLVM_NGRAM_SIZE` or `AFL_LLVM_INSTRUMENT=NGRAM-{value}` diff --git a/docs/perf_tips.md b/docs/perf_tips.md index fbcb4d8d..c5968206 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -69,9 +69,6 @@ If you are only interested in specific parts of the code being fuzzed, you can instrument_files the files that are actually relevant. This improves the speed and accuracy of afl. See instrumentation/README.instrument_list.md -Also use the InsTrim mode on larger binaries, this improves performance and -coverage a lot. - ## 4. Profile and optimize the binary Check for any parameters or settings that obviously improve performance. For diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc deleted file mode 100644 index 62de6ec5..00000000 --- a/instrumentation/LLVMInsTrim.so.cc +++ /dev/null @@ -1,599 +0,0 @@ -#include -#include -#include -#include - -#include "llvm/Config/llvm-config.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 -typedef long double max_align_t; -#endif - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) - #include "llvm/IR/CFG.h" - #include "llvm/IR/Dominators.h" - #include "llvm/IR/DebugInfo.h" -#else - #include "llvm/Support/CFG.h" - #include "llvm/Analysis/Dominators.h" - #include "llvm/DebugInfo.h" -#endif -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/IR/BasicBlock.h" -#include -#include -#include -#include -#include - -#include "MarkNodes.h" -#include "afl-llvm-common.h" -#include "llvm-alternative-coverage.h" - -#include "config.h" -#include "debug.h" - -using namespace llvm; - -static cl::opt MarkSetOpt("markset", cl::desc("MarkSet"), - cl::init(false)); -static cl::opt LoopHeadOpt("loophead", cl::desc("LoopHead"), - cl::init(false)); - -namespace { - -struct InsTrim : public ModulePass { - - protected: - uint32_t function_minimum_size = 1; - char * skip_nozero = NULL; - - private: - std::mt19937 generator; - int total_instr = 0; - - unsigned int genLabel() { - - return generator() & (MAP_SIZE - 1); - - } - - public: - static char ID; - - InsTrim() : ModulePass(ID), generator(0) { - - initInstrumentList(); - - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - - AU.addRequired(); - - } - -#if LLVM_VERSION_MAJOR < 4 - const char * -#else - StringRef -#endif - getPassName() const override { - - return "InstTrim Instrumentation"; - - } - -#if LLVM_VERSION_MAJOR > 4 || \ - (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) - #define AFL_HAVE_VECTOR_INTRINSICS 1 -#endif - - bool runOnModule(Module &M) override { - - setvbuf(stdout, NULL, _IONBF, 0); - - if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { - - SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n"); - - } else - - be_quiet = 1; - - if (getenv("AFL_DEBUG") != NULL) debug = 1; - - LLVMContext &C = M.getContext(); - - IntegerType *Int8Ty = IntegerType::getInt8Ty(C); - IntegerType *Int32Ty = IntegerType::getInt32Ty(C); - -#if LLVM_VERSION_MAJOR < 9 - char *neverZero_counters_str; - if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL) - if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n"); -#endif - skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); - - if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL || - getenv("LOOPHEAD") != NULL) { - - LoopHeadOpt = true; - - } - - unsigned int PrevLocSize = 0; - char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); - if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); - char *caller_str = getenv("AFL_LLVM_CALLER"); - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - unsigned int ngram_size = 0; - /* Decide previous location vector size (must be a power of two) */ - VectorType *PrevLocTy = NULL; - - if (ngram_size_str) - if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 || - ngram_size > NGRAM_SIZE_MAX) - FATAL( - "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX " - "(%u))", - NGRAM_SIZE_MAX); - - if (ngram_size) - PrevLocSize = ngram_size - 1; - else -#else - if (ngram_size_str) - #ifdef LLVM_VERSION_STRING - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version %s!", - LLVM_VERSION_STRING); - #else - #ifndef LLVM_VERSION_PATCH - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version " - "%d.%d.%d!", - LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0); - #else - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version " - "%d.%d.%d!", - LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH); - #endif - #endif -#endif - PrevLocSize = 1; - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - // IntegerType *Int64Ty = IntegerType::getInt64Ty(C); - int PrevLocVecSize = PowerOf2Ceil(PrevLocSize); - IntegerType *IntLocTy = - IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT); - if (ngram_size) - PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize - #if LLVM_VERSION_MAJOR >= 12 - , - false - #endif - ); -#endif - - /* Get globals for the SHM region and the previous location. Note that - __afl_prev_loc is thread-local. */ - - GlobalVariable *AFLMapPtr = - new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, - GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); - GlobalVariable *AFLPrevLoc; - GlobalVariable *AFLContext = NULL; - LoadInst * PrevCaller = NULL; // for CALLER sensitive coverage - - if (caller_str) -#if defined(__ANDROID__) || defined(__HAIKU__) - AFLContext = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); -#else - AFLContext = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", - 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); -#endif - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) - #if defined(__ANDROID__) || defined(__HAIKU__) - AFLPrevLoc = new GlobalVariable( - M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, - /* Initializer */ nullptr, "__afl_prev_loc"); - #else - AFLPrevLoc = new GlobalVariable( - M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, - /* Initializer */ nullptr, "__afl_prev_loc", - /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel, - /* AddressSpace */ 0, /* IsExternallyInitialized */ false); - #endif - else -#endif -#if defined(__ANDROID__) || defined(__HAIKU__) - AFLPrevLoc = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); -#else - AFLPrevLoc = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0, - GlobalVariable::GeneralDynamicTLSModel, 0, false); -#endif - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - /* Create the vector shuffle mask for updating the previous block history. - Note that the first element of the vector will store cur_loc, so just set - it to undef to allow the optimizer to do its thing. */ - - SmallVector PrevLocShuffle = {UndefValue::get(Int32Ty)}; - - for (unsigned I = 0; I < PrevLocSize - 1; ++I) - PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I)); - - for (int I = PrevLocSize; I < PrevLocVecSize; ++I) - PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize)); - - Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle); -#endif - - // this is our default - MarkSetOpt = true; - - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); - ConstantInt *One = ConstantInt::get(Int8Ty, 1); - - u64 total_rs = 0; - u64 total_hs = 0; - - scanForDangerousFunctions(&M); - - for (Function &F : M) { - - if (debug) { - - uint32_t bb_cnt = 0; - - for (auto &BB : F) - if (BB.size() > 0) ++bb_cnt; - DEBUGF("Function %s size %zu %u\n", F.getName().str().c_str(), F.size(), - bb_cnt); - - } - - if (!isInInstrumentList(&F)) continue; - - // if the function below our minimum size skip it (1 or 2) - if (F.size() < function_minimum_size) { continue; } - - std::unordered_set MS; - if (!MarkSetOpt) { - - for (auto &BB : F) { - - MS.insert(&BB); - - } - - total_rs += F.size(); - - } else { - - auto Result = markNodes(&F); - auto RS = Result.first; - auto HS = Result.second; - - MS.insert(RS.begin(), RS.end()); - if (!LoopHeadOpt) { - - MS.insert(HS.begin(), HS.end()); - total_rs += MS.size(); - - } else { - - DenseSet> EdgeSet; - DominatorTreeWrapperPass * DTWP = - &getAnalysis(F); - auto DT = &DTWP->getDomTree(); - - total_rs += RS.size(); - total_hs += HS.size(); - - for (BasicBlock *BB : HS) { - - bool Inserted = false; - for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) { - - auto Edge = BasicBlockEdge(*BI, BB); - if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) { - - EdgeSet.insert({*BI, BB}); - Inserted = true; - break; - - } - - } - - if (!Inserted) { - - MS.insert(BB); - total_rs += 1; - total_hs -= 1; - - } - - } - - for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) { - - auto PredBB = I->first; - auto SuccBB = I->second; - auto NewBB = - SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT, nullptr, -#if LLVM_VERSION_MAJOR >= 8 - nullptr, -#endif - false); - MS.insert(NewBB); - - } - - } - - for (BasicBlock &BB : F) { - - if (MS.find(&BB) == MS.end()) { continue; } - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) { - - LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); - PrevLoc->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - Value *ShuffledPrevLoc = IRB.CreateShuffleVector( - PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask); - Value *UpdatedPrevLoc = IRB.CreateInsertElement( - ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()), - (uint64_t)0); - - IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc) - ->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } else - -#endif - { - - IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc); - - } - - } - - } - - int has_calls = 0; - for (BasicBlock &BB : F) { - - auto PI = pred_begin(&BB); - auto PE = pred_end(&BB); - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - Value * L = NULL; - unsigned int cur_loc; - - // Context sensitive coverage - if (caller_str && &BB == &F.getEntryBlock()) { - - PrevCaller = IRB.CreateLoad(AFLContext); - PrevCaller->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - // does the function have calls? and is any of the calls larger than - // one basic block? - has_calls = 0; - for (auto &BB2 : F) { - - if (has_calls) break; - for (auto &IN : BB2) { - - CallInst *callInst = nullptr; - if ((callInst = dyn_cast(&IN))) { - - Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < function_minimum_size) - continue; - else { - - has_calls = 1; - break; - - } - - } - - } - - } - - // if yes we store a context ID for this function in the global var - if (has_calls) { - - ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel()); - StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); - StoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } - - } // END of caller_str - - if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; } - - if (PI == PE) { - - cur_loc = genLabel(); - L = ConstantInt::get(Int32Ty, cur_loc); - - } else { - - auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); - DenseMap PredMap; - for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { - - BasicBlock *PBB = *PI; - auto It = PredMap.insert({PBB, genLabel()}); - unsigned Label = It.first->second; - // cur_loc = Label; - PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB); - - } - - L = PN; - - } - - /* Load prev_loc */ - LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); - PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *PrevLocTrans; - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - /* "For efficiency, we propose to hash the tuple as a key into the - hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where - prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */ - - if (ngram_size) - PrevLocTrans = - IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty()); - else -#endif - PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); - - if (caller_str) - PrevLocTrans = - IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCaller), Int32Ty); - - /* Load SHM pointer */ - LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); - MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *MapPtrIdx; -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) - MapPtrIdx = IRB.CreateGEP( - MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty)); - else -#endif - MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L)); - - /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - Value *Incr = IRB.CreateAdd(Counter, One); - -#if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) // with llvm 9 we make this the default as the bug in llvm is - // then fixed -#else - if (!skip_nozero) -#endif - { - - /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to - * 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter - */ - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); - - } - - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - if (caller_str && has_calls) { - - // in CALLER mode we have to restore the original context for the - // caller - she might be calling other functions which need the - // correct CALLER - Instruction *Inst = BB.getTerminator(); - if (isa(Inst) || isa(Inst)) { - - IRBuilder<> Post_IRB(Inst); - StoreInst * RestoreCtx = - Post_IRB.CreateStore(PrevCaller, AFLContext); - RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } - - } - - total_instr++; - - } - - } - - if (!be_quiet) { - - char modeline[100]; - snprintf(modeline, sizeof(modeline), "%s%s%s%s%s", - getenv("AFL_HARDEN") ? "hardened" : "non-hardened", - getenv("AFL_USE_ASAN") ? ", ASAN" : "", - getenv("AFL_USE_MSAN") ? ", MSAN" : "", - getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", - getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - - OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr, - total_rs, total_hs, modeline); - - } - - return false; - - } - -}; // end of struct InsTrim - -} // end of anonymous namespace - -char InsTrim::ID = 0; - -static void registerAFLPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { - - PM.add(new InsTrim()); - -} - -static RegisterStandardPasses RegisterAFLPass( - PassManagerBuilder::EP_OptimizerLast, registerAFLPass); - -static RegisterStandardPasses RegisterAFLPass0( - PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); - diff --git a/instrumentation/MarkNodes.cc b/instrumentation/MarkNodes.cc deleted file mode 100644 index b77466d9..00000000 --- a/instrumentation/MarkNodes.cc +++ /dev/null @@ -1,481 +0,0 @@ -#include -#include -#include -#include -#include - -#include "llvm/Config/llvm-config.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 -typedef long double max_align_t; -#endif - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/BasicBlock.h" -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) - #include "llvm/IR/CFG.h" -#else - #include "llvm/Support/CFG.h" -#endif -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -DenseMap LMap; -std::vector Blocks; -std::set Marked, Markabove; -std::vector > Succs, Preds; - -void reset() { - - LMap.clear(); - Blocks.clear(); - Marked.clear(); - Markabove.clear(); - -} - -uint32_t start_point; - -void labelEachBlock(Function *F) { - - // Fake single endpoint; - LMap[NULL] = Blocks.size(); - Blocks.push_back(NULL); - - // Assign the unique LabelID to each block; - for (auto I = F->begin(), E = F->end(); I != E; ++I) { - - BasicBlock *BB = &*I; - LMap[BB] = Blocks.size(); - Blocks.push_back(BB); - - } - - start_point = LMap[&F->getEntryBlock()]; - -} - -void buildCFG(Function *F) { - - Succs.resize(Blocks.size()); - Preds.resize(Blocks.size()); - for (size_t i = 0; i < Succs.size(); i++) { - - Succs[i].clear(); - Preds[i].clear(); - - } - - for (auto S = F->begin(), E = F->end(); S != E; ++S) { - - BasicBlock *BB = &*S; - uint32_t MyID = LMap[BB]; - - for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { - - Succs[MyID].push_back(LMap[*I]); - - } - - } - -} - -std::vector > tSuccs; -std::vector tag, indfs; - -void DFStree(size_t now_id) { - - if (tag[now_id]) return; - tag[now_id] = true; - indfs[now_id] = true; - for (auto succ : tSuccs[now_id]) { - - if (tag[succ] and indfs[succ]) { - - Marked.insert(succ); - Markabove.insert(succ); - continue; - - } - - Succs[now_id].push_back(succ); - Preds[succ].push_back(now_id); - DFStree(succ); - - } - - indfs[now_id] = false; - -} - -void turnCFGintoDAG() { - - tSuccs = Succs; - tag.resize(Blocks.size()); - indfs.resize(Blocks.size()); - for (size_t i = 0; i < Blocks.size(); ++i) { - - Succs[i].clear(); - tag[i] = false; - indfs[i] = false; - - } - - DFStree(start_point); - for (size_t i = 0; i < Blocks.size(); ++i) - if (Succs[i].empty()) { - - Succs[i].push_back(0); - Preds[0].push_back(i); - - } - -} - -uint32_t timeStamp; -namespace DominatorTree { - -std::vector > cov; -std::vector dfn, nfd, par, sdom, idom, mom, mn; - -bool Compare(uint32_t u, uint32_t v) { - - return dfn[u] < dfn[v]; - -} - -uint32_t eval(uint32_t u) { - - if (mom[u] == u) return u; - uint32_t res = eval(mom[u]); - if (Compare(sdom[mn[mom[u]]], sdom[mn[u]])) { mn[u] = mn[mom[u]]; } - return mom[u] = res; - -} - -void DFS(uint32_t now) { - - timeStamp += 1; - dfn[now] = timeStamp; - nfd[timeStamp - 1] = now; - for (auto succ : Succs[now]) { - - if (dfn[succ] == 0) { - - par[succ] = now; - DFS(succ); - - } - - } - -} - -void DominatorTree() { - - if (Blocks.empty()) return; - uint32_t s = start_point; - - // Initialization - mn.resize(Blocks.size()); - cov.resize(Blocks.size()); - dfn.resize(Blocks.size()); - nfd.resize(Blocks.size()); - par.resize(Blocks.size()); - mom.resize(Blocks.size()); - sdom.resize(Blocks.size()); - idom.resize(Blocks.size()); - - for (uint32_t i = 0; i < Blocks.size(); i++) { - - dfn[i] = 0; - nfd[i] = Blocks.size(); - cov[i].clear(); - idom[i] = mom[i] = mn[i] = sdom[i] = i; - - } - - timeStamp = 0; - DFS(s); - - for (uint32_t i = Blocks.size() - 1; i >= 1u; i--) { - - uint32_t now = nfd[i]; - if (now == Blocks.size()) { continue; } - for (uint32_t pre : Preds[now]) { - - if (dfn[pre]) { - - eval(pre); - if (Compare(sdom[mn[pre]], sdom[now])) { sdom[now] = sdom[mn[pre]]; } - - } - - } - - cov[sdom[now]].push_back(now); - mom[now] = par[now]; - for (uint32_t x : cov[par[now]]) { - - eval(x); - if (Compare(sdom[mn[x]], par[now])) { - - idom[x] = mn[x]; - - } else { - - idom[x] = par[now]; - - } - - } - - } - - for (uint32_t i = 1; i < Blocks.size(); i += 1) { - - uint32_t now = nfd[i]; - if (now == Blocks.size()) { continue; } - if (idom[now] != sdom[now]) idom[now] = idom[idom[now]]; - - } - -} - -} // namespace DominatorTree - -std::vector Visited, InStack; -std::vector TopoOrder, InDeg; -std::vector > t_Succ, t_Pred; - -void Go(uint32_t now, uint32_t tt) { - - if (now == tt) return; - Visited[now] = InStack[now] = timeStamp; - - for (uint32_t nxt : Succs[now]) { - - if (Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) { - - Marked.insert(nxt); - - } - - t_Succ[now].push_back(nxt); - t_Pred[nxt].push_back(now); - InDeg[nxt] += 1; - if (Visited[nxt] == timeStamp) { continue; } - Go(nxt, tt); - - } - - InStack[now] = 0; - -} - -void TopologicalSort(uint32_t ss, uint32_t tt) { - - timeStamp += 1; - - Go(ss, tt); - - TopoOrder.clear(); - std::queue wait; - wait.push(ss); - while (not wait.empty()) { - - uint32_t now = wait.front(); - wait.pop(); - TopoOrder.push_back(now); - for (uint32_t nxt : t_Succ[now]) { - - InDeg[nxt] -= 1; - if (InDeg[nxt] == 0u) { wait.push(nxt); } - - } - - } - -} - -std::vector > NextMarked; -bool Indistinguish(uint32_t node1, uint32_t node2) { - - if (NextMarked[node1].size() > NextMarked[node2].size()) { - - uint32_t _swap = node1; - node1 = node2; - node2 = _swap; - - } - - for (uint32_t x : NextMarked[node1]) { - - if (NextMarked[node2].find(x) != NextMarked[node2].end()) { return true; } - - } - - return false; - -} - -void MakeUniq(uint32_t now) { - - if (Marked.find(now) == Marked.end()) { - - for (uint32_t pred1 : t_Pred[now]) { - - bool StopFlag = false; - for (uint32_t pred2 : t_Pred[now]) { - - if (pred1 == pred2) continue; - if (Indistinguish(pred1, pred2)) { - - Marked.insert(now); - StopFlag = true; - break; - - } - - } - - if (StopFlag) { break; } - - } - - } - - if (Marked.find(now) != Marked.end()) { - - NextMarked[now].insert(now); - - } else { - - for (uint32_t pred : t_Pred[now]) { - - for (uint32_t x : NextMarked[pred]) { - - NextMarked[now].insert(x); - - } - - } - - } - -} - -bool MarkSubGraph(uint32_t ss, uint32_t tt) { - - TopologicalSort(ss, tt); - if (TopoOrder.empty()) return false; - - for (uint32_t i : TopoOrder) { - - NextMarked[i].clear(); - - } - - NextMarked[TopoOrder[0]].insert(TopoOrder[0]); - for (uint32_t i = 1; i < TopoOrder.size(); i += 1) { - - MakeUniq(TopoOrder[i]); - - } - - // Check if there is an empty path. - if (NextMarked[tt].count(TopoOrder[0]) > 0) return true; - return false; - -} - -void MarkVertice() { - - uint32_t s = start_point; - - InDeg.resize(Blocks.size()); - Visited.resize(Blocks.size()); - InStack.resize(Blocks.size()); - t_Succ.resize(Blocks.size()); - t_Pred.resize(Blocks.size()); - NextMarked.resize(Blocks.size()); - - for (uint32_t i = 0; i < Blocks.size(); i += 1) { - - Visited[i] = InStack[i] = InDeg[i] = 0; - t_Succ[i].clear(); - t_Pred[i].clear(); - - } - - timeStamp = 0; - uint32_t t = 0; - bool emptyPathExists = true; - - while (s != t) { - - emptyPathExists &= MarkSubGraph(DominatorTree::idom[t], t); - t = DominatorTree::idom[t]; - - } - - if (emptyPathExists) { - - // Mark all exit blocks to catch the empty path. - Marked.insert(t_Pred[0].begin(), t_Pred[0].end()); - - } - -} - -// return {marked nodes} -std::pair, std::vector > markNodes( - Function *F) { - - assert(F->size() > 0 && "Function can not be empty"); - - reset(); - labelEachBlock(F); - buildCFG(F); - turnCFGintoDAG(); - DominatorTree::DominatorTree(); - MarkVertice(); - - std::vector Result, ResultAbove; - for (uint32_t x : Markabove) { - - auto it = Marked.find(x); - if (it != Marked.end()) Marked.erase(it); - if (x) ResultAbove.push_back(Blocks[x]); - - } - - for (uint32_t x : Marked) { - - if (x == 0) { - - continue; - - } else { - - Result.push_back(Blocks[x]); - - } - - } - - return {Result, ResultAbove}; - -} - diff --git a/instrumentation/MarkNodes.h b/instrumentation/MarkNodes.h deleted file mode 100644 index 8ddc978d..00000000 --- a/instrumentation/MarkNodes.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __MARK_NODES__ -#define __MARK_NODES__ - -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" -#include - -std::pair, std::vector> -markNodes(llvm::Function *F); - -#endif - diff --git a/instrumentation/README.instrim.md b/instrumentation/README.instrim.md deleted file mode 100644 index 99f6477a..00000000 --- a/instrumentation/README.instrim.md +++ /dev/null @@ -1,30 +0,0 @@ -# InsTrim - -InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing - -## Introduction - -InsTrim is the work of Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang. - -It uses a CFG (call flow graph) and markers to instrument just what -is necessary in the binary (ie less than llvm_mode). As a result the binary is -about 10-15% faster compared to normal llvm_mode however with some coverage loss. -It requires at least llvm version 3.8.0 to build. -If you have LLVM 7+ we recommend PCGUARD instead. - -## Usage - -Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1` -during compilation of the target. - -There is also special mode which instruments loops in a way so that -afl-fuzz can see which loop path has been selected but not being able to -see how often the loop has been rerun. -This again is a tradeoff for speed for less path information. -To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`. - -## Background - -The paper from Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang: -[InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing] -(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf) diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 2705ce0d..adce6c1d 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -101,8 +101,7 @@ instrumentation by either setting `AFL_CC_COMPILER=LLVM` or pass the parameter The tool honors roughly the same environmental variables as afl-gcc (see [docs/env_variables.md](../docs/env_variables.md)). This includes AFL_USE_ASAN, AFL_HARDEN, and AFL_DONT_OPTIMIZE. However AFL_INST_RATIO is not honored -as it does not serve a good purpose with the more effective PCGUARD, LTO and - instrim CFG analysis. +as it does not serve a good purpose with the more effective PCGUARD analysis. ## 3) Options @@ -116,26 +115,20 @@ For splitting memcmp, strncmp, etc. please see [README.laf-intel.md](README.laf- Then there are different ways of instrumenting the target: -1. There is an optimized instrumentation strategy that uses CFGs and -markers to just instrument what is needed. This increases speed by 10-15% -without any disadvantages -If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1 -See [README.instrim.md](README.instrim.md) - -2. An even better instrumentation strategy uses LTO and link time +1. An better instrumentation strategy uses LTO and link time instrumentation. Note that not all targets can compile in this mode, however if it works it is the best option you can use. Simply use afl-clang-lto/afl-clang-lto++ to use this option. See [README.lto.md](README.lto.md) -3. Alternativly you can choose a completely different coverage method: +2. Alternativly you can choose a completely different coverage method: -3a. N-GRAM coverage - which combines the previous visited edges with the +2a. N-GRAM coverage - which combines the previous visited edges with the current one. This explodes the map but on the other hand has proven to be effective for fuzzing. See [README.ngram.md](README.ngram.md) -3b. Context sensitive coverage - which combines the visited edges with an +2b. Context sensitive coverage - which combines the visited edges with an individual caller ID (the function that called the current one) [README.ctx.md](README.ctx.md) diff --git a/instrumentation/README.snapshot.md b/instrumentation/README.snapshot.md index c40a956a..c794c2fd 100644 --- a/instrumentation/README.snapshot.md +++ b/instrumentation/README.snapshot.md @@ -1,5 +1,7 @@ # AFL++ snapshot feature +**NOTE:** the snapshot lkm is currently not supported and needs a maintainer :-) + Snapshotting is a feature that makes a snapshot from a process and then restores its state, which is faster then forking it again. diff --git a/src/afl-cc.c b/src/afl-cc.c index 80fc0742..d134f013 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -66,7 +66,6 @@ enum { INSTRUMENT_CLASSIC = 1, INSTRUMENT_AFL = 1, INSTRUMENT_PCGUARD = 2, - INSTRUMENT_INSTRIM = 3, INSTRUMENT_CFG = 3, INSTRUMENT_LTO = 4, INSTRUMENT_LLVMNATIVE = 5, @@ -639,10 +638,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; - if (instrument_mode == INSTRUMENT_CFG) - cc_params[cc_par_cnt++] = - alloc_printf("%s/libLLVMInsTrim.so", obj_path); - else cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); @@ -1252,8 +1247,7 @@ int main(int argc, char **argv, char **envp) { strcasecmp(ptr, "CFG") == 0) { - compiler_mode = LLVM; - instrument_mode = INSTRUMENT_CFG; + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } else if (strcasecmp(ptr, "AFL") == 0 || @@ -1319,10 +1313,7 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { - if (instrument_mode == 0) - instrument_mode = INSTRUMENT_CFG; - else if (instrument_mode != INSTRUMENT_CFG) - FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together"); + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } @@ -1409,17 +1400,7 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { - if (instrument_mode == INSTRUMENT_LTO) { - - instrument_mode = INSTRUMENT_CFG; - lto_mode = 1; - - } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG) - - instrument_mode = INSTRUMENT_CFG; - else - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } @@ -1428,7 +1409,7 @@ int main(int argc, char **argv, char **envp) { lto_mode = 1; if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) instrument_mode = INSTRUMENT_LTO; - else if (instrument_mode != INSTRUMENT_CFG) + else FATAL("main instrumentation mode already set with %s", instrument_mode_string[instrument_mode]); @@ -1642,11 +1623,6 @@ int main(int argc, char **argv, char **envp) { " - CALLER\n" " - CTX\n" " - NGRAM-{2-16}\n" - " INSTRIM no yes module yes yes " - " yes\n" - " - NORMAL\n" - " - CALLER\n" - " - NGRAM-{2-16}\n" " [GCC_PLUGIN] gcc plugin: %s%s\n" " CLASSIC DEFAULT no yes no no no " "yes\n" @@ -1697,9 +1673,7 @@ int main(int argc, char **argv, char **envp) { " CTX: CLASSIC + full callee context " "(instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " - "((instrumentation/README.ngram.md)\n" - " INSTRIM: Dominator tree (for LLVM <= 6.0) " - "(instrumentation/README.instrim.md)\n\n"); + "((instrumentation/README.ngram.md)\n\n"); #undef NATIVE_MSG @@ -1791,19 +1765,15 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, " - "NGRAM-2 ..-16\n" + " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 ..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" - " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" - " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed " - "(option to INSTRIM)\n" " AFL_LLVM_CALLER: use single context sensitive coverage (for " "CLASSIC)\n" " AFL_LLVM_CTX: use full context sensitive coverage (for " "CLASSIC)\n" " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for " - "CLASSIC & INSTRIM)\n"); + "CLASSIC)\n"); #ifdef AFL_CLANG_FLTO if (have_lto) @@ -1951,11 +1921,7 @@ int main(int argc, char **argv, char **envp) { "(requires LLVM 11 or higher)"); #endif - if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG && - instrument_opt_mode & INSTRUMENT_OPT_CTX) - FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX."); - else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) - // we will drop CFG/INSTRIM in the future so do not advertise + if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) FATAL( "CALLER, CTX and NGRAM instrumentation options can only be used with " "the LLVM CLASSIC instrumentation mode."); diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 0a978653..8928ddc9 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -73,8 +73,7 @@ static u32 ld_param_cnt = 1; /* Number of params to 'ld' */ so we exploit this property to keep the code "simple". */ static void edit_params(int argc, char **argv) { - u32 i, instrim = 0, gold_pos = 0, gold_present = 0, rt_present = 0, - rt_lto_present = 0, inst_present = 0; + u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, inst_present = 0; char *ptr; ld_params = ck_alloc(4096 * sizeof(u8 *)); @@ -186,17 +185,16 @@ static void edit_params(int argc, char **argv) { } - if (getenv("AFL_LLVM_INSTRIM")) - instrim = 1; - else if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && - (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0)) - instrim = 1; + if (getenv("AFL_LLVM_INSTRIM") || + ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && + (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) + FATAL("InsTrim was removed because it is not effective. Use a modern LLVM and PCGUARD (which is the default in afl-cc).\n"); if (debug) DEBUGF( - "passthrough=%s instrim=%u, gold_pos=%u, gold_present=%s " + "passthrough=%s, gold_pos=%u, gold_present=%s " "inst_present=%s rt_present=%s rt_lto_present=%s\n", - passthrough ? "true" : "false", instrim, gold_pos, + passthrough ? "true" : "false", gold_pos, gold_present ? "true" : "false", inst_present ? "true" : "false", rt_present ? "true" : "false", rt_lto_present ? "true" : "false"); @@ -230,10 +228,6 @@ static void edit_params(int argc, char **argv) { if (!inst_present) { - if (instrim) - ld_params[ld_param_cnt++] = - alloc_printf("-mllvm=-load=%s/afl-llvm-lto-instrim.so", afl_path); - else ld_params[ld_param_cnt++] = alloc_printf( "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 3ef36b37..eae76643 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -166,27 +166,6 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { } rm -f test-instr.plain - # now for the special llvm_mode things - test -e ../libLLVMInsTrim.so && { - AFL_LLVM_INSTRUMENT=CFG AFL_LLVM_INSTRIM_LOOPHEAD=1 ../afl-clang-fast -o test-instr.instrim ../test-instr.c > /dev/null 2>test.out - test -e test-instr.instrim && { - TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.instrim 2>&1 | grep Captur | awk '{print$3}'` - test "$TUPLES" -gt 1 -a "$TUPLES" -lt 5 && { - $ECHO "$GREEN[+] llvm_mode InsTrim reported $TUPLES instrumented locations which is fine" - } || { - $ECHO "$RED[!] llvm_mode InsTrim instrumentation produces weird numbers: $TUPLES" - CODE=1 - } - rm -f test-instr.instrim test.out - } || { - cat test.out - $ECHO "$RED[!] llvm_mode InsTrim compilation failed" - CODE=1 - } - } || { - $ECHO "$YELLOW[-] llvm_mode InsTrim not compiled, cannot test" - INCOMPLETE=1 - } AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1 test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && { grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && { -- cgit 1.4.1 From 1725e6be316b57e89df2a077710b66b684b55242 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 25 Mar 2021 17:41:14 +0000 Subject: Fix support for afl-cmin and updated README --- afl-cmin | 11 +++- afl-cmin.bash | 9 +++- frida_mode/Makefile | 40 ++++++++++++++ frida_mode/README.md | 145 ++++++++++++++++++++++++++++++++++++++++----------- src/afl-analyze.c | 2 - src/afl-fuzz.c | 2 - src/afl-showmap.c | 3 -- src/afl-tmin.c | 2 - 8 files changed, 172 insertions(+), 42 deletions(-) diff --git a/afl-cmin b/afl-cmin index a1fc6f21..3f3a7517 100755 --- a/afl-cmin +++ b/afl-cmin @@ -106,6 +106,7 @@ function usage() { " -f file - location read by the fuzzed program (stdin)\n" \ " -m megs - memory limit for child process ("mem_limit" MB)\n" \ " -t msec - run time limit for child process (none)\n" \ +" -O - use binary-only instrumentation (FRIDA mode)\n" \ " -Q - use binary-only instrumentation (QEMU mode)\n" \ " -U - use unicorn-based instrumentation (unicorn mode)\n" \ "\n" \ @@ -140,7 +141,7 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCQU?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eCOQU?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -180,6 +181,12 @@ BEGIN { extra_par = extra_par " -e" continue } else + if (_go_c == "O") { + if (frida_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} + extra_par = extra_par " -O" + frida_mode = 1 + continue + } else if (_go_c == "Q") { if (qemu_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} extra_par = extra_par " -Q" @@ -275,7 +282,7 @@ BEGIN { target_bin = tnew } - if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !unicorn_mode) { + if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) { if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) { print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr" exit 1 diff --git a/afl-cmin.bash b/afl-cmin.bash index 5b2c3894..f4bd269d 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \ export AFL_QUIET=1 -while getopts "+i:o:f:m:t:eQUCh" opt; do +while getopts "+i:o:f:m:t:eOQUCh" opt; do case "$opt" in @@ -83,6 +83,10 @@ while getopts "+i:o:f:m:t:eQUCh" opt; do "C") export AFL_CMIN_CRASHES_ONLY=1 ;; + "O") + EXTRA_PAR="$EXTRA_PAR -O" + FRIDA_MODE=1 + ;; "Q") EXTRA_PAR="$EXTRA_PAR -Q" QEMU_MODE=1 @@ -118,6 +122,7 @@ Execution control settings: -f file - location read by the fuzzed program (stdin) -m megs - memory limit for child process ($MEM_LIMIT MB) -t msec - run time limit for child process (none) + -O - use binary-only instrumentation (FRIDA mode) -Q - use binary-only instrumentation (QEMU mode) -U - use unicorn-based instrumentation (Unicorn mode) @@ -209,7 +214,7 @@ if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then fi -if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$UNICORN_MODE" = "" ]; then +if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2 diff --git a/frida_mode/Makefile b/frida_mode/Makefile index 73a4142c..efae5ebf 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -306,5 +306,45 @@ analyze_frida: $(TEST_BIN) ./afl-analyze \ -O \ -i $(TEST_DATA_DIR)basn0g01.png \ + -- \ + $(TEST_BIN) @@ + +cmin_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-cmin \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +cmin_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-cmin \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +cmin_bash_qemu: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-cmin.bash \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +cmin_bash_frida: $(TEST_BIN) + make -C .. + cd .. && \ + ./afl-cmin.bash \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ -- \ $(TEST_BIN) @@ \ No newline at end of file diff --git a/frida_mode/README.md b/frida_mode/README.md index c5436e8b..bc260e3e 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -3,46 +3,133 @@ The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AF just like that provided by QEMU mode. The intention is to provide a very similar user experience, right down to the options provided through environment variables. -Additionally, the intention is to be able to make a direct performance comparison -between the two approaches. Hopefully, we should also be able to leverage the same -approaches for adding features which QEMU uses, possibly even sharing code. +Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) +this requires the code to be fuzzed to be provided as a shared library, it +cannot be used to fuzz executables. Additionally, it requires the user to write +a small harness around their target code of interest, FRIDA mode instead takes a +different approach to avoid these limitations. -## Limitations -The current focus is on x64 support for Intel. Although parts may be architecturally -dependent, the approach itself should remain architecture agnostic. +# Current Progress +As FRIDA mode is new, it is missing a lot of features. Most importantly, +persistent mode. The design is such that it should be possible to add these +features in a similar manner to QEMU mode and perhaps leverage some of its +design and implementation. -## Usage -FRIDA mode requires some small modifications to the afl-fuzz and similar tools in -AFLplusplus. The intention is that it behaves identically to QEMU, but uses the 'O' -switch rather than 'Q'. + | Feature/Instrumentation | frida-mode | + | -------------------------|:----------:| + | NeverZero | | + | Persistent Mode | | + | LAF-Intel / CompCov | | + | CmpLog | | + | Selective Instrumentation| x | + | Non-Colliding Coverage | | + | Ngram prev_loc Coverage | | + | Context Coverage | | + | Auto Dictionary | | + | Snapshot LKM Support | | -## Design -AFL Frida works by means of a shared library injected into a binary program using -LD_PRELOAD, similar to the way which other fuzzing features are injected into targets. +# Compatibility +Currently FRIDA mode supports Linux and macOS targets on both x86/x64 +architecture and aarch64. Later releases may add support for aarch32 and Windows +targets as well as embedded linux environments. -## Testing -Alongside the FRIDA mode, we also include a test program for fuzzing. This test -program is built using the libpng benchmark from fuzz-bench and integrating the -StandaloneFuzzTargetMain from the llvm project. This is built and linked without -any special modifications to suit FRIDA or QEMU. However, at present we don't have -a representative corpus. +FRIDA has been used on various embedded targets using both uClibc and musl C +runtime libraries, so porting should be possible. However, the current build +system does not support cross compilation. ## Getting Started To build everything run `make`. -To run the benchmark sample with qemu run `make test_qemu`. -To run the benchmark sample with frida run `make test_frida`. +To run the benchmark sample with qemu run `make png_qemu`. +To run the benchmark sample with frida run `make png_frida`. + +## Usage +FRIDA mode requires some small modifications to the afl-fuzz and similar tools +in AFLplusplus. The intention is that it behaves identically to QEMU, but uses +the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have +made more sense for a mode powered by FRIDA Stalker, they were all taken, so +instead we use 'O' in homage to the [author](https://github.com/oleavr) of +FRIDA. + +Similarly, the intention is to mimic the use of environment variables used by +QEMU where possible (although replacing `s/QEMU/FRIDA/g`). Accodingly, the +following options are currently supported. -# Configuration options * `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` * `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` -* `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_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. * `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` -* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into excluded regions and generate both instrumented blocks and coverage data (e.g. indirect calls on x86). The excluded block is generally honoured as soon as another function is called within the excluded region. The overhead of generating, running and instrumenting these few additional blocks is likely to be fairly small, but it may hinder you when checking that the correct number of paths are found for testing purposes or similar. There is a performance penatly for this option during block compilation where we check the block isn't in a list of excluded ranges. -* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. + +# Performance + +Additionally, the intention is to be able to make a direct performance +comparison between the two approaches. Accordingly, FRIDA mode includes a test +target based on the [libpng](https://libpng.sourceforge.io/) benchmark used by +[fuzzbench](https://google.github.io/fuzzbench/) and integrated with the +[StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c) +from the llvm project. This is built and linked without any special +modifications to suit FRIDA or QEMU. We use the test data provided with libpng +as our corpus. + +Whilst not much performance tuning has been completed to date, performance is +around 30-50% of that of QEMU mode, however, this gap may reduce with the +introduction of persistent mode. Performance can be tested by running +`make compare`, albeit a longer time measurement may be required for move +accurate results. + +Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) +claims a 5-10x performance increase over QEMU, it has not been possible to +reproduce these claims. However, the number of executions per second can vary +dramatically as a result of the randomization of the fuzzer input. Some inputs +may traverse relatively few paths before being rejected as invalid whilst others +may be valid inputs or be subject to much more processing before rejection. +Accordingly, it is recommended that testing be carried out over prolongued +periods to gather timings which are more than indicative. + +# Design +FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS) +to inject a shared library (`afl-frida-trace.so`) into the target. This shared +library is built using the [frida-gum](https://github.com/frida/frida-gum) +devkit from the [FRIDA](https://github.com/frida/frida) project. One of the +components of frida-gum is [Stalker](https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb0df8), +this allows the dynamic instrumentation of running code for AARCH32, AARCH64, +x86 and x64 architectutes. Implementation details can be found +[here](https://frida.re/docs/stalker/). + +Dynamic instrumentation is used to augment the target application with similar +coverage information to that inserted by `afl-gcc` or `afl-clang`. The shared +library is also linked to the `compiler-rt` component of AFLplusplus to feedback +this coverage information to AFL and also provide a fork server. It also makes +use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115) +support to feedback instrumented blocks from the child to the parent using a +shared memory region to avoid the need to regenerate instrumented blocks on each +fork. + +Whilst FRIDA allows for a normal C function to be used to augment instrumented +code, to minimize the costs of storing and restoring all of the registers, FRIDA +mode instead makes use of optimized assembly instead on AARCH64 and x86/64 +targets. + +# Advanced configuration options +* `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_NO_PREFETCH` - Disable prefetching. By default the child will +report instrumented blocks back to the parent so that it can also instrument +them and they be inherited by the next child on fork. +* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into +excluded regions and generate both instrumented blocks and coverage data (e.g. +indirect calls on x86). The excluded block is generally honoured as soon as +another function is called within the excluded region and so such encroachment +is usually of little consequence. This detail may however, hinder you when +checking that the correct number of paths are found for testing purposes or +similar. There is a performance penatly for this option during block compilation +where we check the block isn't in a list of excluded ranges. +* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. +Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. # TODO -* Add AARCH64 inline assembly optimization from libFuzz -* Fix issues running on OSX -* Identify cause of erroneous additional paths +As can be seen from the progress section above, there are a number of features +which are missing in its currently form. Chief amongst which is persistent mode. +The intention is to achieve feature parity with QEMU mode in due course. +Contributions are welcome, but please get in touch to ensure that efforts are +deconflicted. \ No newline at end of file diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 6ff119ac..8e5a1772 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -842,7 +842,6 @@ static void set_up_environment(char **argv) { } ck_free(frida_binary); - OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); @@ -859,7 +858,6 @@ static void set_up_environment(char **argv) { u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); ck_free(frida_binary); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 34e9d420..ba8feb53 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1320,7 +1320,6 @@ int main(int argc, char **argv_orig, char **envp) { } ck_free(frida_binary); - OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); @@ -1337,7 +1336,6 @@ int main(int argc, char **argv_orig, char **envp) { u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); ck_free(frida_binary); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index aea90b3b..38d03d80 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -617,7 +617,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { } ck_free(frida_binary); - OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); @@ -634,7 +633,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); ck_free(frida_binary); } @@ -996,7 +994,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { /* If we don't have a file name chosen yet, use a safe default. */ diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 68e61109..bad5d71b 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -772,7 +772,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { } ck_free(frida_binary); - OKF("Frida Mode setting LD_PRELOAD %s", frida_afl_preload); setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); @@ -789,7 +788,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - OKF("Frida Mode setting LD_PRELOAD %s", frida_binary); ck_free(frida_binary); } -- cgit 1.4.1 From c169cb3911b33fbc3974005788ade1c9218ade98 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 20:10:09 +0100 Subject: integrate frida_mode, code-format --- GNUmakefile | 3 +++ docs/Changelog.md | 2 ++ docs/env_variables.md | 5 +++-- frida_mode/Makefile | 32 +++++++++++++++----------------- frida_mode/inc/instrument.h | 7 ------- frida_mode/inc/interceptor.h | 4 ---- frida_mode/inc/prefetch.h | 5 ----- frida_mode/inc/ranges.h | 6 ------ frida_mode/include/instrument.h | 7 +++++++ frida_mode/include/interceptor.h | 4 ++++ frida_mode/include/prefetch.h | 5 +++++ frida_mode/include/ranges.h | 6 ++++++ frida_mode/src/main.c | 8 ++++---- include/forkserver.h | 2 +- qemu_mode/qemuafl | 2 +- src/afl-cc.c | 18 ++++++++++++------ src/afl-common.c | 11 ++++++++++- src/afl-ld-lto.c | 15 +++++++++------ 18 files changed, 82 insertions(+), 60 deletions(-) delete mode 100644 frida_mode/inc/instrument.h delete mode 100644 frida_mode/inc/interceptor.h delete mode 100644 frida_mode/inc/prefetch.h delete mode 100644 frida_mode/inc/ranges.h create mode 100644 frida_mode/include/instrument.h create mode 100644 frida_mode/include/interceptor.h create mode 100644 frida_mode/include/prefetch.h create mode 100644 frida_mode/include/ranges.h diff --git a/GNUmakefile b/GNUmakefile index ac8fe796..963004bd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -593,6 +593,7 @@ distrib: all $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -603,6 +604,7 @@ binary-only: test_shm test_python ready $(PROGS) $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -648,6 +650,7 @@ install: all $(MANPAGES) @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi + @if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 730791da..6ae42b04 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,8 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - frida_mode - new mode that uses frida to fuzz binary-only targets, + thanks to @WorksButNotTested! - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` diff --git a/docs/env_variables.md b/docs/env_variables.md index 572fad01..899b36cc 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -372,7 +372,8 @@ checks or alter some of the more exotic semantics of the tool: may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace. + - In QEMU mode (-Q), Unicorn mode (-U) and Frida mode (-O), `AFL_PATH` will + be searched for afl-qemu-trace. - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip prepending `afl-qemu-trace` to your command line. Use this if you wish to use a @@ -605,7 +606,7 @@ optimal values if not already present in the environment: override this by setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. - - By default, `ASAN_OPTIONS` are set to: + - By default, `ASAN_OPTIONS` are set to (among others): ``` abort_on_error=1 detect_leaks=0 diff --git a/frida_mode/Makefile b/frida_mode/Makefile index efae5ebf..822f1c6a 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,41 +1,39 @@ PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)inc/ +INC_DIR:=$(PWD)include/ SRC_DIR:=$(PWD)src/ INCLUDES:=$(wildcard $(INC_DIR)*.h) SOURCES:=$(wildcard $(SRC_DIR)*.c) BUILD_DIR:=$(PWD)build/ -CFLAGS:= $(CFLAGS) \ - -fPIC \ - -D_GNU_SOURCE +CFLAGS+=-fPIC -D_GNU_SOURCE FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" -ARCH:=arm64 -TESTINSTR_BASE:=0x0000aaaaaaaaa000 + ARCH:=arm64 + TESTINSTR_BASE:=0x0000aaaaaaaaa000 endif ifeq "$(ARCH)" "x86_64" -TESTINSTR_BASE:=0x0000555555554000 + TESTINSTR_BASE:=0x0000555555554000 endif ifeq "$(shell uname)" "Darwin" -OS:=macos -AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF -CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations -TEST_LDFLAGS:=-undefined dynamic_lookup + OS:=macos + AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF + CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations + TEST_LDFLAGS:=-undefined dynamic_lookup endif ifeq "$(shell uname)" "Linux" -OS:=linux -AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) -CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor -TEST_LDFLAGS:= + OS:=linux + AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) + CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor + TEST_LDFLAGS:= endif ifndef OS -$(error "Operating system unsupported") + $(error "Operating system unsupported") endif VERSION=14.2.13 @@ -347,4 +345,4 @@ cmin_bash_frida: $(TEST_BIN) -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TEST_BIN) @@ \ No newline at end of file + $(TEST_BIN) @@ diff --git a/frida_mode/inc/instrument.h b/frida_mode/inc/instrument.h deleted file mode 100644 index ff71bed4..00000000 --- a/frida_mode/inc/instrument.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "frida-gum.h" - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); - -void instrument_init(); - diff --git a/frida_mode/inc/interceptor.h b/frida_mode/inc/interceptor.h deleted file mode 100644 index 5ed3cf49..00000000 --- a/frida_mode/inc/interceptor.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "frida-gum.h" - -void intercept(void *address, gpointer replacement, gpointer user_data); - diff --git a/frida_mode/inc/prefetch.h b/frida_mode/inc/prefetch.h deleted file mode 100644 index b7f25a97..00000000 --- a/frida_mode/inc/prefetch.h +++ /dev/null @@ -1,5 +0,0 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); -void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); - diff --git a/frida_mode/inc/ranges.h b/frida_mode/inc/ranges.h deleted file mode 100644 index b9394dbc..00000000 --- a/frida_mode/inc/ranges.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "frida-gum.h" - -void ranges_init(GumStalker *stalker); - -gboolean range_is_excluded(gpointer address); - diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h new file mode 100644 index 00000000..ff71bed4 --- /dev/null +++ b/frida_mode/include/instrument.h @@ -0,0 +1,7 @@ +#include "frida-gum.h" + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); + +void instrument_init(); + diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h new file mode 100644 index 00000000..5ed3cf49 --- /dev/null +++ b/frida_mode/include/interceptor.h @@ -0,0 +1,4 @@ +#include "frida-gum.h" + +void intercept(void *address, gpointer replacement, gpointer user_data); + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h new file mode 100644 index 00000000..b7f25a97 --- /dev/null +++ b/frida_mode/include/prefetch.h @@ -0,0 +1,5 @@ +void prefetch_init(); +void prefetch_start(GumStalker *stalker); +void prefetch_write(void *addr); +void prefetch_read(GumStalker *stalker); + diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h new file mode 100644 index 00000000..b9394dbc --- /dev/null +++ b/frida_mode/include/ranges.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +void ranges_init(GumStalker *stalker); + +gboolean range_is_excluded(gpointer address); + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 444c9583..7505c2f9 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -22,10 +22,10 @@ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); #else -extern int __libc_start_main(int *(main)(int, char **, char **), int argc, - char **ubp_av, void (*init)(void), - void (*fini)(void), void (*rtld_fini)(void), - void(*stack_end)); +extern int __libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)); #endif typedef int *(*main_fn_t)(int argc, char **argv, char **envp); diff --git a/include/forkserver.h b/include/forkserver.h index cc759545..48db94c7 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,7 +77,7 @@ typedef struct afl_forkserver { bool qemu_mode; /* if running in qemu mode or not */ - bool frida_mode; /* if running in frida mode or not */ + bool frida_mode; /* if running in frida mode or not */ bool use_stdin; /* use stdin for sending data */ diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 0fb212da..ddc4a974 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 0fb212daab492411b3e323bc18a3074c1aecfd37 +Subproject commit ddc4a9748d59857753fb33c30a356f354595f36d diff --git a/src/afl-cc.c b/src/afl-cc.c index d134f013..1b4edbb9 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -638,8 +638,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); } @@ -1247,7 +1246,9 @@ int main(int argc, char **argv, char **envp) { strcasecmp(ptr, "CFG") == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } else if (strcasecmp(ptr, "AFL") == 0 || @@ -1313,7 +1314,9 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD " + "(default in afl-cc).\n"); } @@ -1400,7 +1403,9 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } @@ -1765,7 +1770,8 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 ..-16\n" + " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 " + "..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" " AFL_LLVM_CALLER: use single context sensitive coverage (for " diff --git a/src/afl-common.c b/src/afl-common.c index 087aa113..0fb1462e 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -336,7 +336,16 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { } - target_path = alloc_printf("%s/%s", BIN_PATH, fname); + if (perm == X_OK) { + + target_path = alloc_printf("%s/%s", BIN_PATH, fname); + + } else { + + target_path = alloc_printf("%s/%s", AFL_PATH, fname); + + } + if (!access(target_path, perm)) { return target_path; diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 8928ddc9..d0113af9 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -73,7 +73,8 @@ static u32 ld_param_cnt = 1; /* Number of params to 'ld' */ so we exploit this property to keep the code "simple". */ static void edit_params(int argc, char **argv) { - u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, inst_present = 0; + u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, + inst_present = 0; char *ptr; ld_params = ck_alloc(4096 * sizeof(u8 *)); @@ -185,10 +186,12 @@ static void edit_params(int argc, char **argv) { } - if (getenv("AFL_LLVM_INSTRIM") || + if (getenv("AFL_LLVM_INSTRIM") || ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && - (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) - FATAL("InsTrim was removed because it is not effective. Use a modern LLVM and PCGUARD (which is the default in afl-cc).\n"); + (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) + FATAL( + "InsTrim was removed because it is not effective. Use a modern LLVM " + "and PCGUARD (which is the default in afl-cc).\n"); if (debug) DEBUGF( @@ -228,8 +231,8 @@ static void edit_params(int argc, char **argv) { if (!inst_present) { - ld_params[ld_param_cnt++] = alloc_printf( - "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); + ld_params[ld_param_cnt++] = alloc_printf( + "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); } -- cgit 1.4.1 From 22c696ff1c64025398504e87f3112da82857d901 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 20:24:47 +0100 Subject: update README --- README.md | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3ba05777..b0ed8634 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,11 @@ For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. -## Major changes in afl++ 3.00 + 3.10 +## Major changes in afl++ 3.00 onwards: + +With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for +binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android, +iOS etc. With afl++ 3.10 we introduced the following changes from previous behaviours: * The '+' feature of the '-t' option now means to auto-calculate the timeout @@ -81,21 +85,21 @@ behaviours and defaults: ## Important features of afl++ afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1 - with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and - Android support and much, much, much more. - - | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | qemu_mode | unicorn_mode | - | -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:| - | NeverZero | x86[_64]| x(1) | x | x | x | - | Persistent Mode | | x | x | x86[_64]/arm[64] | x | - | LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | x86[_64]/arm[64] | | - | Selective Instrumentation| | x | x | x | | - | Non-Colliding Coverage | | x(4) | | (x)(5) | | - | Ngram prev_loc Coverage | | x(6) | | | | - | Context Coverage | | x(6) | | | | - | Auto Dictionary | | x(7) | | | | - | Snapshot LKM Support | | x(8) | x(8) | (x)(5) | | + with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, + Mac OS, Solaris and Android support and much, much, much more. + + | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | + | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| + | NeverZero | x86[_64]| x(1) | x | | x | x | + | Persistent Mode | | x | x | | x86[_64]/arm[64] | x | + | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | + | CmpLog | | x | | | x86[_64]/arm[64] | | + | Selective Instrumentation| | x | x | x | x | | + | Non-Colliding Coverage | | x(4) | | | (x)(5) | | + | Ngram prev_loc Coverage | | x(6) | | | | | + | Context Coverage | | x(6) | | | | | + | Auto Dictionary | | x(7) | | | | | + | Snapshot LKM Support | | x(8) | x(8) | | (x)(5) | | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8 2. GCC creates non-performant code, hence it is disabled in gcc_plugin @@ -140,6 +144,7 @@ behaviours and defaults: time when we are satisfied with its stability * [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a checkout which does not compile or has a bug. *We only accept PRs in dev!!* + * [release](https://github.com/AFLplusplus/AFLplusplus/tree/release) : the latest release * (any other) : experimental branches to work on specific features or testing new functionality or changes. -- cgit 1.4.1 From 2c5844f6657861cfc881adf2f38aa5d3da3ccf9d Mon Sep 17 00:00:00 2001 From: Yong-Hao Zou Date: Fri, 26 Mar 2021 15:41:19 +0800 Subject: Update custom_mutators.md --- docs/custom_mutators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 61d711e4..62e01f83 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -89,10 +89,10 @@ def queue_get(filename): def queue_new_entry(filename_new_queue, filename_orig_queue): pass -``` def introspection(): return string +``` ### Custom Mutation -- cgit 1.4.1 From 1006abffade85df1108112b728e09a666d8388a8 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 26 Mar 2021 16:19:07 +0100 Subject: fix compilation for llvm 3.8.0 --- instrumentation/afl-llvm-common.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 74943fb2..24498f3e 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -104,7 +104,8 @@ bool isIgnoreFunction(const llvm::Function *F) { for (auto const &ignoreListFunc : ignoreSubstringList) { - if (F->getName().contains(ignoreListFunc)) { return true; } + // hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0 + if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; } } -- cgit 1.4.1 From 3439d641c0e79d2bb3229a04c7e78c45e0b1e3f5 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 26 Mar 2021 16:56:57 +0100 Subject: pass lib -ldl only on Linux platforms --- test/test-llvm.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test-llvm.sh b/test/test-llvm.sh index eae76643..06d0a0f8 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -46,7 +46,8 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1 test -e test-instr.so && { $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded" - ../afl-clang-fast -o test-dlopen.plain test-dlopen.c -ldl > /dev/null 2>&1 + test `uname -s` = 'Linux' && LIBS=-ldl : + ../afl-clang-fast -o test-dlopen.plain test-dlopen.c ${LIBS} > /dev/null 2>&1 test -e test-dlopen.plain && { $ECHO "$GREEN[+] llvm_mode test-dlopen compilation succeeded" echo 0 | TEST_DLOPEN_TARGET=./test-instr.so AFL_QUIET=1 ./test-dlopen.plain > /dev/null 2>&1 @@ -81,6 +82,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { CODE=1 } rm -f test-dlopen.plain test-dlopen.plain.0 test-dlopen.plain.1 test-instr.so + unset LIBS } || { $ECHO "$RED[!] llvm_mode shared object with -z defs compilation failed" CODE=1 -- cgit 1.4.1 From a50d95b8313cfc85191778f71fb74481675ff807 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 26 Mar 2021 17:42:54 +0100 Subject: typos --- frida_mode/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frida_mode/README.md b/frida_mode/README.md index bc260e3e..8abee0dd 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -44,11 +44,11 @@ To run the benchmark sample with qemu run `make png_qemu`. To run the benchmark sample with frida run `make png_frida`. ## Usage -FRIDA mode requires some small modifications to the afl-fuzz and similar tools +FRIDA mode requires some small modifications to `afl-fuzz` and similar tools in AFLplusplus. The intention is that it behaves identically to QEMU, but uses the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have made more sense for a mode powered by FRIDA Stalker, they were all taken, so -instead we use 'O' in homage to the [author](https://github.com/oleavr) of +instead we use 'O' in hommage to the [author](https://github.com/oleavr) of FRIDA. Similarly, the intention is to mimic the use of environment variables used by @@ -73,7 +73,7 @@ as our corpus. Whilst not much performance tuning has been completed to date, performance is around 30-50% of that of QEMU mode, however, this gap may reduce with the introduction of persistent mode. Performance can be tested by running -`make compare`, albeit a longer time measurement may be required for move +`make compare`, albeit a longer time measurement may be required for more accurate results. Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) @@ -92,13 +92,13 @@ library is built using the [frida-gum](https://github.com/frida/frida-gum) devkit from the [FRIDA](https://github.com/frida/frida) project. One of the components of frida-gum is [Stalker](https://medium.com/@oleavr/anatomy-of-a-code-tracer-b081aadb0df8), this allows the dynamic instrumentation of running code for AARCH32, AARCH64, -x86 and x64 architectutes. Implementation details can be found +x86 and x64 architectures. Implementation details can be found [here](https://frida.re/docs/stalker/). Dynamic instrumentation is used to augment the target application with similar coverage information to that inserted by `afl-gcc` or `afl-clang`. The shared library is also linked to the `compiler-rt` component of AFLplusplus to feedback -this coverage information to AFL and also provide a fork server. It also makes +this coverage information to AFL++ and also provide a fork server. It also makes use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115) support to feedback instrumented blocks from the child to the parent using a shared memory region to avoid the need to regenerate instrumented blocks on each @@ -132,4 +132,4 @@ As can be seen from the progress section above, there are a number of features which are missing in its currently form. Chief amongst which is persistent mode. The intention is to achieve feature parity with QEMU mode in due course. Contributions are welcome, but please get in touch to ensure that efforts are -deconflicted. \ No newline at end of file +deconflicted. -- cgit 1.4.1 From fa349b4f4ceaa3e8309e7b01ddee6b6f895175f6 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 26 Mar 2021 17:49:20 +0100 Subject: simpler argument processing --- utils/crash_triage/triage_crashes.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh index c9ca1f79..4d75430e 100755 --- a/utils/crash_triage/triage_crashes.sh +++ b/utils/crash_triage/triage_crashes.sh @@ -90,13 +90,15 @@ for crash in $DIR/crashes/id:*; do for a in $@; do - if echo "$a" | grep -qF '@@'; then - escaped_fname=`echo $crash | sed 's:/:\\\\/:g'` - use_args="$use_args `echo $a | sed "s/@@/$escaped_fname/g"`" + case "$a" in + *@@*) unset use_stdio - else + use_args="$use_args `printf %s "$a" | sed -e 's<@@<'$crash' Date: Sat, 27 Mar 2021 12:24:18 +0100 Subject: restructure havoc --- src/afl-fuzz-one.c | 662 +++++++++++++++++++++++++++++------------------------ 1 file changed, 367 insertions(+), 295 deletions(-) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4e8154cd..e0d961ba 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1997,16 +1997,19 @@ havoc_stage: /* We essentially just do several thousand runs (depending on perf_score) where we take the input file and make random stacked tweaks. */ +#define MAX_HAVOC_ENTRY 59 /* 55 to 60 */ + u32 r_max, r; - r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) + + (afl->a_extras_cnt ? 2 : 0); if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here, they are activated after a full cycle without finds happened */ - r_max++; + r_max += 4; } @@ -2015,7 +2018,7 @@ havoc_stage: /* add expensive havoc cases here if there is no findings in the last 5s */ - r_max++; + r_max += 4; } @@ -2069,7 +2072,7 @@ havoc_stage: switch ((r = rand_below(afl, r_max))) { - case 0: + case 0 ... 3: { /* Flip a single bit somewhere. Spooky! */ @@ -2080,7 +2083,9 @@ havoc_stage: FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); break; - case 1: + } + + case 4 ... 7: { /* Set byte to interesting value. */ @@ -2092,63 +2097,77 @@ havoc_stage: interesting_8[rand_below(afl, sizeof(interesting_8))]; break; - case 2: + } + + case 8 ... 9: { /* Set word to interesting value, randomly choosing endian. */ if (temp_len < 2) { break; } - if (rand_below(afl, 2)) { - #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = - interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; - } else { + break; + + } + + case 10 ... 11: { + + /* Set word to interesting value, randomly choosing endian. */ + + if (temp_len < 2) { break; } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( - interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); - - } + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); break; - case 3: + } + + case 12 ... 13: { /* Set dword to interesting value, randomly choosing endian. */ if (temp_len < 4) { break; } - if (rand_below(afl, 2)) { - #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32"); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32"); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = - interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = + interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; - } else { + break; + + } + + case 14 ... 15: { + + /* Set dword to interesting value, randomly choosing endian. */ + + if (temp_len < 4) { break; } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE"); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE"); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( - interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); - - } + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( + interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); break; - case 4: + } + + case 16 ... 19: { /* Randomly subtract from byte. */ @@ -2159,7 +2178,9 @@ havoc_stage: out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); break; - case 5: + } + + case 20 ... 23: { /* Randomly add to byte. */ @@ -2170,139 +2191,165 @@ havoc_stage: out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); break; - case 6: + } + + case 24 ... 25: { - /* Randomly subtract from word, random endian. */ + /* Randomly subtract from word, little endian. */ if (temp_len < 2) { break; } - if (rand_below(afl, 2)) { - - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below(afl, temp_len - 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); + *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); - } else { + break; + + } + + case 26 ... 27: { + + /* Randomly subtract from word, big endian. */ - u32 pos = rand_below(afl, temp_len - 1); - u16 num = 1 + rand_below(afl, ARITH_MAX); + if (temp_len < 2) { break; } + + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos, - num); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) = - SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); - - } + *(u16 *)(out_buf + pos) = + SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); break; - case 7: + } - /* Randomly add to word, random endian. */ + case 28 ... 29: { - if (temp_len < 2) { break; } + /* Randomly add to word, little endian. */ - if (rand_below(afl, 2)) { + if (temp_len < 2) { break; } - u32 pos = rand_below(afl, temp_len - 1); + u32 pos = rand_below(afl, temp_len - 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); + *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); - } else { + break; + + } - u32 pos = rand_below(afl, temp_len - 1); - u16 num = 1 + rand_below(afl, ARITH_MAX); + case 30 ... 31: { + + /* Randomly add to word, big endian. */ + + if (temp_len < 2) { break; } + + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos, - num); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) = - SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); - - } + *(u16 *)(out_buf + pos) = + SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); break; - case 8: + } + + case 32 ... 33: { - /* Randomly subtract from dword, random endian. */ + /* Randomly subtract from dword, little endian. */ if (temp_len < 4) { break; } - if (rand_below(afl, 2)) { - - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below(afl, temp_len - 3); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); + *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); - } else { + break; + + } + + case 34 ... 35: { + + /* Randomly subtract from dword, big endian. */ - u32 pos = rand_below(afl, temp_len - 3); - u32 num = 1 + rand_below(afl, ARITH_MAX); + if (temp_len < 4) { break; } + + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos, - num); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) = - SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); - - } + *(u32 *)(out_buf + pos) = + SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); break; - case 9: + } - /* Randomly add to dword, random endian. */ + case 36 ... 37: { - if (temp_len < 4) { break; } + /* Randomly add to dword, little endian. */ - if (rand_below(afl, 2)) { + if (temp_len < 4) { break; } - u32 pos = rand_below(afl, temp_len - 3); + u32 pos = rand_below(afl, temp_len - 3); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); + *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); - } else { + break; + + } - u32 pos = rand_below(afl, temp_len - 3); - u32 num = 1 + rand_below(afl, ARITH_MAX); + case 38 ... 39: { + + /* Randomly add to dword, big endian. */ + + if (temp_len < 4) { break; } + + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos, - num); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos, + num); + strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) = - SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); - - } + *(u32 *)(out_buf + pos) = + SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); break; - case 10: + } + + case 40 ... 43: { /* Just set a random byte to a random value. Because, why not. We use XOR with 1-255 to eliminate the @@ -2315,59 +2362,58 @@ havoc_stage: out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); break; - case 11 ... 12: { - - /* Delete bytes. We're making this a bit more likely - than insertion (the next option) in hopes of keeping - files reasonably small. */ - - u32 del_from, del_len; + } - if (temp_len < 2) { break; } + case 44 ... 46: { - /* Don't delete too much. */ + if (temp_len + HAVOC_BLK_XL < MAX_FILE) { - del_len = choose_block_len(afl, temp_len - 1); + /* Clone bytes. */ - del_from = rand_below(afl, temp_len - del_len + 1); + u32 clone_len = choose_block_len(afl, temp_len); + u32 clone_from = rand_below(afl, temp_len - clone_len + 1); + u32 clone_to = rand_below(afl, temp_len); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from, - del_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u", + actually_clone ? "clone" : "insert", clone_from, clone_to, + clone_len); + strcat(afl->mutation, afl->m_tmp); #endif - memmove(out_buf + del_from, out_buf + del_from + del_len, - temp_len - del_from - del_len); + u8 *new_buf = + afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); + if (unlikely(!new_buf)) { PFATAL("alloc"); } - temp_len -= del_len; + /* Head */ - break; + memcpy(new_buf, out_buf, clone_to); - } + /* Inserted part */ - case 13: + memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); - if (temp_len + HAVOC_BLK_XL < MAX_FILE) { + /* Tail */ + memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); - /* Clone bytes (75%) or insert a block of constant bytes (25%). */ + out_buf = new_buf; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); + temp_len += clone_len; - u8 actually_clone = rand_below(afl, 4); - u32 clone_from, clone_to, clone_len; - u8 *new_buf; + } - if (likely(actually_clone)) { + break; - clone_len = choose_block_len(afl, temp_len); - clone_from = rand_below(afl, temp_len - clone_len + 1); + } - } else { + case 47: { - clone_len = choose_block_len(afl, HAVOC_BLK_XL); - clone_from = 0; + if (temp_len + HAVOC_BLK_XL < MAX_FILE) { - } + /* Insert a block of constant bytes (25%). */ - clone_to = rand_below(afl, temp_len); + u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL); + u32 clone_to = rand_below(afl, temp_len); #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u", @@ -2375,7 +2421,7 @@ havoc_stage: clone_len); strcat(afl->mutation, afl->m_tmp); #endif - new_buf = + u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); if (unlikely(!new_buf)) { PFATAL("alloc"); } @@ -2385,18 +2431,10 @@ havoc_stage: /* Inserted part */ - if (likely(actually_clone)) { - - memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); - - } else { - - memset(new_buf + clone_to, - rand_below(afl, 2) ? rand_below(afl, 256) - : out_buf[rand_below(afl, temp_len)], - clone_len); - - } + memset(new_buf + clone_to, + rand_below(afl, 2) ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], + clone_len); /* Tail */ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, @@ -2410,47 +2448,79 @@ havoc_stage: break; - case 14: { + } - /* Overwrite bytes with a randomly selected chunk (75%) or fixed - bytes (25%). */ + case 48 ... 50: { - u32 copy_from, copy_to, copy_len; + /* Overwrite bytes with a randomly selected chunk bytes. */ if (temp_len < 2) { break; } - copy_len = choose_block_len(afl, temp_len - 1); + u32 copy_len = choose_block_len(afl, temp_len - 1); + u32 copy_from = rand_below(afl, temp_len - copy_len + 1); + u32 copy_to = rand_below(afl, temp_len - copy_len + 1); + + if (likely(copy_from != copy_to)) { + +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_COPY-%u-%u-%u", + copy_from, copy_to, copy_len); + strcat(afl->mutation, afl->m_tmp); +#endif + memmove(out_buf + copy_to, out_buf + copy_from, copy_len); + + } + + break; + + } - copy_from = rand_below(afl, temp_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + case 51: { - if (likely(rand_below(afl, 4))) { + /* Overwrite bytes with fixed bytes. */ + + if (temp_len < 2) { break; } - if (likely(copy_from != copy_to)) { + u32 copy_len = choose_block_len(afl, temp_len - 1); + u32 copy_to = rand_below(afl, temp_len - copy_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " OVERWRITE_COPY-%u-%u-%u", copy_from, copy_to, - copy_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u-%u", + copy_from, copy_to, copy_len); + strcat(afl->mutation, afl->m_tmp); #endif - memmove(out_buf + copy_to, out_buf + copy_from, copy_len); + memset(out_buf + copy_to, + rand_below(afl, 2) ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], + copy_len); - } + break; - } else { + } + + // increase from 4 up to 8? + case 52 ... MAX_HAVOC_ENTRY: { + + /* Delete bytes. We're making this a bit more likely + than insertion (the next option) in hopes of keeping + files reasonably small. */ + + if (temp_len < 2) { break; } + + /* Don't delete too much. */ + + u32 del_len = choose_block_len(afl, temp_len - 1); + u32 del_from = rand_below(afl, temp_len - del_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " OVERWRITE_FIXED-%u-%u-%u", copy_from, copy_to, copy_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from, + del_len); + strcat(afl->mutation, afl->m_tmp); #endif - memset(out_buf + copy_to, - rand_below(afl, 2) ? rand_below(afl, 256) - : out_buf[rand_below(afl, temp_len)], - copy_len); + memmove(out_buf + del_from, out_buf + del_from + del_len, + temp_len - del_from - del_len); - } + temp_len -= del_len; break; @@ -2458,93 +2528,101 @@ havoc_stage: default: - if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) { - - /* Values 15 and 16 can be selected only if there are any extras - present in the dictionaries. */ + r -= (MAX_HAVOC_ENTRY + 1); - if (r == 15) { + if (afl->extras_cnt) { - /* Overwrite bytes with an extra. */ + if (r < 2) { - if (!afl->extras_cnt || - (afl->a_extras_cnt && rand_below(afl, 2))) { - - /* No user-specified extras or odds in our favor. Let's use an - auto-detected one. */ + /* Use the dictionary. */ - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; - if (extra_len > temp_len) { break; } + if (extra_len > temp_len) { break; } - u32 insert_at = rand_below(afl, temp_len - extra_len + 1); + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_OVERWRITE-%u-%u", + insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); - - } else { + memcpy(out_buf + insert_at, afl->extras[use_extra].data, + extra_len); - /* No auto extras or odds in our favor. Use the dictionary. */ + break; - u32 use_extra = rand_below(afl, afl->extras_cnt); - u32 extra_len = afl->extras[use_extra].len; + } else if (r < 4) { - if (extra_len > temp_len) { break; } + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; + if (temp_len + extra_len >= MAX_FILE) { break; } - u32 insert_at = rand_below(afl, temp_len - extra_len + 1); + u8 *ptr = afl->extras[use_extra].data; + u32 insert_at = rand_below(afl, temp_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u", + insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - memcpy(out_buf + insert_at, afl->extras[use_extra].data, - extra_len); - } + out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } + + /* Tail */ + memmove(out_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); + + /* Inserted part */ + memcpy(out_buf + insert_at, ptr, extra_len); + temp_len += extra_len; break; - } else { // case 16 + } else { - u32 use_extra, extra_len, - insert_at = rand_below(afl, temp_len + 1); - u8 *ptr; + r -= 4; - /* Insert an extra. Do the same dice-rolling stuff as for the - previous case. */ + } - if (!afl->extras_cnt || - (afl->a_extras_cnt && rand_below(afl, 2))) { + } - use_extra = rand_below(afl, afl->a_extras_cnt); - extra_len = afl->a_extras[use_extra].len; - ptr = afl->a_extras[use_extra].data; -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); -#endif + if (afl->a_extras_cnt) { - } else { + if (r == 0) { - use_extra = rand_below(afl, afl->extras_cnt); - extra_len = afl->extras[use_extra].len; - ptr = afl->extras[use_extra].data; + /* Use the dictionary. */ + + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; + + if (extra_len > temp_len) { break; } + + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u", - insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO_EXTRA_OVERWRITE-%u-%u", + insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif + memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, + extra_len); - } + break; + + } else if (r == 1) { + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; if (temp_len + extra_len >= MAX_FILE) { break; } + u8 *ptr = afl->a_extras[use_extra].data; + u32 insert_at = rand_below(afl, temp_len + 1); +#ifdef INTROSPECTION + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO_EXTRA_INSERT-%u-%u", + insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); +#endif + out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); if (unlikely(!out_buf)) { PFATAL("alloc"); } @@ -2554,103 +2632,97 @@ havoc_stage: /* Inserted part */ memcpy(out_buf + insert_at, ptr, extra_len); - temp_len += extra_len; break; - } + } else { - } else { + r -= 2; - /* - switch (r) { + } - case 15: // fall through - case 16: - case 17: {*/ + } - /* Overwrite bytes with a randomly selected chunk from another - testcase or insert that chunk. */ + /* Splicing otherwise if we are still here. + Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ - /* Pick a random queue entry and seek to it. */ + /* Pick a random queue entry and seek to it. */ - u32 tid; - do { + u32 tid; + do { - tid = rand_below(afl, afl->queued_paths); + tid = rand_below(afl, afl->queued_paths); - } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); + } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); - /* Get the testcase for splicing. */ - struct queue_entry *target = afl->queue_buf[tid]; - u32 new_len = target->len; - u8 * new_buf = queue_testcase_get(afl, target); + /* Get the testcase for splicing. */ + struct queue_entry *target = afl->queue_buf[tid]; + u32 new_len = target->len; + u8 * new_buf = queue_testcase_get(afl, target); - if ((temp_len >= 2 && rand_below(afl, 2)) || - temp_len + HAVOC_BLK_XL >= MAX_FILE) { + if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) { - /* overwrite mode */ + /* overwrite mode */ - u32 copy_from, copy_to, copy_len; + u32 copy_from, copy_to, copy_len; - copy_len = choose_block_len(afl, new_len - 1); - if (copy_len > temp_len) copy_len = temp_len; + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; - copy_from = rand_below(afl, new_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to, - copy_len, target->fname); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to, + copy_len, target->fname); + strcat(afl->mutation, afl->m_tmp); #endif - memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - } else { + } else { - /* insert mode */ + /* insert mode */ - u32 clone_from, clone_to, clone_len; + u32 clone_from, clone_to, clone_len; - clone_len = choose_block_len(afl, new_len); - clone_from = rand_below(afl, new_len - clone_len + 1); - clone_to = rand_below(afl, temp_len + 1); + clone_len = choose_block_len(afl, new_len); + clone_from = rand_below(afl, new_len - clone_len + 1); + clone_to = rand_below(afl, temp_len + 1); - u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), - temp_len + clone_len + 1); - if (unlikely(!temp_buf)) { PFATAL("alloc"); } + u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), + temp_len + clone_len + 1); + if (unlikely(!temp_buf)) { PFATAL("alloc"); } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to, - clone_len, target->fname); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to, + clone_len, target->fname); + strcat(afl->mutation, afl->m_tmp); #endif - /* Head */ - - memcpy(temp_buf, out_buf, clone_to); - - /* Inserted part */ + /* Head */ - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + memcpy(temp_buf, out_buf, clone_to); - /* Tail */ - memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); + /* Inserted part */ - out_buf = temp_buf; - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - temp_len += clone_len; + memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); - } + /* Tail */ + memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); - break; + out_buf = temp_buf; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); + temp_len += clone_len; } - // end of default: + break; + + // end of default } -- cgit 1.4.1 From 1edc3ece6172be28802f1856bee758ff5acfd91c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Mar 2021 12:50:57 +0100 Subject: add introspection --- src/afl-fuzz-one.c | 20 +++++++++----------- src/afl-fuzz.c | 7 +++++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index e0d961ba..28ec0c46 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2376,8 +2376,7 @@ havoc_stage: #ifdef INTROSPECTION snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u", - actually_clone ? "clone" : "insert", clone_from, clone_to, - clone_len); + "clone", clone_from, clone_to, clone_len); strcat(afl->mutation, afl->m_tmp); #endif u8 *new_buf = @@ -2416,9 +2415,8 @@ havoc_stage: u32 clone_to = rand_below(afl, temp_len); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u", - actually_clone ? "clone" : "insert", clone_from, clone_to, - clone_len); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u", + "insert", clone_to, clone_len); strcat(afl->mutation, afl->m_tmp); #endif u8 *new_buf = @@ -2485,8 +2483,8 @@ havoc_stage: u32 copy_to = rand_below(afl, temp_len - copy_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u-%u", - copy_from, copy_to, copy_len); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u", + copy_to, copy_len); strcat(afl->mutation, afl->m_tmp); #endif memset(out_buf + copy_to, @@ -2600,8 +2598,8 @@ havoc_stage: u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO_EXTRA_OVERWRITE-%u-%u", - insert_at, extra_len); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); strcat(afl->mutation, afl->m_tmp); #endif memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, @@ -2618,8 +2616,8 @@ havoc_stage: u8 *ptr = afl->a_extras[use_extra].data; u32 insert_at = rand_below(afl, temp_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO_EXTRA_INSERT-%u-%u", - insert_at, extra_len); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len); strcat(afl->mutation, afl->m_tmp); #endif diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a7edb924..9bd7fca0 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1980,6 +1980,13 @@ int main(int argc, char **argv_orig, char **envp) { } + #ifdef INTROSPECTION + fprintf(afl->introspection_file, + "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n", + afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc, + afl->queued_paths); + #endif + if (afl->cycle_schedules) { /* we cannot mix non-AFLfast schedules with others */ -- cgit 1.4.1 From 7ca51fab19adfcda211282d4a1134eada7b60d2b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Mar 2021 12:53:09 +0100 Subject: ensure one fuzzer sync per cycle, cycle introspection --- docs/Changelog.md | 1 + include/afl-fuzz.h | 1 + src/afl-fuzz-run.c | 1 + src/afl-fuzz.c | 22 +++++++++++++++------- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6ae42b04..91d1a8cc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,6 +18,7 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - ensure one fuzzer sync per cycle - afl-cc: - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 046b0177..40a7fc85 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -572,6 +572,7 @@ typedef struct afl_state { blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ last_sync_time, /* Time of last sync */ + last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 83133dad..832f17bb 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -712,6 +712,7 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); afl->last_sync_time = get_cur_time(); + afl->last_sync_cycle = afl->queue_cycle; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a7edb924..9688c84f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1867,6 +1867,14 @@ int main(int argc, char **argv_orig, char **envp) { runs_in_current_cycle > afl->queued_paths) || (afl->old_seed_selection && !afl->queue_cur))) { + if (unlikely((afl->last_sync_cycle < afl->queue_cycle || + (!afl->queue_cycle && afl->afl_env.afl_import_first)) && + afl->sync_id)) { + + sync_fuzzers(afl); + + } + ++afl->queue_cycle; runs_in_current_cycle = (u32)-1; afl->cur_skipped_paths = 0; @@ -1980,6 +1988,13 @@ int main(int argc, char **argv_orig, char **envp) { } + #ifdef INTROSPECTION + fprintf(afl->introspection_file, + "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n", + afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc, + afl->queued_paths); + #endif + if (afl->cycle_schedules) { /* we cannot mix non-AFLfast schedules with others */ @@ -2031,13 +2046,6 @@ int main(int argc, char **argv_orig, char **envp) { prev_queued = afl->queued_paths; - if (afl->sync_id && afl->queue_cycle == 1 && - afl->afl_env.afl_import_first) { - - sync_fuzzers(afl); - - } - } ++runs_in_current_cycle; -- cgit 1.4.1 From 84a99f49b84b5380b9b2d79354bd9892216b180d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 29 Mar 2021 19:07:47 +0200 Subject: remove unneeded var --- instrumentation/afl-compiler-rt.o.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index f241447a..36b9c2f2 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -99,12 +99,10 @@ int __afl_selective_coverage_temp = 1; PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; PREV_LOC_T __afl_prev_caller[CTX_MAX_K]; u32 __afl_prev_ctx; -u32 __afl_cmp_counter; #else __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; __thread PREV_LOC_T __afl_prev_caller[CTX_MAX_K]; __thread u32 __afl_prev_ctx; -__thread u32 __afl_cmp_counter; #endif int __afl_sharedmem_fuzzing __attribute__((weak)); -- cgit 1.4.1 From 89eb285a232e4e5b421a98434d9c67444129bb97 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 30 Mar 2021 09:48:21 +0200 Subject: add parallel builds --- TODO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index b8a091ff..dc765ec4 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,7 @@ - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - cmplog: too much tainted bytes, directly add to dict and skip? - + - parallel builds for source-only targets ## Further down the road -- cgit 1.4.1 From 049ace8a4062a7b91b5750305bbf090113090bef Mon Sep 17 00:00:00 2001 From: "R. Elliott Childre" Date: Tue, 30 Mar 2021 10:54:04 -0400 Subject: Add network_proxy build targets to gitignore (#852) All other build targets in utils/ are ignored except for these due to the lack of file extension. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2aaaf9ef..c8d29e50 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,5 @@ libAFLQemuDriver.a test/.afl_performance gmon.out afl-frida-trace.so +utils/afl_network_proxy/afl-network-client +utils/afl_network_proxy/afl-network-server -- cgit 1.4.1 From 221616a1b78ed5bf77b880a7e9e10a671a0340d9 Mon Sep 17 00:00:00 2001 From: "R. Elliott Childre" Date: Tue, 30 Mar 2021 10:58:29 -0400 Subject: Fixes: 6d2ac3e3140 ("fix grammar download script") The git submodle entry point is "grammar_mutator" not "grammar-mutator" The build script fails without this --- custom_mutators/grammar_mutator/build_grammar_mutator.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/custom_mutators/grammar_mutator/build_grammar_mutator.sh b/custom_mutators/grammar_mutator/build_grammar_mutator.sh index ef145dfe..b6cef66f 100755 --- a/custom_mutators/grammar_mutator/build_grammar_mutator.sh +++ b/custom_mutators/grammar_mutator/build_grammar_mutator.sh @@ -106,23 +106,23 @@ git status 1>/dev/null 2>/dev/null if [ $? -eq 0 ]; then echo "[*] initializing grammar mutator submodule" git submodule init || exit 1 - git submodule update ./grammar-mutator 2>/dev/null # ignore errors + git submodule update ./grammar_mutator 2>/dev/null # ignore errors else echo "[*] cloning grammar mutator" - test -d grammar-mutator || { + test -d grammar_mutator || { CNT=1 - while [ '!' -d grammar-mutator -a "$CNT" -lt 4 ]; do - echo "Trying to clone grammar-mutator (attempt $CNT/3)" + while [ '!' -d grammar_mutator -a "$CNT" -lt 4 ]; do + echo "Trying to clone grammar_mutator (attempt $CNT/3)" git clone "$GRAMMAR_REPO" CNT=`expr "$CNT" + 1` done } fi -test -d grammar-mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; } +test -d grammar_mutator || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; } echo "[+] Got grammar mutator." -cd "grammar-mutator" || exit 1 +cd "grammar_mutator" || exit 1 echo "[*] Checking out $GRAMMAR_VERSION" sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null git checkout "$GRAMMAR_VERSION" || exit 1 @@ -134,7 +134,7 @@ echo echo echo "[+] All successfully prepared!" echo "[!] To build for your grammar just do:" -echo " cd grammar-mutator" +echo " cd grammar_mutator" echo " make GRAMMAR_FILE=/path/to/your/grammar" -echo "[+] You will find a JSON and RUBY grammar in grammar-mutator/grammars to play with." +echo "[+] You will find a JSON and RUBY grammar in grammar_mutator/grammars to play with." echo -- cgit 1.4.1 From 1004fb9a41df364818c5034e8b95b4c00583335f Mon Sep 17 00:00:00 2001 From: Jiangen Jiao Date: Wed, 31 Mar 2021 15:44:27 +0800 Subject: fix #if A == B always evalutes to true --- Android.bp | 1 - utils/afl_frida/afl-frida.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Android.bp b/Android.bp index 64794e19..bf37757d 100644 --- a/Android.bp +++ b/Android.bp @@ -32,7 +32,6 @@ cc_defaults { target: { android_arm64: { cflags: [ - "-D__aarch64__", "-D__ANDROID__", ], }, diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c index 711d8f33..e49d6f42 100644 --- a/utils/afl_frida/afl-frida.c +++ b/utils/afl_frida/afl-frida.c @@ -111,7 +111,7 @@ inline static void afl_maybe_log(guint64 current_pc) { } -#if GUM_NATIVE_CPU == GUM_CPU_AMD64 +#ifdef __x86_64__ static const guint8 afl_maybe_log_code[] = { @@ -177,7 +177,7 @@ void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, if (instr->address >= range->code_start && instr->address <= range->code_end) { -#if GUM_NATIVE_CPU == GUM_CPU_AMD64 +#ifdef __x86_64__ GumX86Writer *cw = output->writer.x86; if (range->current_log_impl == 0 || !gum_x86_writer_can_branch_directly_between( -- cgit 1.4.1 From e20f0bf0ea555eb60a393377d6bfe8d379e15135 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 1 Apr 2021 12:33:45 +0200 Subject: try to avoid CI build failure by updating apt packages --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31cfceaf..a5f3429e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ jobs: - uses: actions/checkout@v2 - name: debug run: apt-cache search plugin-dev | grep gcc- ; echo ; apt-cache search clang-format- | grep clang-format- + - name: update + run: sudo apt-get update && sudo apt-get upgrade -y - name: install packages run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools - name: compiler installed -- cgit 1.4.1 From 3ff4ca348c344bded53f53b0d0c4b020a188f26e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 2 Apr 2021 14:39:56 +0200 Subject: fix k-ctx --- src/afl-cc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/afl-cc.c b/src/afl-cc.c index 3f75c549..b354077e 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1442,9 +1442,11 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0) { + if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 || + strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 || + strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) { - u8 *ptr3 = ptr2 + strlen("ctx-"); + u8 *ptr3 = ptr2; while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) ptr3++; @@ -1480,7 +1482,7 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) { + if (strcasecmp(ptr2, "ctx") == 0) { instrument_opt_mode |= INSTRUMENT_OPT_CTX; setenv("AFL_LLVM_CTX", "1", 1); -- cgit 1.4.1 From 565f61a6abc30dfb4df0269384466589690fbae5 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Fri, 2 Apr 2021 20:09:16 +0400 Subject: Initialalize the autodict-ql Initialalize the autodict-ql add codeql scripts --- utils/autodict_ql/litool.ql | 10 ++++++++++ utils/autodict_ql/memcmp-str.ql | 8 ++++++++ utils/autodict_ql/strcmp-str.ql | 8 ++++++++ utils/autodict_ql/strncmp-str.ql | 8 ++++++++ utils/autodict_ql/strtool.ql | 24 ++++++++++++++++++++++++ 5 files changed, 58 insertions(+) create mode 100644 utils/autodict_ql/litool.ql create mode 100644 utils/autodict_ql/memcmp-str.ql create mode 100644 utils/autodict_ql/strcmp-str.ql create mode 100644 utils/autodict_ql/strncmp-str.ql create mode 100644 utils/autodict_ql/strtool.ql diff --git a/utils/autodict_ql/litool.ql b/utils/autodict_ql/litool.ql new file mode 100644 index 00000000..b7f4bf33 --- /dev/null +++ b/utils/autodict_ql/litool.ql @@ -0,0 +1,10 @@ +import cpp + +class HexOrOctLiteral extends Literal{ + HexOrOctLiteral(){ + (this instanceof HexLiteral) or (this instanceof OctalLiteral) + } +} + +from HexOrOctLiteral lit +select lit.getValueText() \ No newline at end of file diff --git a/utils/autodict_ql/memcmp-str.ql b/utils/autodict_ql/memcmp-str.ql new file mode 100644 index 00000000..830c9cac --- /dev/null +++ b/utils/autodict_ql/memcmp-str.ql @@ -0,0 +1,8 @@ +import cpp + +/// function : memcmp trace + +from FunctionCall fucall, Expr size +where + fucall.getTarget().hasName("memcmp") +select fucall.getArgument(_).getValueText() \ No newline at end of file diff --git a/utils/autodict_ql/strcmp-str.ql b/utils/autodict_ql/strcmp-str.ql new file mode 100644 index 00000000..83ffadaf --- /dev/null +++ b/utils/autodict_ql/strcmp-str.ql @@ -0,0 +1,8 @@ +import cpp + +/// function : strcmp + +from FunctionCall fucall, Expr size +where + fucall.getTarget().hasName("strcmp") +select fucall.getArgument(_).getValueText() \ No newline at end of file diff --git a/utils/autodict_ql/strncmp-str.ql b/utils/autodict_ql/strncmp-str.ql new file mode 100644 index 00000000..dbb952e5 --- /dev/null +++ b/utils/autodict_ql/strncmp-str.ql @@ -0,0 +1,8 @@ +import cpp + +/// function : strncmp + +from FunctionCall fucall, Expr size +where + fucall.getTarget().hasName("strncmp") +select fucall.getArgument(_).getValueText() \ No newline at end of file diff --git a/utils/autodict_ql/strtool.ql b/utils/autodict_ql/strtool.ql new file mode 100644 index 00000000..f78aabbb --- /dev/null +++ b/utils/autodict_ql/strtool.ql @@ -0,0 +1,24 @@ +import cpp +import semmle.code.cpp.dataflow.DataFlow +class StringLiteralNode extends DataFlow::Node { + StringLiteralNode() { this.asExpr() instanceof StringLiteral } +} +class MemcmpArgNode extends DataFlow::Node { + MemcmpArgNode() { + exists(FunctionCall fc | + fc.getTarget().getName().regexpMatch(".*(str|mem|strn|b)*(cmp|str)*") and + fc.getArgument(0) = this.asExpr() + ) + or + exists(FunctionCall fc | + fc.getTarget().getName().regexpMatch(".*(str|mem|strn|b)*(cmp|str)*") and + fc.getArgument(1) = this.asExpr() + ) + } +} + +from StringLiteralNode src, MemcmpArgNode arg +where + DataFlow::localFlow(src, arg) + +select src.asExpr().(StringLiteral).toString() \ No newline at end of file -- cgit 1.4.1 From a26ed3b7580e31b6f6f174169528fc0bebe20ad6 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:02:45 +0400 Subject: update the codes, readme - add readme - add required qlpack.yml --- utils/autodict_ql/autodict_ql.py | 188 ++++++++++++++++++++++++++++++++++++++ utils/autodict_ql/build-codeql.sh | 17 ++++ utils/autodict_ql/litan.py | 86 +++++++++++++++++ utils/autodict_ql/qlpack.yml | 3 + utils/autodict_ql/readme.md | 81 ++++++++++++++++ utils/autodict_ql/strtool.ql | 6 +- 6 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 utils/autodict_ql/autodict_ql.py create mode 100644 utils/autodict_ql/build-codeql.sh create mode 100644 utils/autodict_ql/litan.py create mode 100644 utils/autodict_ql/qlpack.yml create mode 100644 utils/autodict_ql/readme.md diff --git a/utils/autodict_ql/autodict_ql.py b/utils/autodict_ql/autodict_ql.py new file mode 100644 index 00000000..69d11f48 --- /dev/null +++ b/utils/autodict_ql/autodict_ql.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import shutil +import subprocess + +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + + #parser.add_argument("tokenpath", + #help="Destination directory for tokens") + parser.add_argument("cur", + help = "Current Path") + parser.add_argument("db", + help = "CodeQL database Path") + parser.add_argument("tokenpath", + help="Destination directory for tokens") + + return parser.parse_args() + +def static_analysis(file,file2,cur,db) : + with open(cur+"/"+file, "w") as f: + print(cur+"/"+file) + stream = os.popen("codeql query run " + cur +"/"+ file2 + " -d " + db ) + output = stream.read() + f.write(output) + f.close() + +def copy_tokens(cur, tokenpath) : + subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strstr-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "local-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "global-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "arrays-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + #strtool-strs + + +def codeql_analysis(cur, db) : + static_analysis("litout.out","litool.ql", cur, db) + static_analysis("strcmp-strings.out","strcmp-str.ql", cur, db) + static_analysis("strncmp-strings.out","strncmp-str.ql", cur, db) + static_analysis("strstr-strings.out","strstr-str.ql", cur, db) + static_analysis("memcmp-strings.out","memcmp-str.ql", cur, db) + static_analysis("global-values-strings.out","globals-values.ql", cur, db) + static_analysis("local-strings.out","locals-strs.ql", cur, db) + static_analysis("strtool-strings.out","strtool.ql", cur, db) + static_analysis("arrays.out","array-literals.ql", cur, db) + start_aflql(0,cur) + #command1 = [ + # 'codeql','query', 'run', + # cur + '/litool.ql', + # '-d', + # db, '>','fff.txt' + # ] + #with open("litool2.log", "w") as f: + # stream = os.popen("codeql query run litool.ql -d " + db ) + # output = stream.read() + # f.write(output) + # f.close() + #worker1 = subprocess.Popen(command1) + #print(worker1.communicate()) + + +def start_aflql(tokenpath, cur): + command = [ + 'python3', + cur + '/litan.py', + cur+'/lits/', + cur+'/litout.out' + ] + worker1 = subprocess.Popen(command) + print(worker1.communicate()) + + command1 = [ + 'python3', + cur + '/strcmp-strings.py', + cur + '/strcmp-strs/', + cur + '/strcmp-strings.out' + ] + worker2 = subprocess.Popen(command1) + print(worker2.communicate()) + + command2 = [ + 'python3', + cur + '/strncmp-strings.py', + cur + '/strncmp-strs/', + cur + '/strncmp-strings.out' + ] + worker3 = subprocess.Popen(command2) + print(worker3.communicate()) + + command3 = [ + 'python3', + cur + '/array-lits.py', + cur + '/arrays-lits/', + cur + '/arrays.out' + ] + worker4 = subprocess.Popen(command3) + print(worker4.communicate()) + + command4 = [ + 'python3', + cur + '/array-strings.py', + cur + '/arrays-strs/', + cur + '/arrays.out' + ] + worker5 = subprocess.Popen(command4) + print(worker5.communicate()) + + + command5 = [ + 'python3', + cur + '/memcmp-strings.py', + cur + '/memcmp-strs/', + cur + '/memcmp-strings.out' + ] + worker6 = subprocess.Popen(command5) + print(worker6.communicate()) + + command6 = [ + 'python3', + cur + '/globals-strings.py', + cur + '/global-strs/', + cur + '/global-values-strings.out' + ] + worker7 = subprocess.Popen(command6) + print(worker7.communicate()) + + command7 = [ + 'python3', + cur + '/strstr-strings.py', + cur + '/strstr-strs/', + cur + '/strstr-strings.out' + ] + worker8 = subprocess.Popen(command7) + print(worker8.communicate()) + + + #strtool-strings.out + + command8 = [ + 'python3', + cur + '/stan-strings.py', + cur + '/strtool-strs/', + cur + '/strtool-strings.out' + ] + worker9 = subprocess.Popen(command8) + print(worker9.communicate()) + + command9 = [ + 'python3', + cur + '/local-strings.py', + cur + '/local-strs/', + cur + '/local-strings.out' + ] + worker10 = subprocess.Popen(command9) + print(worker10.communicate()) + +def main(): + args = parse_args() + ensure_dir(args.tokenpath) + #copy_tokens(args.cur, args.tokenpath) + codeql_analysis(args.cur, args.db) + copy_tokens(args.cur, args.tokenpath) + #start_aflql(args.tokenpath, args.cur) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/build-codeql.sh b/utils/autodict_ql/build-codeql.sh new file mode 100644 index 00000000..ccff932e --- /dev/null +++ b/utils/autodict_ql/build-codeql.sh @@ -0,0 +1,17 @@ +cd ~ +if [ -d "codeql-home" ]; then + echo "Exist !" + exit 1 +fi +sudo apt install build-essential libtool-bin python3-dev automake git vim wget -y +mkdir codeql-home +cd codeql-home +git clone https://github.com/github/codeql.git codeql-repo +git clone https://github.com/github/codeql-go.git +wget https://github.com/github/codeql-cli-binaries/releases/download/v2.4.6/codeql-linux64.zip +unzip codeql-linux64.zip +mv codeql codeql-cli +export "PATH=~/codeql-home/codeql-cli/:$PATH" +codeql resolve languages +codeql resolve qlpacks +echo "export PATH=~/codeql-home/codeql-cli/:$PATH" >> ~/.bashrc \ No newline at end of file diff --git a/utils/autodict_ql/litan.py b/utils/autodict_ql/litan.py new file mode 100644 index 00000000..18c04c34 --- /dev/null +++ b/utils/autodict_ql/litan.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Autodict-QL - Optimal token generation for fuzzing +# Part of AFL++ Project +# Author : Microsvuln - Arash.vre@gmail.com +import string +import os +import binascii +import codecs +import struct +import errno +import argparse +import re +import base64 +from binascii import unhexlify +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt")) + parser.add_argument("corpdir", + help="The path to the corpus directory to generate files.") + parser.add_argument("infile", + help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt") + return parser.parse_args() +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno == errno.EEXIST: + #print "[-] Directory exists, specify another directory" + exit(1) +def do_analysis1(corpdir, infile): + with open(infile, "rb") as f: + lines = f.readlines()[1:] + f.close() + new_lst = [] + n = 1 + for i, num in enumerate(lines): + if i != 0: + new_lst.append(num) + str1 = str(num) + print ("num is " + str1) + str1 = str1.rstrip('\n\n') + #str1 = str1.replace("0x",""); + str1 = str1.replace("|","") + str1 = str1.rstrip('\r\n') + str1 = str1.rstrip('\n') + str1 = str1.replace(" ","") + #str1 = str1.translate(None, string.punctuation) + translator=str.maketrans('','',string.punctuation) + str1=str1.translate(translator) + str1 = str1[1:] + str1 = str1[:-1] + print("After cleanup : " + str1) + if (str1 != '0') and (str1 != 'ffffffff') and (str1 != 'fffffffe') or (len(str1) == 4) or (len(str1) == 8): + print ("first : "+str1) + if len(str1) > 8 : + str1 = str1[:-1] + elif (len(str1) == 5) : + str1 = str1 = "0" + try: + #str1 = str1.decode("hex") + with open(corpdir+'/lit-seed{0}'.format(n), 'w') as file: + str1 = str1.replace("0x",""); + print (str1) + str1 = int(str1,base=16) + str1 = str1.to_bytes(4, byteorder='little') + file.write(str(str1)) + file.close() + with open (corpdir+'/lit-seed{0}'.format(n), 'r') as q : + a = q.readline() + a = a[1:] + print ("AFL++ Autodict-QL by Microsvuln : Writing Token :" + str(a)) + q.close() + with open (corpdir+'/lit-seed{0}'.format(n), 'w') as w1 : + w1.write(str(a)) + print ("Done!") + w1.close() + except: + print("Error!") + n = n+1 + +def main(): + args = parse_args() + ensure_dir(args.corpdir) + do_analysis1(args.corpdir, args.infile) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/qlpack.yml b/utils/autodict_ql/qlpack.yml new file mode 100644 index 00000000..c037a344 --- /dev/null +++ b/utils/autodict_ql/qlpack.yml @@ -0,0 +1,3 @@ +name: automate +version: 0.0.0 +libraryPathDependencies: codeql-cpp diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md new file mode 100644 index 00000000..77a15f8e --- /dev/null +++ b/utils/autodict_ql/readme.md @@ -0,0 +1,81 @@ +# Autodict-QL - Optimal Token Generation for Fuzzing + +## What is this? + +Autodict-QL is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (Unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses the CodeQL (A powerful semantic code analysis engine) to fetch information from a code base. + +Tokens are useful when you perform fuzzing on different parsers. AFL++ `-x` switch enables the usage of dictionaries through your fuzzing campagin. if you are not familiar with Dictionaries in fuzzing, take a look [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries) . + + +## Why CodeQL ? +We basically developed this plugin on top of CodeQL engine because it gives the user scripting features, it's easier and it's independent of the LLVM system. This means that a user can write his CodeQL scripts or modify the current scripts to improve or change the token generation algorithms based on different program analysis concepts. + + +## CodeQL scripts +Currently, we pushed some scripts as defaults for Token generation. In addition, we provide every CodeQL script as an standalone script because it's easier to modify or test. + +Currently we provided the following CodeQL scripts : + +`strcmp-str.ql` is used to extract strings that are related to `strcmp` function. + +`strncmp-str.ql` is used to extract the strings from the `strncmp` function. + +`memcmp-str.ql` is used to extract the strings from the `memcmp` function. + +`litool.ql` extracts Magic numbers as Hexadecimal format. + +`strtool.ql` extracts strings with uses of a regex and dataflow concept to capture the string comparison functions. if strcmp is rewritten in a project as Mystrcmp or something like strmycmp, then this script can catch the arguments and these are valuable tokens. + +You can write other CodeQL scripts to extract possible effective tokens if you think they can be useful. + + +## Usage +The usage of Autodict-QL is pretty easy. But let's describe it as : + +1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system, so : + +` # chmod +x codeql-build.sh` + +` # codeql ` + +Then you should get : + +` Usage: codeql ... +Create and query CodeQL databases, or work with the QL language. + +GitHub makes this program freely available for the analysis of open-source software and certain other uses, but it is +not itself free software. Type codeql --license to see the license terms. + + --license Show the license terms for the CodeQL toolchain. +Common options: + -h, --help Show this help text. + -v, --verbose Incrementally increase the number of progress messages printed. + -q, --quiet Incrementally decrease the number of progress messages printed. +Some advanced options have been hidden; try --help -v for a fuller view. +Commands: + query Compile and execute QL code. + bqrs Get information from .bqrs files. + database Create, analyze and process CodeQL databases. + dataset [Plumbing] Work with raw QL datasets. + test Execute QL unit tests. + resolve [Deep plumbing] Helper commands to resolve disk locations etc. + execute [Deep plumbing] Low-level commands that need special JVM options. + version Show the version of the CodeQL toolchain. + generate Generate formatted QL documentation. + github Commands useful for interacting with the GitHub API through CodeQL. +` + +2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . + - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: + - `./configure --disable-shared` + - `codeql create database libxml-db --language=cpp --command=make + - Now you have the CodeQL database of the project :-) +3. To run the Autodict-QL, the final step is to just create a folder named `automate` in the project you want to fuzz. + - `mkdir automate` (inside the libxml directory) +4. The final step is to update the CodeQL database you created in the step 2 inside the automate dir you created at step 3 : + - `codeql database upgrade ../libxml-db` +5. Everything is set! :-), now you should issue the following to get the tokens : + - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` + - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` + - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. +6. Done! \ No newline at end of file diff --git a/utils/autodict_ql/strtool.ql b/utils/autodict_ql/strtool.ql index f78aabbb..253d1555 100644 --- a/utils/autodict_ql/strtool.ql +++ b/utils/autodict_ql/strtool.ql @@ -3,8 +3,8 @@ import semmle.code.cpp.dataflow.DataFlow class StringLiteralNode extends DataFlow::Node { StringLiteralNode() { this.asExpr() instanceof StringLiteral } } -class MemcmpArgNode extends DataFlow::Node { - MemcmpArgNode() { +class CmpArgNode extends DataFlow::Node { + CmpArgNode() { exists(FunctionCall fc | fc.getTarget().getName().regexpMatch(".*(str|mem|strn|b)*(cmp|str)*") and fc.getArgument(0) = this.asExpr() @@ -17,7 +17,7 @@ class MemcmpArgNode extends DataFlow::Node { } } -from StringLiteralNode src, MemcmpArgNode arg +from StringLiteralNode src, CmpArgNode arg where DataFlow::localFlow(src, arg) -- cgit 1.4.1 From 6088a0d4c2aeada7d952ce05bc1e683b858b1ade Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:04:17 +0400 Subject: update readme update readme --- utils/autodict_ql/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 77a15f8e..a610afb7 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -40,7 +40,7 @@ The usage of Autodict-QL is pretty easy. But let's describe it as : Then you should get : -` Usage: codeql ... +' Usage: codeql ... Create and query CodeQL databases, or work with the QL language. GitHub makes this program freely available for the analysis of open-source software and certain other uses, but it is @@ -63,7 +63,7 @@ Commands: version Show the version of the CodeQL toolchain. generate Generate formatted QL documentation. github Commands useful for interacting with the GitHub API through CodeQL. -` +' 2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: -- cgit 1.4.1 From cabde32140d6b781fea3c81e535b717bd01b1ec7 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:06:18 +0400 Subject: Update readme Update readme --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index a610afb7..82aa0a23 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -68,7 +68,7 @@ Commands: 2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: - `./configure --disable-shared` - - `codeql create database libxml-db --language=cpp --command=make + - `codeql create database libxml-db --language=cpp --command=make` - Now you have the CodeQL database of the project :-) 3. To run the Autodict-QL, the final step is to just create a folder named `automate` in the project you want to fuzz. - `mkdir automate` (inside the libxml directory) -- cgit 1.4.1 From 01658fb2e8d923c2d3df225249d9e8e0931511e8 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:07:24 +0400 Subject: Update readme Update readme --- utils/autodict_ql/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 82aa0a23..e8d3c761 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -70,8 +70,8 @@ Commands: - `./configure --disable-shared` - `codeql create database libxml-db --language=cpp --command=make` - Now you have the CodeQL database of the project :-) -3. To run the Autodict-QL, the final step is to just create a folder named `automate` in the project you want to fuzz. - - `mkdir automate` (inside the libxml directory) +3. To run the Autodict-QL, the final step is to just create a folder named `automate` in the project you want to fuzz. (inside the libxml directory) + - `mkdir automate` 4. The final step is to update the CodeQL database you created in the step 2 inside the automate dir you created at step 3 : - `codeql database upgrade ../libxml-db` 5. Everything is set! :-), now you should issue the following to get the tokens : -- cgit 1.4.1 From 7a383342de6687a09b46151c1f3cf0d44810995a Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:07:52 +0400 Subject: rename python file rename python file --- utils/autodict_ql/autodict-ql.py | 188 +++++++++++++++++++++++++++++++++++++++ utils/autodict_ql/autodict_ql.py | 188 --------------------------------------- 2 files changed, 188 insertions(+), 188 deletions(-) create mode 100644 utils/autodict_ql/autodict-ql.py delete mode 100644 utils/autodict_ql/autodict_ql.py diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py new file mode 100644 index 00000000..69d11f48 --- /dev/null +++ b/utils/autodict_ql/autodict-ql.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import shutil +import subprocess + +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + + #parser.add_argument("tokenpath", + #help="Destination directory for tokens") + parser.add_argument("cur", + help = "Current Path") + parser.add_argument("db", + help = "CodeQL database Path") + parser.add_argument("tokenpath", + help="Destination directory for tokens") + + return parser.parse_args() + +def static_analysis(file,file2,cur,db) : + with open(cur+"/"+file, "w") as f: + print(cur+"/"+file) + stream = os.popen("codeql query run " + cur +"/"+ file2 + " -d " + db ) + output = stream.read() + f.write(output) + f.close() + +def copy_tokens(cur, tokenpath) : + subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strstr-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "local-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "global-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "arrays-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + #strtool-strs + + +def codeql_analysis(cur, db) : + static_analysis("litout.out","litool.ql", cur, db) + static_analysis("strcmp-strings.out","strcmp-str.ql", cur, db) + static_analysis("strncmp-strings.out","strncmp-str.ql", cur, db) + static_analysis("strstr-strings.out","strstr-str.ql", cur, db) + static_analysis("memcmp-strings.out","memcmp-str.ql", cur, db) + static_analysis("global-values-strings.out","globals-values.ql", cur, db) + static_analysis("local-strings.out","locals-strs.ql", cur, db) + static_analysis("strtool-strings.out","strtool.ql", cur, db) + static_analysis("arrays.out","array-literals.ql", cur, db) + start_aflql(0,cur) + #command1 = [ + # 'codeql','query', 'run', + # cur + '/litool.ql', + # '-d', + # db, '>','fff.txt' + # ] + #with open("litool2.log", "w") as f: + # stream = os.popen("codeql query run litool.ql -d " + db ) + # output = stream.read() + # f.write(output) + # f.close() + #worker1 = subprocess.Popen(command1) + #print(worker1.communicate()) + + +def start_aflql(tokenpath, cur): + command = [ + 'python3', + cur + '/litan.py', + cur+'/lits/', + cur+'/litout.out' + ] + worker1 = subprocess.Popen(command) + print(worker1.communicate()) + + command1 = [ + 'python3', + cur + '/strcmp-strings.py', + cur + '/strcmp-strs/', + cur + '/strcmp-strings.out' + ] + worker2 = subprocess.Popen(command1) + print(worker2.communicate()) + + command2 = [ + 'python3', + cur + '/strncmp-strings.py', + cur + '/strncmp-strs/', + cur + '/strncmp-strings.out' + ] + worker3 = subprocess.Popen(command2) + print(worker3.communicate()) + + command3 = [ + 'python3', + cur + '/array-lits.py', + cur + '/arrays-lits/', + cur + '/arrays.out' + ] + worker4 = subprocess.Popen(command3) + print(worker4.communicate()) + + command4 = [ + 'python3', + cur + '/array-strings.py', + cur + '/arrays-strs/', + cur + '/arrays.out' + ] + worker5 = subprocess.Popen(command4) + print(worker5.communicate()) + + + command5 = [ + 'python3', + cur + '/memcmp-strings.py', + cur + '/memcmp-strs/', + cur + '/memcmp-strings.out' + ] + worker6 = subprocess.Popen(command5) + print(worker6.communicate()) + + command6 = [ + 'python3', + cur + '/globals-strings.py', + cur + '/global-strs/', + cur + '/global-values-strings.out' + ] + worker7 = subprocess.Popen(command6) + print(worker7.communicate()) + + command7 = [ + 'python3', + cur + '/strstr-strings.py', + cur + '/strstr-strs/', + cur + '/strstr-strings.out' + ] + worker8 = subprocess.Popen(command7) + print(worker8.communicate()) + + + #strtool-strings.out + + command8 = [ + 'python3', + cur + '/stan-strings.py', + cur + '/strtool-strs/', + cur + '/strtool-strings.out' + ] + worker9 = subprocess.Popen(command8) + print(worker9.communicate()) + + command9 = [ + 'python3', + cur + '/local-strings.py', + cur + '/local-strs/', + cur + '/local-strings.out' + ] + worker10 = subprocess.Popen(command9) + print(worker10.communicate()) + +def main(): + args = parse_args() + ensure_dir(args.tokenpath) + #copy_tokens(args.cur, args.tokenpath) + codeql_analysis(args.cur, args.db) + copy_tokens(args.cur, args.tokenpath) + #start_aflql(args.tokenpath, args.cur) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/autodict_ql.py b/utils/autodict_ql/autodict_ql.py deleted file mode 100644 index 69d11f48..00000000 --- a/utils/autodict_ql/autodict_ql.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python3 -import os -import string -import binascii -import codecs -import errno -import struct -import argparse -import shutil -import subprocess - -from binascii import unhexlify - -def ensure_dir(dir): - try: - os.makedirs(dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise - -def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - - #parser.add_argument("tokenpath", - #help="Destination directory for tokens") - parser.add_argument("cur", - help = "Current Path") - parser.add_argument("db", - help = "CodeQL database Path") - parser.add_argument("tokenpath", - help="Destination directory for tokens") - - return parser.parse_args() - -def static_analysis(file,file2,cur,db) : - with open(cur+"/"+file, "w") as f: - print(cur+"/"+file) - stream = os.popen("codeql query run " + cur +"/"+ file2 + " -d " + db ) - output = stream.read() - f.write(output) - f.close() - -def copy_tokens(cur, tokenpath) : - subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strstr-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "local-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "global-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "arrays-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - #strtool-strs - - -def codeql_analysis(cur, db) : - static_analysis("litout.out","litool.ql", cur, db) - static_analysis("strcmp-strings.out","strcmp-str.ql", cur, db) - static_analysis("strncmp-strings.out","strncmp-str.ql", cur, db) - static_analysis("strstr-strings.out","strstr-str.ql", cur, db) - static_analysis("memcmp-strings.out","memcmp-str.ql", cur, db) - static_analysis("global-values-strings.out","globals-values.ql", cur, db) - static_analysis("local-strings.out","locals-strs.ql", cur, db) - static_analysis("strtool-strings.out","strtool.ql", cur, db) - static_analysis("arrays.out","array-literals.ql", cur, db) - start_aflql(0,cur) - #command1 = [ - # 'codeql','query', 'run', - # cur + '/litool.ql', - # '-d', - # db, '>','fff.txt' - # ] - #with open("litool2.log", "w") as f: - # stream = os.popen("codeql query run litool.ql -d " + db ) - # output = stream.read() - # f.write(output) - # f.close() - #worker1 = subprocess.Popen(command1) - #print(worker1.communicate()) - - -def start_aflql(tokenpath, cur): - command = [ - 'python3', - cur + '/litan.py', - cur+'/lits/', - cur+'/litout.out' - ] - worker1 = subprocess.Popen(command) - print(worker1.communicate()) - - command1 = [ - 'python3', - cur + '/strcmp-strings.py', - cur + '/strcmp-strs/', - cur + '/strcmp-strings.out' - ] - worker2 = subprocess.Popen(command1) - print(worker2.communicate()) - - command2 = [ - 'python3', - cur + '/strncmp-strings.py', - cur + '/strncmp-strs/', - cur + '/strncmp-strings.out' - ] - worker3 = subprocess.Popen(command2) - print(worker3.communicate()) - - command3 = [ - 'python3', - cur + '/array-lits.py', - cur + '/arrays-lits/', - cur + '/arrays.out' - ] - worker4 = subprocess.Popen(command3) - print(worker4.communicate()) - - command4 = [ - 'python3', - cur + '/array-strings.py', - cur + '/arrays-strs/', - cur + '/arrays.out' - ] - worker5 = subprocess.Popen(command4) - print(worker5.communicate()) - - - command5 = [ - 'python3', - cur + '/memcmp-strings.py', - cur + '/memcmp-strs/', - cur + '/memcmp-strings.out' - ] - worker6 = subprocess.Popen(command5) - print(worker6.communicate()) - - command6 = [ - 'python3', - cur + '/globals-strings.py', - cur + '/global-strs/', - cur + '/global-values-strings.out' - ] - worker7 = subprocess.Popen(command6) - print(worker7.communicate()) - - command7 = [ - 'python3', - cur + '/strstr-strings.py', - cur + '/strstr-strs/', - cur + '/strstr-strings.out' - ] - worker8 = subprocess.Popen(command7) - print(worker8.communicate()) - - - #strtool-strings.out - - command8 = [ - 'python3', - cur + '/stan-strings.py', - cur + '/strtool-strs/', - cur + '/strtool-strings.out' - ] - worker9 = subprocess.Popen(command8) - print(worker9.communicate()) - - command9 = [ - 'python3', - cur + '/local-strings.py', - cur + '/local-strs/', - cur + '/local-strings.out' - ] - worker10 = subprocess.Popen(command9) - print(worker10.communicate()) - -def main(): - args = parse_args() - ensure_dir(args.tokenpath) - #copy_tokens(args.cur, args.tokenpath) - codeql_analysis(args.cur, args.db) - copy_tokens(args.cur, args.tokenpath) - #start_aflql(args.tokenpath, args.cur) -if __name__ == '__main__': - main() \ No newline at end of file -- cgit 1.4.1 From 67989e9f2acb5e39e9ef422c27f0fe9db3f7da95 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:09:38 +0400 Subject: update update --- utils/autodict_ql/readme.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index e8d3c761..b368002c 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -40,7 +40,8 @@ The usage of Autodict-QL is pretty easy. But let's describe it as : Then you should get : -' Usage: codeql ... +" +Usage: codeql ... Create and query CodeQL databases, or work with the QL language. GitHub makes this program freely available for the analysis of open-source software and certain other uses, but it is @@ -63,7 +64,7 @@ Commands: version Show the version of the CodeQL toolchain. generate Generate formatted QL documentation. github Commands useful for interacting with the GitHub API through CodeQL. -' +" 2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: @@ -74,7 +75,7 @@ Commands: - `mkdir automate` 4. The final step is to update the CodeQL database you created in the step 2 inside the automate dir you created at step 3 : - `codeql database upgrade ../libxml-db` -5. Everything is set! :-), now you should issue the following to get the tokens : +5. Everything is set! Now you should issue the following to get the tokens : - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. -- cgit 1.4.1 From c4f418c3b27bad3cc61eb61e7b9cf6fb7bbe6868 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:12:24 +0400 Subject: Add shell command Add shell command --- utils/autodict_ql/readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index b368002c..c9c0d2d0 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -40,7 +40,7 @@ The usage of Autodict-QL is pretty easy. But let's describe it as : Then you should get : -" +```shell Usage: codeql ... Create and query CodeQL databases, or work with the QL language. @@ -64,7 +64,7 @@ Commands: version Show the version of the CodeQL toolchain. generate Generate formatted QL documentation. github Commands useful for interacting with the GitHub API through CodeQL. -" +``` 2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: @@ -76,7 +76,7 @@ Commands: 4. The final step is to update the CodeQL database you created in the step 2 inside the automate dir you created at step 3 : - `codeql database upgrade ../libxml-db` 5. Everything is set! Now you should issue the following to get the tokens : - - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` - - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. + - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` + - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` + - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. 6. Done! \ No newline at end of file -- cgit 1.4.1 From bc99b5ba03815e2cfd2a6314a2fa9da78baa6fb6 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:13:18 +0400 Subject: update readme update readme --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index c9c0d2d0..c8e5556f 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -2,7 +2,7 @@ ## What is this? -Autodict-QL is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (Unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses the CodeQL (A powerful semantic code analysis engine) to fetch information from a code base. +`Autodict-QL` is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (Unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses the CodeQL (A powerful semantic code analysis engine) to fetch information from a code base. Tokens are useful when you perform fuzzing on different parsers. AFL++ `-x` switch enables the usage of dictionaries through your fuzzing campagin. if you are not familiar with Dictionaries in fuzzing, take a look [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries) . -- cgit 1.4.1 From 920e9402a4d6101bbbed2ef7584d85a3c3de0eaa Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 2 Apr 2021 22:23:11 +0000 Subject: Add support for standalone leak-sanitizer, introducting the environment variable AFL_USE_LSAN. AFL_USE_LSAN introduces the macro __AFL_CHECK_LEAK() which will check for a memory leak when the macro is run. This is especially helpful when using __AFL_LOOP(). If __AFL_LEAK_CHECK() is not used when AFL_USE_LSAN=1 is set, the leak checker will run when the program exits. --- GNUmakefile | 4 ++-- README.md | 2 +- docs/env_variables.md | 20 ++++++++++++++++---- docs/notes_for_asan.md | 7 +++++++ include/config.h | 4 ++++ include/envs.h | 1 + src/afl-analyze.c | 19 +++++++++++++++++++ src/afl-as.c | 7 ++++--- src/afl-cc.c | 16 ++++++++++++++-- src/afl-forkserver.c | 17 +++++++++++++---- src/afl-fuzz-init.c | 17 ++++++++++++++++- src/afl-showmap.c | 4 ++++ src/afl-tmin.c | 18 ++++++++++++++++++ test/test-pre.sh | 1 + 14 files changed, 120 insertions(+), 17 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index f885f998..a6314a8b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -517,7 +517,7 @@ code-format: ifndef AFL_NO_X86 test_build: afl-cc afl-gcc afl-as afl-showmap @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." - @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) + @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @@ -525,7 +525,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap @echo @echo "[+] All right, the instrumentation of afl-cc seems to be working!" # @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." -# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) +# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr # @rm -f test-instr diff --git a/README.md b/README.md index 2528e1d1..41d55e9c 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; - export AFL_USE_CFISAN=1 ; ` + export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN`) * one should fuzz the target with CMPLOG/redqueen (see above) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV diff --git a/docs/env_variables.md b/docs/env_variables.md index c6ad0aa4..682ab7f1 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: overridden. - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - compiler supports that. Note that fuzzing with ASAN is mildly challenging + compiler supports itt. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the @@ -64,6 +64,13 @@ make fairly broad use of environmental variables instead: there is the Control Flow Integrity sanitizer that can be activated by `AFL_USE_CFISAN=1`) + - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided + that your compiler supports it. To perform a leak check within your + program at a certain point (such as at the end of an __AFL_LOOP, + you can run the macro __AFL_CHECK_LEAK(); which will cause + an abort if any memory is leaked (you can combine this with the + LSAN_OPTIONS=suppressions option to supress some known leaks). + - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries in your `$PATH`. @@ -628,7 +635,12 @@ optimal values if not already present in the environment: msan_track_origins=0 allocator_may_return_null=1 ``` - Be sure to include the first one when customizing anything, since some - MSAN versions don't call `abort()` on error, and we need a way to detect - faults. + - Similarly, the default `LSAN_OPTIONS` are set to: +``` + exit_code=86 + fast_unwind_on_malloc=0 +```` + Be sure to include the first ones for LSAN and MSAN when customizing + anything, since some MSAN and LSAN versions don't call `abort()` on + error, and we need a way to detect faults. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 2b3bc028..26f34fad 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that. (You can also use AFL_USE_MSAN=1 to enable MSAN instead.) +When compiling with AFL_USE_LSAN, the leak sanitizer will normally run +when the program exits. In order to utilize this check at different times, +such as at the end of a loop, you may use the macro __AFL_CHECK_LEAK();. +This macro will report a crash in afl-fuzz if any memory is left leaking +at this stage. You can also use LSAN_OPTIONS and a supressions file +for more fine-tuned checking, however make sure you keep exitcode=23. + NOTE: if you run several secondary instances, only one should run the target compiled with ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers compiled in. diff --git a/include/config.h b/include/config.h index 29225f6b..6490a5fe 100644 --- a/include/config.h +++ b/include/config.h @@ -393,6 +393,10 @@ #define MSAN_ERROR 86 +/* Distinctive exit code used to indicate LSAN trip condition: */ + +#define LSAN_ERROR 23 + /* Designated file descriptors for forkserver commands (the application will use FORKSRV_FD and FORKSRV_FD + 1): */ diff --git a/include/envs.h b/include/envs.h index 2ce50be7..d1856c50 100644 --- a/include/envs.h +++ b/include/envs.h @@ -172,6 +172,7 @@ static char *afl_environment_variables[] = { "AFL_USE_TRACE_PC", "AFL_USE_UBSAN", "AFL_USE_CFISAN", + "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 86b0f7e9..90305714 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -781,6 +781,19 @@ static void set_up_environment(void) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -818,6 +831,12 @@ static void set_up_environment(void) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(MSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + + if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-as.c b/src/afl-as.c index 7de267a3..dfae44f2 100644 --- a/src/afl-as.c +++ b/src/afl-as.c @@ -517,11 +517,12 @@ static void add_instrumentation(void) { } else { char modeline[100]; - snprintf(modeline, sizeof(modeline), "%s%s%s%s", + snprintf(modeline, sizeof(modeline), "%s%s%s%s%s", getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_USE_ASAN") ? ", ASAN" : "", getenv("AFL_USE_MSAN") ? ", MSAN" : "", - getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); + getenv("AFL_USE_UBSAN") ? ", UBSAN" : "", + getenv("AFL_USE_LSAN") ? ", LSAN" : ""); OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines, use_64bit ? "64" : "32", modeline, inst_ratio); @@ -585,7 +586,7 @@ int main(int argc, char **argv) { "AFL_QUIET: suppress verbose output\n" "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n" "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n" - "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN:\n" + "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n" " used in the instrumentation summary message\n", argv[0]); diff --git a/src/afl-cc.c b/src/afl-cc.c index 5251465b..e0478503 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) have_instr_list = 1; - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) + if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory"))) asan_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; @@ -817,6 +817,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; + } + if (getenv("AFL_USE_CFISAN")) { if (!lto_mode) { @@ -914,6 +918,13 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; + } + + cc_params[cc_par_cnt++] = + "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " "1;"; @@ -1740,7 +1751,8 @@ int main(int argc, char **argv, char **envp) { " AFL_USE_ASAN: activate address sanitizer\n" " AFL_USE_CFISAN: activate control flow sanitizer\n" " AFL_USE_MSAN: activate memory sanitizer\n" - " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"); + " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" + " AFL_USE_LSAN: activate leak-checker sanitizer\n"); if (have_gcc_plugin) SAYF( diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 68995388..fa89713a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -483,7 +483,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); } - /* Set sane defaults for ASAN if nothing else specified. */ + /* Set sane defaults for ASAN if nothing else is specified. */ if (!getenv("ASAN_OPTIONS")) setenv("ASAN_OPTIONS", @@ -500,7 +500,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); - /* Set sane defaults for UBSAN if nothing else specified. */ + /* Set sane defaults for UBSAN if nothing else is specified. */ if (!getenv("UBSAN_OPTIONS")) setenv("UBSAN_OPTIONS", @@ -538,6 +538,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); + /* LSAN, too, does not support abort_on_error=1. */ + + if (!getenv("LSAN_OPTIONS")) + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 1); + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -1210,8 +1218,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (unlikely( /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || - /* special handling for msan */ - (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + /* special handling for msan and lsan */ + (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 82c1799e..24f5c5b5 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2466,6 +2466,20 @@ void check_asan_opts(afl_state_t *afl) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + + } /* Handle stop signal (Ctrl-C, etc). */ @@ -2711,7 +2725,8 @@ void check_binary(afl_state_t *afl, u8 *fname) { } if (memmem(f_data, f_len, "__asan_init", 11) || - memmem(f_data, f_len, "__msan_init", 11)) { + memmem(f_data, f_len, "__msan_init", 11) || + memmem(f_data, f_len, "__lsan_init", 11)) { afl->fsrv.uses_asan = 1; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 7bf5a9c7..bf076683 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -570,6 +570,10 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); setenv("UBSAN_OPTIONS", "halt_on_error=1:" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 7ef8b9bf..a2741a07 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -712,6 +712,19 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -749,6 +762,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + if (get_afl_env("AFL_PRELOAD")) { if (fsrv->qemu_mode) { diff --git a/test/test-pre.sh b/test/test-pre.sh index 85ac320b..174f2f7f 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -71,6 +71,7 @@ unset AFL_HARDEN unset AFL_USE_ASAN unset AFL_USE_MSAN unset AFL_USE_UBSAN +unset AFL_USE_LSAN unset AFL_TMPDIR unset AFL_CC unset AFL_PRELOAD -- cgit 1.4.1 From 6514e33ab6733dd4e7ae0d3eeec83db06b3f451f Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 2 Apr 2021 22:32:38 +0000 Subject: Replace __AFL_CHECK_LEAK with __AFL_LEAK_CHECK to be more proper. Fix spelling mistakes. Correctly call LSAN_ERROR not MSAN_ERROR. --- docs/env_variables.md | 8 ++++---- docs/notes_for_asan.md | 2 +- src/afl-analyze.c | 2 +- src/afl-cc.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/env_variables.md b/docs/env_variables.md index 682ab7f1..85c2efd7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: overridden. - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - compiler supports itt. Note that fuzzing with ASAN is mildly challenging + compiler supports it. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the @@ -66,8 +66,8 @@ make fairly broad use of environmental variables instead: - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided that your compiler supports it. To perform a leak check within your - program at a certain point (such as at the end of an __AFL_LOOP, - you can run the macro __AFL_CHECK_LEAK(); which will cause + program at a certain point (such as at the end of an __AFL_LOOP), + you can run the macro __AFL_LEAK_CHECK(); which will cause an abort if any memory is leaked (you can combine this with the LSAN_OPTIONS=suppressions option to supress some known leaks). @@ -637,7 +637,7 @@ optimal values if not already present in the environment: ``` - Similarly, the default `LSAN_OPTIONS` are set to: ``` - exit_code=86 + exit_code=23 fast_unwind_on_malloc=0 ```` Be sure to include the first ones for LSAN and MSAN when customizing diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 26f34fad..f55aeaf2 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -30,7 +30,7 @@ Note that ASAN is incompatible with -static, so be mindful of that. When compiling with AFL_USE_LSAN, the leak sanitizer will normally run when the program exits. In order to utilize this check at different times, -such as at the end of a loop, you may use the macro __AFL_CHECK_LEAK();. +such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();. This macro will report a crash in afl-fuzz if any memory is left leaking at this stage. You can also use LSAN_OPTIONS and a supressions file for more fine-tuned checking, however make sure you keep exitcode=23. diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 90305714..f961f13a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -832,7 +832,7 @@ static void set_up_environment(void) { "handle_sigill=0", 0); setenv("LSAN_OPTIONS", - "exitcode=" STRINGIFY(MSAN_ERROR) ":" + "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index e0478503..975b28d1 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -923,7 +923,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } cc_params[cc_par_cnt++] = - "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()"; + "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " -- cgit 1.4.1 From b418c31479f5d5e1d10c75eafec9ead9351453cb Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:39:09 +0400 Subject: Some updates on readme Some updates on readme --- utils/autodict_ql/readme.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index c8e5556f..45f685c6 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -79,4 +79,19 @@ Commands: - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. -6. Done! \ No newline at end of file +6. Done! + + +## More on dictionaries and tokens +Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. +On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. + +I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` is working based on the target. +In overall, fuzzing with dictionaries and well-generated tokens will give better results. + +There are 2 important points to remember : + +- If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chance to discover new bugs. +- Do not remember to set the `AFL_MAX_DET_EXTRAS` to the number of generated dictionaries, if you forget to set this environment variable, then AFL++ use just 200 tokens and use the rest of them probablistically. So this will guarantees that your tokens will be used by AFL++. + + \ No newline at end of file -- cgit 1.4.1 From b7d12c8532da0a094aa2504e90f84a1530d569a9 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 02:45:46 +0400 Subject: Update readme Update readme --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 45f685c6..39857f69 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -83,7 +83,7 @@ Commands: ## More on dictionaries and tokens -Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. +Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` is working based on the target. -- cgit 1.4.1 From 8f9d1fd7b05f916d8c43d5872be54d9074bdf8db Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 03:16:13 +0400 Subject: Updates update --- utils/autodict_ql/readme.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 39857f69..3e4655c8 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -34,10 +34,11 @@ The usage of Autodict-QL is pretty easy. But let's describe it as : 1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system, so : -` # chmod +x codeql-build.sh` - -` # codeql ` - +```shell +# chmod +x codeql-build.sh` +# sudo ./codeql-build.sh +# codeql ` +``` Then you should get : ```shell @@ -93,5 +94,3 @@ There are 2 important points to remember : - If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chance to discover new bugs. - Do not remember to set the `AFL_MAX_DET_EXTRAS` to the number of generated dictionaries, if you forget to set this environment variable, then AFL++ use just 200 tokens and use the rest of them probablistically. So this will guarantees that your tokens will be used by AFL++. - - \ No newline at end of file -- cgit 1.4.1 From 4291c3db5dca5082aed123f3a353f8af4a0f4785 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 14:04:06 +0400 Subject: finalize 1 commit final things --- utils/autodict_ql/autodict-ql.py | 91 ++++++++-------------------------------- utils/autodict_ql/readme.md | 6 ++- 2 files changed, 22 insertions(+), 75 deletions(-) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index 69d11f48..ddc95435 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -1,4 +1,14 @@ #!/usr/bin/env python3 +# AutoDict-QL - Optimal Token Generation for Fuzzing +# Part of AFL++ Project +# Developed and Maintained by Arash Ale Ebrahim (@Microsvuln) +# Usage : python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH] +# CURRENT_DIR = full of your current Dir +# CODEQL_DATABASE_PATH = Full path to your CodeQL database +# TOKEN_PATH = Folder name of the newly generated tokens +# Example : python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens +# Just pass the tokens folder to the -x flag of your fuzzer + import os import string import binascii @@ -42,47 +52,25 @@ def static_analysis(file,file2,cur,db) : f.close() def copy_tokens(cur, tokenpath) : - subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strstr-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "local-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "global-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "arrays-lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "arrays-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - #strtool-strs + def codeql_analysis(cur, db) : static_analysis("litout.out","litool.ql", cur, db) static_analysis("strcmp-strings.out","strcmp-str.ql", cur, db) static_analysis("strncmp-strings.out","strncmp-str.ql", cur, db) - static_analysis("strstr-strings.out","strstr-str.ql", cur, db) static_analysis("memcmp-strings.out","memcmp-str.ql", cur, db) - static_analysis("global-values-strings.out","globals-values.ql", cur, db) - static_analysis("local-strings.out","locals-strs.ql", cur, db) static_analysis("strtool-strings.out","strtool.ql", cur, db) - static_analysis("arrays.out","array-literals.ql", cur, db) - start_aflql(0,cur) - #command1 = [ - # 'codeql','query', 'run', - # cur + '/litool.ql', - # '-d', - # db, '>','fff.txt' - # ] - #with open("litool2.log", "w") as f: - # stream = os.popen("codeql query run litool.ql -d " + db ) - # output = stream.read() - # f.write(output) - # f.close() - #worker1 = subprocess.Popen(command1) - #print(worker1.communicate()) - - -def start_aflql(tokenpath, cur): + start_autodict(0,cur) + + + +def start_autodict(tokenpath, cur): command = [ 'python3', cur + '/litan.py', @@ -110,23 +98,6 @@ def start_aflql(tokenpath, cur): worker3 = subprocess.Popen(command2) print(worker3.communicate()) - command3 = [ - 'python3', - cur + '/array-lits.py', - cur + '/arrays-lits/', - cur + '/arrays.out' - ] - worker4 = subprocess.Popen(command3) - print(worker4.communicate()) - - command4 = [ - 'python3', - cur + '/array-strings.py', - cur + '/arrays-strs/', - cur + '/arrays.out' - ] - worker5 = subprocess.Popen(command4) - print(worker5.communicate()) command5 = [ @@ -138,27 +109,8 @@ def start_aflql(tokenpath, cur): worker6 = subprocess.Popen(command5) print(worker6.communicate()) - command6 = [ - 'python3', - cur + '/globals-strings.py', - cur + '/global-strs/', - cur + '/global-values-strings.out' - ] - worker7 = subprocess.Popen(command6) - print(worker7.communicate()) - - command7 = [ - 'python3', - cur + '/strstr-strings.py', - cur + '/strstr-strs/', - cur + '/strstr-strings.out' - ] - worker8 = subprocess.Popen(command7) - print(worker8.communicate()) - #strtool-strings.out - command8 = [ 'python3', cur + '/stan-strings.py', @@ -168,14 +120,7 @@ def start_aflql(tokenpath, cur): worker9 = subprocess.Popen(command8) print(worker9.communicate()) - command9 = [ - 'python3', - cur + '/local-strings.py', - cur + '/local-strs/', - cur + '/local-strings.out' - ] - worker10 = subprocess.Popen(command9) - print(worker10.communicate()) + def main(): args = parse_args() @@ -183,6 +128,6 @@ def main(): #copy_tokens(args.cur, args.tokenpath) codeql_analysis(args.cur, args.db) copy_tokens(args.cur, args.tokenpath) - #start_aflql(args.tokenpath, args.cur) + #start_autodict(args.tokenpath, args.cur) if __name__ == '__main__': main() \ No newline at end of file diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 3e4655c8..f8d23098 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -67,7 +67,7 @@ Commands: github Commands useful for interacting with the GitHub API through CodeQL. ``` -2. Compiler your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . +2. Compile your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: - `./configure --disable-shared` - `codeql create database libxml-db --language=cpp --command=make` @@ -87,10 +87,12 @@ Commands: Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. -I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` is working based on the target. +I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` and `dict2file` is working based on the target. In overall, fuzzing with dictionaries and well-generated tokens will give better results. There are 2 important points to remember : - If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chance to discover new bugs. - Do not remember to set the `AFL_MAX_DET_EXTRAS` to the number of generated dictionaries, if you forget to set this environment variable, then AFL++ use just 200 tokens and use the rest of them probablistically. So this will guarantees that your tokens will be used by AFL++. + +Thanks are going to Marc Heuse, the AFL++ main developer, Antonio Morales and Stefan Nagy \ No newline at end of file -- cgit 1.4.1 From 7f6d256014ae6728bc938e33b7038105a5714c9b Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 14:06:12 +0400 Subject: space space --- utils/autodict_ql/readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index f8d23098..0449233b 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -30,6 +30,7 @@ You can write other CodeQL scripts to extract possible effective tokens if you t ## Usage + The usage of Autodict-QL is pretty easy. But let's describe it as : 1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system, so : -- cgit 1.4.1 From 7a3dfbce71d45742a6b571e41f07ae6b104e3a6b Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 14:07:13 +0400 Subject: remove things remove things --- utils/autodict_ql/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 0449233b..9e6a7292 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -36,9 +36,9 @@ The usage of Autodict-QL is pretty easy. But let's describe it as : 1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system, so : ```shell -# chmod +x codeql-build.sh` +# chmod +x codeql-build.sh # sudo ./codeql-build.sh -# codeql ` +# codeql ``` Then you should get : -- cgit 1.4.1 From 8d894eec90ef738702d42274cda0d6a4e5494627 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 14:11:33 +0400 Subject: Add python scripts Add python scripts --- utils/autodict_ql/memcmp-strings.py | 64 ++++++++++++++++++++++++++++++++++++ utils/autodict_ql/stan-strings.py | 60 +++++++++++++++++++++++++++++++++ utils/autodict_ql/strcmp-strings.py | 60 +++++++++++++++++++++++++++++++++ utils/autodict_ql/strncmp-strings.py | 64 ++++++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+) create mode 100644 utils/autodict_ql/memcmp-strings.py create mode 100644 utils/autodict_ql/stan-strings.py create mode 100644 utils/autodict_ql/strcmp-strings.py create mode 100644 utils/autodict_ql/strncmp-strings.py diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py new file mode 100644 index 00000000..e948fba4 --- /dev/null +++ b/utils/autodict_ql/memcmp-strings.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# Autodict-QL - Optimal token generation for fuzzing +# Part of AFL++ Project +# Author : Microsvuln - Arash.vre@gmail.com + +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import re +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + parser.add_argument("corpdir", + help="The path to the corpus directory to generate strings.") + parser.add_argument("infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + + return parser.parse_args() + + +def do_string_analysis(corpdir, infile1): + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() + new_lst1 = [] + n = 1 + for i, num1 in enumerate(lines): + if i != 0: + new_lst1.append(num1) + print("num : %s" % num1) + str11 = str(num1) + str11 = str11.replace("|","") + str11 = str11.replace("\n","") + str11 = str11.lstrip() + str11 = str11.rstrip() + print("all strings : %s" % str11) + str11 = str(str11) + if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + print("Space / Paranthesis String : %s" % str11) + else : + with open(corpdir+'/memcmp-str{0}'.format(n), 'w') as file: + file.write(str11) + print("Hahaha : %s" % str11) + n=n+1 + +def main(): + args = parse_args() + ensure_dir(args.corpdir) + do_string_analysis(args.corpdir, args.infile) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py new file mode 100644 index 00000000..c35d8a65 --- /dev/null +++ b/utils/autodict_ql/stan-strings.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import re +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + parser.add_argument("corpdir", + help="The path to the corpus directory to generate strings.") + parser.add_argument("infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + + return parser.parse_args() + + +def do_string_analysis(corpdir, infile1): + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() + new_lst1 = [] + n = 1 + for i, num1 in enumerate(lines): + if i != 0: + new_lst1.append(num1) + print("num : %s" % num1) + str11 = str(num1) + str11 = str11.replace("|","") + str11 = str11.replace("\n","") + str11 = str11.lstrip() + str11 = str11.rstrip() + print("all strings : %s" % str11) + str11 = str(str11) + if ((" " in str11 ) or (")" in str11) or ("(" in str11)) or ("<" in str11) or (">" in str11) : + print("Space / Paranthesis String : %s" % str11) + else : + with open(corpdir+'/seed-str{0}'.format(n), 'w') as file: + file.write(str11) + print("Hahaha : %s" % str11) + n=n+1 + +def main(): + args = parse_args() + ensure_dir(args.corpdir) + do_string_analysis(args.corpdir, args.infile) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py new file mode 100644 index 00000000..412b70ae --- /dev/null +++ b/utils/autodict_ql/strcmp-strings.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import re +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + parser.add_argument("corpdir", + help="The path to the corpus directory to generate strings.") + parser.add_argument("infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + + return parser.parse_args() + + +def do_string_analysis(corpdir, infile1): + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() + new_lst1 = [] + n = 1 + for i, num1 in enumerate(lines): + if i != 0: + new_lst1.append(num1) + print("num : %s" % num1) + str11 = str(num1) + str11 = str11.replace("|","") + str11 = str11.replace("\n","") + str11 = str11.lstrip() + str11 = str11.rstrip() + print("all strings : %s" % str11) + str11 = str(str11) + if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + print("Space / Paranthesis String : %s" % str11) + else : + with open(corpdir+'/strcmp-str{0}'.format(n), 'w') as file: + file.write(str11) + print("Hahaha : %s" % str11) + n=n+1 + +def main(): + args = parse_args() + ensure_dir(args.corpdir) + do_string_analysis(args.corpdir, args.infile) +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py new file mode 100644 index 00000000..2c07718e --- /dev/null +++ b/utils/autodict_ql/strncmp-strings.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# Autodict-QL - Optimal token generation for fuzzing +# Part of AFL++ Project +# Author : Microsvuln - Arash.vre@gmail.com + +import os +import string +import binascii +import codecs +import errno +import struct +import argparse +import re +from binascii import unhexlify + +def ensure_dir(dir): + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + +def parse_args(): + parser = argparse.ArgumentParser(description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) + parser.add_argument("corpdir", + help="The path to the corpus directory to generate strings.") + parser.add_argument("infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + + return parser.parse_args() + + +def do_string_analysis(corpdir, infile1): + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() + new_lst1 = [] + n = 1 + for i, num1 in enumerate(lines): + if i != 0: + new_lst1.append(num1) + print("num : %s" % num1) + str11 = str(num1) + str11 = str11.replace("|","") + str11 = str11.replace("\n","") + str11 = str11.lstrip() + str11 = str11.rstrip() + print("all strings : %s" % str11) + str11 = str(str11) + if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + print("Space / Paranthesis String : %s" % str11) + else : + with open(corpdir+'/strncmp-str{0}'.format(n), 'w') as file: + file.write(str11) + print("Hahaha : %s" % str11) + n=n+1 + +def main(): + args = parse_args() + ensure_dir(args.corpdir) + do_string_analysis(args.corpdir, args.infile) +if __name__ == '__main__': + main() \ No newline at end of file -- cgit 1.4.1 From 6c88b6b362ddc06effd8d99c32375ab34028665c Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 14:13:55 +0400 Subject: Update python scripts Update python scripts --- utils/autodict_ql/memcmp-strings.py | 2 +- utils/autodict_ql/stan-strings.py | 6 +++++- utils/autodict_ql/strcmp-strings.py | 6 +++++- utils/autodict_ql/strncmp-strings.py | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py index e948fba4..fb892aff 100644 --- a/utils/autodict_ql/memcmp-strings.py +++ b/utils/autodict_ql/memcmp-strings.py @@ -53,7 +53,7 @@ def do_string_analysis(corpdir, infile1): else : with open(corpdir+'/memcmp-str{0}'.format(n), 'w') as file: file.write(str11) - print("Hahaha : %s" % str11) + print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) n=n+1 def main(): diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py index c35d8a65..e9f6f0d0 100644 --- a/utils/autodict_ql/stan-strings.py +++ b/utils/autodict_ql/stan-strings.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# Autodict-QL - Optimal token generation for fuzzing +# Part of AFL++ Project +# Author : Microsvuln - Arash.vre@gmail.com + import os import string import binascii @@ -49,7 +53,7 @@ def do_string_analysis(corpdir, infile1): else : with open(corpdir+'/seed-str{0}'.format(n), 'w') as file: file.write(str11) - print("Hahaha : %s" % str11) + print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) n=n+1 def main(): diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py index 412b70ae..a1b7e27c 100644 --- a/utils/autodict_ql/strcmp-strings.py +++ b/utils/autodict_ql/strcmp-strings.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# Autodict-QL - Optimal token generation for fuzzing +# Part of AFL++ Project +# Author : Microsvuln - Arash.vre@gmail.com + import os import string import binascii @@ -49,7 +53,7 @@ def do_string_analysis(corpdir, infile1): else : with open(corpdir+'/strcmp-str{0}'.format(n), 'w') as file: file.write(str11) - print("Hahaha : %s" % str11) + print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) n=n+1 def main(): diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py index 2c07718e..2652f66e 100644 --- a/utils/autodict_ql/strncmp-strings.py +++ b/utils/autodict_ql/strncmp-strings.py @@ -53,7 +53,7 @@ def do_string_analysis(corpdir, infile1): else : with open(corpdir+'/strncmp-str{0}'.format(n), 'w') as file: file.write(str11) - print("Hahaha : %s" % str11) + print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) n=n+1 def main(): -- cgit 1.4.1 From 70e975704465672f49273da9f4a8f7e56f745e20 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 15:47:22 +0400 Subject: new commit - change strings new commit - change strings --- utils/autodict_ql/autodict-ql.py | 1 + utils/autodict_ql/build-codeql.sh | 4 ++-- utils/autodict_ql/memcmp-strings.py | 3 +-- utils/autodict_ql/readme.md | 11 ++++++++--- utils/autodict_ql/stan-strings.py | 3 +-- utils/autodict_ql/strcmp-strings.py | 3 +-- utils/autodict_ql/strncmp-strings.py | 3 +-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index ddc95435..7bba57fc 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -57,6 +57,7 @@ def copy_tokens(cur, tokenpath) : subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["find "+tokenpath+" -size 0 -delete"],shell=True) diff --git a/utils/autodict_ql/build-codeql.sh b/utils/autodict_ql/build-codeql.sh index ccff932e..450207f6 100644 --- a/utils/autodict_ql/build-codeql.sh +++ b/utils/autodict_ql/build-codeql.sh @@ -3,7 +3,6 @@ if [ -d "codeql-home" ]; then echo "Exist !" exit 1 fi -sudo apt install build-essential libtool-bin python3-dev automake git vim wget -y mkdir codeql-home cd codeql-home git clone https://github.com/github/codeql.git codeql-repo @@ -12,6 +11,7 @@ wget https://github.com/github/codeql-cli-binaries/releases/download/v2.4.6/code unzip codeql-linux64.zip mv codeql codeql-cli export "PATH=~/codeql-home/codeql-cli/:$PATH" +echo "export PATH=~/codeql-home/codeql-cli/:$PATH" >> ~/.bashrc codeql resolve languages codeql resolve qlpacks -echo "export PATH=~/codeql-home/codeql-cli/:$PATH" >> ~/.bashrc \ No newline at end of file +codeql \ No newline at end of file diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py index fb892aff..2814da5b 100644 --- a/utils/autodict_ql/memcmp-strings.py +++ b/utils/autodict_ql/memcmp-strings.py @@ -46,9 +46,8 @@ def do_string_analysis(corpdir, infile1): str11 = str11.replace("\n","") str11 = str11.lstrip() str11 = str11.rstrip() - print("all strings : %s" % str11) str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : print("Space / Paranthesis String : %s" % str11) else : with open(corpdir+'/memcmp-str{0}'.format(n), 'w') as file: diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 9e6a7292..ccc9b0e3 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -31,13 +31,18 @@ You can write other CodeQL scripts to extract possible effective tokens if you t ## Usage +Before proceed to installation make sure that you have the following packages by installing them : +```shell +sudo apt install build-essential libtool-bin python3-dev python3 automake git vim wget -y +``` The usage of Autodict-QL is pretty easy. But let's describe it as : -1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system, so : - +1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system. +Do the following : ```shell # chmod +x codeql-build.sh -# sudo ./codeql-build.sh +# ./codeql-build.sh +# source ~/.bashrc # codeql ``` Then you should get : diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py index e9f6f0d0..5a863f80 100644 --- a/utils/autodict_ql/stan-strings.py +++ b/utils/autodict_ql/stan-strings.py @@ -46,9 +46,8 @@ def do_string_analysis(corpdir, infile1): str11 = str11.replace("\n","") str11 = str11.lstrip() str11 = str11.rstrip() - print("all strings : %s" % str11) str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11)) or ("<" in str11) or (">" in str11) : + if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : print("Space / Paranthesis String : %s" % str11) else : with open(corpdir+'/seed-str{0}'.format(n), 'w') as file: diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py index a1b7e27c..1852b947 100644 --- a/utils/autodict_ql/strcmp-strings.py +++ b/utils/autodict_ql/strcmp-strings.py @@ -46,9 +46,8 @@ def do_string_analysis(corpdir, infile1): str11 = str11.replace("\n","") str11 = str11.lstrip() str11 = str11.rstrip() - print("all strings : %s" % str11) str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : print("Space / Paranthesis String : %s" % str11) else : with open(corpdir+'/strcmp-str{0}'.format(n), 'w') as file: diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py index 2652f66e..f00fa3da 100644 --- a/utils/autodict_ql/strncmp-strings.py +++ b/utils/autodict_ql/strncmp-strings.py @@ -46,9 +46,8 @@ def do_string_analysis(corpdir, infile1): str11 = str11.replace("\n","") str11 = str11.lstrip() str11 = str11.rstrip() - print("all strings : %s" % str11) str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11)): + if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : print("Space / Paranthesis String : %s" % str11) else : with open(corpdir+'/strncmp-str{0}'.format(n), 'w') as file: -- cgit 1.4.1 From d5fc03b71819ed75bd7134584e8f00a7f1010149 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 15:49:17 +0400 Subject: update qlpack name update qlpack name --- utils/autodict_ql/qlpack.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/qlpack.yml b/utils/autodict_ql/qlpack.yml index c037a344..28892f24 100644 --- a/utils/autodict_ql/qlpack.yml +++ b/utils/autodict_ql/qlpack.yml @@ -1,3 +1,3 @@ -name: automate +name: autodict version: 0.0.0 libraryPathDependencies: codeql-cpp -- cgit 1.4.1 From 050f331c54a7af2fdb2eb1ca33e9dacd9257dbb0 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:04:14 +0400 Subject: remove unessential things remove unessential things from scripts --- utils/autodict_ql/autodict-ql.py | 10 +++++----- utils/autodict_ql/memcmp-strings.py | 2 +- utils/autodict_ql/stan-strings.py | 2 +- utils/autodict_ql/strcmp-strings.py | 2 +- utils/autodict_ql/strncmp-strings.py | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index 7bba57fc..b51fbb90 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -52,11 +52,11 @@ def static_analysis(file,file2,cur,db) : f.close() def copy_tokens(cur, tokenpath) : - subprocess.call(["cp " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["cp " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["mv " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["mv " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["mv " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["mv " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["mv " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["find "+tokenpath+" -size 0 -delete"],shell=True) diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py index 2814da5b..d1047caa 100644 --- a/utils/autodict_ql/memcmp-strings.py +++ b/utils/autodict_ql/memcmp-strings.py @@ -40,7 +40,7 @@ def do_string_analysis(corpdir, infile1): for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - print("num : %s" % num1) + #print("num : %s" % num1) str11 = str(num1) str11 = str11.replace("|","") str11 = str11.replace("\n","") diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py index 5a863f80..65d08c97 100644 --- a/utils/autodict_ql/stan-strings.py +++ b/utils/autodict_ql/stan-strings.py @@ -40,7 +40,7 @@ def do_string_analysis(corpdir, infile1): for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - print("num : %s" % num1) + #print("num : %s" % num1) str11 = str(num1) str11 = str11.replace("|","") str11 = str11.replace("\n","") diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py index 1852b947..88128dbb 100644 --- a/utils/autodict_ql/strcmp-strings.py +++ b/utils/autodict_ql/strcmp-strings.py @@ -40,7 +40,7 @@ def do_string_analysis(corpdir, infile1): for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - print("num : %s" % num1) + #print("num : %s" % num1) str11 = str(num1) str11 = str11.replace("|","") str11 = str11.replace("\n","") diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py index f00fa3da..0ad0e697 100644 --- a/utils/autodict_ql/strncmp-strings.py +++ b/utils/autodict_ql/strncmp-strings.py @@ -40,7 +40,7 @@ def do_string_analysis(corpdir, infile1): for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - print("num : %s" % num1) + #print("num : %s" % num1) str11 = str(num1) str11 = str11.replace("|","") str11 = str11.replace("\n","") -- cgit 1.4.1 From 05c13588d7f6a0c8e34623eeed0b2920737ba377 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:22:51 +0400 Subject: remove dirs remove dirs --- utils/autodict_ql/autodict-ql.py | 2 ++ utils/autodict_ql/readme.md | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index b51fbb90..0fe7eabf 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -57,6 +57,8 @@ def copy_tokens(cur, tokenpath) : subprocess.call(["mv " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["mv " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) subprocess.call(["mv " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) + subprocess.call(["rm -rf strcmp-strs memcmp-strs strncmp-strs lits strtool-strs"],shell=True) + subprocess.call(["rm *.out"],shell=True) subprocess.call(["find "+tokenpath+" -size 0 -delete"],shell=True) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index ccc9b0e3..16a2a20b 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -93,7 +93,7 @@ Commands: Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. -I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` and `dict2file` is working based on the target. +I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` and `dict2file` are working based on the target. In overall, fuzzing with dictionaries and well-generated tokens will give better results. There are 2 important points to remember : @@ -101,4 +101,3 @@ There are 2 important points to remember : - If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chance to discover new bugs. - Do not remember to set the `AFL_MAX_DET_EXTRAS` to the number of generated dictionaries, if you forget to set this environment variable, then AFL++ use just 200 tokens and use the rest of them probablistically. So this will guarantees that your tokens will be used by AFL++. -Thanks are going to Marc Heuse, the AFL++ main developer, Antonio Morales and Stefan Nagy \ No newline at end of file -- cgit 1.4.1 From c4ad4681cf0aa3ff66f98053345ed7856692f25d Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:28:42 +0400 Subject: Update readme Update readme --- utils/autodict_ql/readme.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 16a2a20b..d8a3b014 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -78,15 +78,13 @@ Commands: - `./configure --disable-shared` - `codeql create database libxml-db --language=cpp --command=make` - Now you have the CodeQL database of the project :-) -3. To run the Autodict-QL, the final step is to just create a folder named `automate` in the project you want to fuzz. (inside the libxml directory) - - `mkdir automate` -4. The final step is to update the CodeQL database you created in the step 2 inside the automate dir you created at step 3 : - - `codeql database upgrade ../libxml-db` -5. Everything is set! Now you should issue the following to get the tokens : +3. The final step is to update the CodeQL database you created in the step 2 : + - `codeql database upgrade /home/user/libxml/libxml-db` +4. Everything is set! Now you should issue the following to get the tokens : - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - - example : `python3 autodict-ql.py /home/user/libxml/automate /home/user/libxml/libxml-db tokens` + - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py `pwd` /home/user/libxml/libxml-db tokens` - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. -6. Done! +5. Done! ## More on dictionaries and tokens -- cgit 1.4.1 From 2b4e93faba3877aeb49ac873b77a930ebd6f0801 Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:30:58 +0400 Subject: Add note Add note --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index d8a3b014..a8d252e4 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -78,7 +78,7 @@ Commands: - `./configure --disable-shared` - `codeql create database libxml-db --language=cpp --command=make` - Now you have the CodeQL database of the project :-) -3. The final step is to update the CodeQL database you created in the step 2 : +3. The final step is to update the CodeQL database you created in the step 2 (Suppose we are in `aflplusplus/utils/autodict_ql/` directory) : - `codeql database upgrade /home/user/libxml/libxml-db` 4. Everything is set! Now you should issue the following to get the tokens : - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` -- cgit 1.4.1 From a7141b6a6ea045a20c0be7031bab0767064915ea Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:31:51 +0400 Subject: Add ` Add ` --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index a8d252e4..6beba871 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -82,7 +82,7 @@ Commands: - `codeql database upgrade /home/user/libxml/libxml-db` 4. Everything is set! Now you should issue the following to get the tokens : - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py `pwd` /home/user/libxml/libxml-db tokens` + - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py ``pwd`` /home/user/libxml/libxml-db tokens` - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. 5. Done! -- cgit 1.4.1 From d35a90101f1ae51fa022332828209139a7e070ad Mon Sep 17 00:00:00 2001 From: microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Sat, 3 Apr 2021 16:33:56 +0400 Subject: change cur change current dir --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 6beba871..8c24d65c 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -82,7 +82,7 @@ Commands: - `codeql database upgrade /home/user/libxml/libxml-db` 4. Everything is set! Now you should issue the following to get the tokens : - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py ``pwd`` /home/user/libxml/libxml-db tokens` + - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py $PWD /home/user/libxml/libxml-db tokens` - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. 5. Done! -- cgit 1.4.1 From afc4da47f78a24d5e441e3815e5b322d1b27fd56 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sat, 3 Apr 2021 14:50:35 +0000 Subject: Fix typos, Use symbolize=0 for LSAN, Remove syntactic sugar. --- README.md | 2 +- docs/env_variables.md | 3 ++- src/afl-analyze.c | 8 ++++---- src/afl-cc.c | 2 +- src/afl-forkserver.c | 3 ++- src/afl-fuzz-init.c | 5 ++--- src/afl-showmap.c | 4 +++- src/afl-tmin.c | 3 ++- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 41d55e9c..4d3f8aa9 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; - export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN`) + export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`) * one should fuzz the target with CMPLOG/redqueen (see above) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV diff --git a/docs/env_variables.md b/docs/env_variables.md index 85c2efd7..5f9233d7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -639,7 +639,8 @@ optimal values if not already present in the environment: ``` exit_code=23 fast_unwind_on_malloc=0 -```` + symbolize=0 +``` Be sure to include the first ones for LSAN and MSAN when customizing anything, since some MSAN and LSAN versions don't call `abort()` on error, and we need a way to detect faults. diff --git a/src/afl-analyze.c b/src/afl-analyze.c index f961f13a..38a40556 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -785,10 +785,9 @@ static void set_up_environment(void) { if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( - LSAN_ERROR) " - please fix!"); + FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); } @@ -833,7 +832,8 @@ static void set_up_environment(void) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index 975b28d1..650e4e43 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) have_instr_list = 1; - if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory"))) + if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) asan_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index fa89713a..f102b73b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -543,7 +543,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!getenv("LSAN_OPTIONS")) setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 1); fsrv->init_child_func(fsrv, argv); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 24f5c5b5..6f663021 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2470,10 +2470,9 @@ void check_asan_opts(afl_state_t *afl) { if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( - LSAN_ERROR) " - please fix!"); + FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index bf076683..2b7d200b 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -570,9 +570,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); setenv("UBSAN_OPTIONS", diff --git a/src/afl-tmin.c b/src/afl-tmin.c index a2741a07..c257b67c 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -764,7 +764,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); if (get_afl_env("AFL_PRELOAD")) { -- cgit 1.4.1 From fee74700836c3694c2037c1e708846150e52d5bd Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sat, 3 Apr 2021 14:57:52 +0000 Subject: Remove check for exit_code on LSAN and replace it with check for symbolize=0. --- src/afl-tmin.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/afl-tmin.c b/src/afl-tmin.c index c257b67c..3a196e2e 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -716,10 +716,9 @@ static void set_up_environment(afl_forkserver_t *fsrv) { if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( - LSAN_ERROR) " - please fix!"); + FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); } -- cgit 1.4.1 From 99819cf5d1cbc262810f26098a5796c9d1262bc5 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sun, 4 Apr 2021 12:45:52 +0000 Subject: Move definition of __AFL_LEAK_CHECK inside ifguards, use LSAN_OPTIONS=print_suppressions=0 --- docs/env_variables.md | 1 + src/afl-analyze.c | 3 ++- src/afl-cc.c | 10 +++------- src/afl-forkserver.c | 3 ++- src/afl-showmap.c | 3 ++- src/afl-tmin.c | 3 ++- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/env_variables.md b/docs/env_variables.md index 5f9233d7..83bc487f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -640,6 +640,7 @@ optimal values if not already present in the environment: exit_code=23 fast_unwind_on_malloc=0 symbolize=0 + print_suppressions=0 ``` Be sure to include the first ones for LSAN and MSAN when customizing anything, since some MSAN and LSAN versions don't call `abort()` on diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 38a40556..f4436980 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -833,7 +833,8 @@ static void set_up_environment(void) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index 650e4e43..e2dd06e2 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -819,6 +819,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (getenv("AFL_USE_LSAN")) { cc_params[cc_par_cnt++] = "-fsanitize=leak"; + cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; + cc_params[cc_par_cnt++] = + "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; } if (getenv("AFL_USE_CFISAN")) { @@ -918,13 +921,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (getenv("AFL_USE_LSAN")) { - cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; - } - - cc_params[cc_par_cnt++] = - "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; - cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " "1;"; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index f102b73b..ac7a1600 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -544,7 +544,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 1); fsrv->init_child_func(fsrv, argv); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 2b7d200b..df91a4c2 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -574,7 +574,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); setenv("UBSAN_OPTIONS", diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 3a196e2e..eb5e0dcf 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -764,7 +764,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); if (get_afl_env("AFL_PRELOAD")) { -- cgit 1.4.1 From 845c584b9cee7092772305912508b825155142fa Mon Sep 17 00:00:00 2001 From: begasus Date: Sun, 4 Apr 2021 17:41:43 +0000 Subject: Fix Haiku references, no and missing defines for USEMMAP --- instrumentation/afl-compiler-rt.o.c | 4 +++- utils/afl_network_proxy/afl-network-server.c | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index f241447a..fa53263c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -34,8 +34,10 @@ #include #include -#include #ifndef __HAIKU__ + #include +#endif +#ifndef USEMMAP #include #endif #include diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c index 0dfae658..60f174ee 100644 --- a/utils/afl_network_proxy/afl-network-server.c +++ b/utils/afl_network_proxy/afl-network-server.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include @@ -53,7 +52,9 @@ #include #include #include -#include +#ifndef USEMMAP + #include +#endif #include #include -- cgit 1.4.1 From 3c846859eef4d17d2587ea28db83c680b51723a7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Apr 2021 20:05:02 +0200 Subject: cleanup --- GNUmakefile | 38 ++++++++++++---------- GNUmakefile.gcc_plugin | 12 ++++--- GNUmakefile.llvm | 8 +++-- docs/Changelog.md | 3 ++ include/android-ashmem.h | 16 +++++---- instrumentation/afl-llvm-lto-instrumentation.so.cc | 2 +- src/afl-analyze.c | 3 +- src/afl-cc.c | 5 +-- src/afl-forkserver.c | 7 ++-- src/afl-fuzz-init.c | 1 - src/afl-tmin.c | 2 +- 11 files changed, 55 insertions(+), 42 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index fdbcd542..d5fb570d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -36,6 +36,11 @@ SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 ASAN_OPTIONS=detect_leaks=0 +SYS = $(shell uname -s) +ARCH = $(shell uname -m) + +$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH)) + ifdef NO_SPLICING override CFLAGS += -DNO_SPLICING endif @@ -82,7 +87,7 @@ endif # endif #endif -ifneq "$(shell uname)" "Darwin" +ifneq "$(SYS)" "Darwin" #ifeq "$(HAVE_MARCHNATIVE)" "1" # SPECIAL_PERFORMANCE += -march=native #endif @@ -92,7 +97,7 @@ ifneq "$(shell uname)" "Darwin" endif endif -ifeq "$(shell uname)" "SunOS" +ifeq "$(SYS)" "SunOS" CFLAGS_OPT += -Wno-format-truncation LDFLAGS = -lkstat -lrt endif @@ -119,11 +124,10 @@ ifdef INTROSPECTION CFLAGS_OPT += -DINTROSPECTION=1 endif - -ifneq "$(shell uname -m)" "x86_64" - ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386" - ifneq "$(shell uname -m)" "amd64" - ifneq "$(shell uname -m)" "i86pc" +ifneq "$(ARCH)" "x86_64" + ifneq "$(patsubst i%86,i386,$(ARCH))" "i386" + ifneq "$(ARCH)" "amd64" + ifneq "$(ARCH)" "i86pc" AFL_NO_X86=1 endif endif @@ -141,27 +145,27 @@ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpoi -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" -ifeq "$(shell uname -s)" "FreeBSD" +ifeq "$(SYS)" "FreeBSD" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" override CFLAGS += -I /usr/local/include/ -mno-retpoline LDFLAGS += -Wl,-z,notext -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "NetBSD" +ifeq "$(SYS)" "NetBSD" override CFLAGS += -I /usr/pkg/include/ LDFLAGS += -L /usr/pkg/lib/ endif -ifeq "$(shell uname -s)" "Haiku" +ifeq "$(SYS)" "Haiku" SHMAT_OK=0 override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC LDFLAGS += -Wno-deprecated-declarations -lgnu @@ -236,24 +240,24 @@ else BUILD_DATE ?= $(shell date "+%Y-%m-%d") endif -ifneq "$(filter Linux GNU%,$(shell uname))" "" +ifneq "$(filter Linux GNU%,$(SYS))" "" ifndef DEBUG override CFLAGS += -D_FORTIFY_SOURCE=2 endif LDFLAGS += -ldl -lrt -lm endif -ifneq "$(findstring FreeBSD, $(shell uname))" "" +ifneq "$(findstring FreeBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring NetBSD, $(shell uname))" "" +ifneq "$(findstring NetBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring OpenBSD, $(shell uname))" "" +ifneq "$(findstring OpenBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif @@ -485,7 +489,7 @@ unit_clean: @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o .PHONY: unit -ifneq "$(shell uname)" "Darwin" +ifneq "$(ARCH)" "Darwin" unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else unit: diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index aa93c688..b0f90f1b 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -41,6 +41,8 @@ CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11 CC ?= gcc CXX ?= g++ +SYS = $(shell uname -s) + ifeq "clang" "$(CC)" CC = gcc CXX = g++ @@ -75,25 +77,25 @@ ifeq "$(TEST_MMAP)" "1" override CFLAGS_SAFE += -DUSEMMAP=1 endif -ifneq "$(shell uname -s)" "Haiku" -ifneq "$(shell uname -s)" "OpenBSD" +ifneq "$(SYS)" "Haiku" +ifneq "$(SYS)" "OpenBSD" LDFLAGS += -lrt endif else CFLAGS_SAFE += -DUSEMMAP=1 endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CC = egcc CXX = eg++ PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "SunOS" +ifeq "$(SYS)" "SunOS" PLUGIN_FLAGS += -I/usr/include/gmp endif diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 4b5ac520..61c17e92 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -30,7 +30,9 @@ BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/nul VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) -ifeq "$(shell uname)" "OpenBSD" +SYS = $(shell uname -s) + +ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" @@ -275,13 +277,13 @@ CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) # User teor2345 reports that this is required to make things work on MacOS X. -ifeq "$(shell uname)" "Darwin" +ifeq "$(SYS)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress else CLANG_CPPFL += -Wl,-znodelete endif -ifeq "$(shell uname)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so CLANG_CPPFL += -mno-retpoline CFLAGS += -mno-retpoline diff --git a/docs/Changelog.md b/docs/Changelog.md index 91d1a8cc..24877f9a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,8 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, thanks to @WorksButNotTested! + - create a fuzzing dictionary with the help of CodeQL thanks to + @microsvuln! see utils/autodict_ql - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` @@ -20,6 +22,7 @@ sending a mail to . - default cmplog level (-l) is now 2, better efficiency. - ensure one fuzzer sync per cycle - afl-cc: + - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD ### Version ++3.12c (release) diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 44fe556a..1bfd3220 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -13,12 +13,14 @@ #include #define ASHMEM_DEVICE "/dev/ashmem" -int shmdt(const void* address) { -#if defined(SYS_shmdt) +int shmdt(const void *address) { + + #if defined(SYS_shmdt) return syscall(SYS_shmdt, address); -#else + #else return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); -#endif + #endif + } int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { @@ -26,7 +28,7 @@ int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); @@ -77,6 +79,6 @@ void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { } - #endif /* !_ANDROID_ASHMEM_H */ -#endif /* !__ANDROID__ */ + #endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 50306224..6eb19060 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -176,7 +176,7 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (debug) { fprintf(stderr, "map address is 0x%lx\n", map_addr); } + if (debug) { fprintf(stderr, "map address is 0x%llx\n", map_addr); } /* Get/set the globals for the SHM region. */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 7d7519fa..aabdbf1a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -833,14 +833,13 @@ static void set_up_environment(char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" "print_suppressions=0", 0); - if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-cc.c b/src/afl-cc.c index d4c0a6b7..3af31b3c 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -820,10 +820,11 @@ static void edit_params(u32 argc, char **argv, char **envp) { } if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; - cc_params[cc_par_cnt++] = - "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + } if (getenv("AFL_USE_CFISAN")) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index cd04e23d..2c502621 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -560,7 +560,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* LSAN, too, does not support abort_on_error=1. */ if (!getenv("LSAN_OPTIONS")) - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" @@ -1314,8 +1314,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || /* special handling for msan and lsan */ - (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || - WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || + (fsrv->uses_asan && + (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 48f3289d..e505abd4 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2502,7 +2502,6 @@ void check_asan_opts(afl_state_t *afl) { } - } /* Handle stop signal (Ctrl-C, etc). */ diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 6aad748c..6656712a 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -763,7 +763,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" -- cgit 1.4.1 From 96b743094dc5a158b8588c4bdf58057161a99e8e Mon Sep 17 00:00:00 2001 From: begasus Date: Sun, 4 Apr 2021 19:25:04 +0000 Subject: Add -lnetwork to dependencies for Haiku --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index ac8fe796..542097a3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -164,7 +164,7 @@ endif ifeq "$(shell uname -s)" "Haiku" SHMAT_OK=0 override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC - LDFLAGS += -Wno-deprecated-declarations -lgnu + LDFLAGS += -Wno-deprecated-declarations -lgnu -lnetwork SPECIAL_PERFORMANCE += -DUSEMMAP=1 endif -- cgit 1.4.1 From f2efd940358374b9693e3f4323c159a6c6e7d20a Mon Sep 17 00:00:00 2001 From: begasus Date: Sun, 4 Apr 2021 20:16:41 +0000 Subject: fix conflict --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index bde328e7..b8a091ff 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,6 @@ - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - cmplog: too much tainted bytes, directly add to dict and skip? - - parallel builds for source-only targets ## Further down the road -- cgit 1.4.1 From a02d84a11cb28bc620bf24bda322e14701ad726f Mon Sep 17 00:00:00 2001 From: begasus Date: Mon, 5 Apr 2021 11:56:04 +0000 Subject: Fix undeclared SYS_write on Haiku --- instrumentation/afl-compiler-rt.o.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index fa53263c..9bb6114b 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1740,7 +1740,11 @@ static int area_is_valid(void *ptr, size_t len) { if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; } - long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); + #ifndef __HAIKU__ + long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); + #else + long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); + #endif // HAIKU if (r <= 0 || r > len) return 0; -- cgit 1.4.1 From 43b1a0d46bd7fb55e2baeadd5d105e60aecdee9c Mon Sep 17 00:00:00 2001 From: begasus Date: Mon, 5 Apr 2021 13:02:26 +0000 Subject: Declare private api __kern_write for Haiku --- instrumentation/afl-compiler-rt.o.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 9bb6114b..50ecba80 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -78,6 +78,10 @@ #define MAP_INITIAL_SIZE MAP_SIZE #endif +#if defined(__HAIKU__) + extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); +#endif // HAIKU + u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 * __afl_area_ptr_dummy = __afl_area_initial; u8 * __afl_area_ptr = __afl_area_initial; -- cgit 1.4.1 From 5ab14f22a5da4e7c9379f75fa043a8f242ba87d4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 Apr 2021 08:12:09 +0200 Subject: better MacOs msg --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 76a698a4..a87b2f7b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -550,7 +550,7 @@ all_done: test_build @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." - @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi + @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecific for MacOs.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null .NOTPARALLEL: clean all -- cgit 1.4.1 From 19690b606d00b3c32958df07d1b87a3ce8cd8903 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 6 Apr 2021 19:03:53 +0000 Subject: Haiku: create directory for debug_server, if not present --- afl-system-config | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/afl-system-config b/afl-system-config index ae37a062..2b945d7a 100755 --- a/afl-system-config +++ b/afl-system-config @@ -98,7 +98,9 @@ if [ "$PLATFORM" = "Darwin" ] ; then DONE=1 fi if [ "$PLATFORM" = "Haiku" ] ; then - SETTINGS=~/config/settings/system/debug_server/settings + DEBUG_SERVER_DIR=~/config/settings/system/debug_server + [ ! -r ${DEBUG_SERVER_DIR} ] && mkdir ${DEBUG_SERVER_DIR} + SETTINGS=${DEBUG_SERVER_DIR}/settings [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \ echo We change the debug_server default_action from user to silently kill; \ [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \ -- cgit 1.4.1 From 2e6e1e566b6b58081969d179c67398fa1316c49b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 Apr 2021 22:16:56 +0200 Subject: add missing env --- include/envs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/envs.h b/include/envs.h index 887e2c4f..466ab087 100644 --- a/include/envs.h +++ b/include/envs.h @@ -26,6 +26,7 @@ static char *afl_environment_variables[] = { "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", + "AFL_CC_COMPILER", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW", -- cgit 1.4.1 From 7181112233f119b4dfda93b594b0f1bacdd3139a Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 6 Apr 2021 20:43:26 +0000 Subject: better understandable directory creation logic --- afl-system-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afl-system-config b/afl-system-config index 2b945d7a..5ad9d937 100755 --- a/afl-system-config +++ b/afl-system-config @@ -99,7 +99,7 @@ if [ "$PLATFORM" = "Darwin" ] ; then fi if [ "$PLATFORM" = "Haiku" ] ; then DEBUG_SERVER_DIR=~/config/settings/system/debug_server - [ ! -r ${DEBUG_SERVER_DIR} ] && mkdir ${DEBUG_SERVER_DIR} + [ ! -d ${DEBUG_SERVER_DIR} ] && mkdir -p ${DEBUG_SERVER_DIR} SETTINGS=${DEBUG_SERVER_DIR}/settings [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \ echo We change the debug_server default_action from user to silently kill; \ -- cgit 1.4.1 From 28878c69e0c275e42b40bc2ab17bdca7dd1a989e Mon Sep 17 00:00:00 2001 From: Jiangen Jiao Date: Wed, 7 Apr 2021 11:28:19 +0800 Subject: android: disable sigaction inside debuggerd check https://github.com/google/AFL/blob/master/docs/INSTALL#L173 --- instrumentation/afl-compiler-rt.o.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1f003c1e..552bbea8 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1144,6 +1144,18 @@ void __afl_manual_init(void) { __attribute__((constructor())) void __afl_auto_init(void) { +#ifdef __ANDROID__ + // Disable handlers in linker/debuggerd, check include/debuggerd/handler.h + signal(SIGABRT, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGILL, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGSTKFLT, SIG_DFL); + signal(SIGSYS, SIG_DFL); + signal(SIGTRAP, SIG_DFL); +#endif + if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; if (getenv(DEFER_ENV_VAR)) return; -- cgit 1.4.1 From bfe7e3fd55cc4cfc8ae334b68095e7b26b8ec8a5 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 7 Apr 2021 14:20:50 +0200 Subject: fix forkserver timeout error msg --- src/afl-forkserver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 2c502621..727e7f8d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -821,7 +821,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (fsrv->last_run_timed_out) { - FATAL("Timeout while initializing fork server (adjusting -t may help)"); + FATAL( + "Timeout while initializing fork server (setting " + "AFL_FORKSRV_INIT_TMOUT may help)"); } -- cgit 1.4.1 From 9c517199b25e5fb43c38737021002249fd506ad7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 8 Apr 2021 10:03:36 +0200 Subject: removed -lc++ linking for lto --- src/afl-cc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/afl-cc.c b/src/afl-cc.c index 3af31b3c..1f89bac5 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -430,9 +430,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument"; - if (lto_mode && plusplus_mode) - cc_params[cc_par_cnt++] = "-lc++"; // needed by fuzzbench, early - if (lto_mode && have_instr_env) { cc_params[cc_par_cnt++] = "-Xclang"; -- cgit 1.4.1 From 019b26de58a4e7eb4b95aab6425beba4efb853f4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 Apr 2021 11:19:40 +0200 Subject: fix afl_custom_queue_new_entry when syncing --- docs/Changelog.md | 3 +++ instrumentation/afl-llvm-lto-instrumentation.so.cc | 2 +- src/afl-fuzz-queue.c | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 24877f9a..072320dc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -21,9 +21,12 @@ sending a mail to . AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. - ensure one fuzzer sync per cycle + - fix afl_custom_queue_new_entry original file name when syncing + from fuzzers - afl-cc: - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD + - Removed automatic linking with -lc++ for LTO mode ### Version ++3.12c (release) - afl-fuzz: diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 6eb19060..f6cdbe9e 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -92,7 +92,7 @@ class AFLLTOPass : public ModulePass { uint32_t afl_global_id = 1, autodictionary = 1; uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; - uint64_t map_addr = 0x10000; + unsigned long long int map_addr = 0x10000; char * skip_nozero = NULL; }; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index e5f51a6c..811e805c 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -478,7 +478,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { u8 *fname_orig = NULL; /* At the initialization stage, queue_cur is NULL */ - if (afl->queue_cur) fname_orig = afl->queue_cur->fname; + if (afl->queue_cur && !afl->syncing_party) { + + fname_orig = afl->queue_cur->fname; + + } el->afl_custom_queue_new_entry(el->data, fname, fname_orig); -- cgit 1.4.1 From c19d1f0c7519fe7d1234e695c497a78f24aaf8b7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 Apr 2021 12:22:16 +0200 Subject: update grammar-mutator, show better fuzzing strategy yields --- TODO.md | 1 + custom_mutators/grammar_mutator/GRAMMAR_VERSION | 2 +- custom_mutators/grammar_mutator/grammar_mutator | 2 +- docs/Changelog.md | 1 + src/afl-fuzz-stats.c | 72 +++++++++++++++---------- 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/TODO.md b/TODO.md index dc765ec4..96b24521 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,7 @@ ## Roadmap 3.00+ + - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - CPU affinity for many cores? There seems to be an issue > 96 cores - afl-plot to support multiple plot_data diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION index a3fe6bb1..c7c1948d 100644 --- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION +++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION @@ -1 +1 @@ -b3c4fcf +a2d4e4a diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator index b3c4fcfa..a2d4e4ab 160000 --- a/custom_mutators/grammar_mutator/grammar_mutator +++ b/custom_mutators/grammar_mutator/grammar_mutator @@ -1 +1 @@ -Subproject commit b3c4fcfa6ae28918bc410f7747135eafd4fb7263 +Subproject commit a2d4e4ab966f0581219fbb282f5ac8c89e85ead9 diff --git a/docs/Changelog.md b/docs/Changelog.md index 072320dc..4139a9b3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - better fuzzing strategy yields for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 2c814d90..b9a94ac3 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -861,9 +861,9 @@ void show_stats(afl_state_t *afl) { " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); - if (afl->skip_deterministic) { + if (likely(afl->skip_deterministic)) { - strcpy(tmp, "n/a, n/a, n/a"); + strcpy(tmp, "disabled (default, enable with -D)"); } else { @@ -881,7 +881,7 @@ void show_stats(afl_state_t *afl) { " levels : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->max_depth)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]), @@ -897,7 +897,7 @@ void show_stats(afl_state_t *afl) { " pending : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]), @@ -913,7 +913,7 @@ void show_stats(afl_state_t *afl) { " pend fav : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->pending_favored)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]), @@ -929,7 +929,7 @@ void show_stats(afl_state_t *afl) { " own finds : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->queued_discovered)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]), @@ -974,35 +974,52 @@ void show_stats(afl_state_t *afl) { : cRST), tmp); - if (afl->shm.cmplog_mode) { + if (unlikely(afl->afl_env.afl_python_module)) { - sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s", + sprintf(tmp, "%s/%s, ", u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), - u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), - u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON])); + + } else { + + strcpy(tmp, "unused, "); + + } + + if (unlikely(afl->afl_env.afl_custom_mutator_library)) { + + sprintf(tmp, "%s%s/%s, ", tmp, + u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); + + } else { + + strcat(tmp, "unused, "); + + } + + if (unlikely(afl->shm.cmplog_mode)) { + + sprintf(tmp, "%s%s/%s, %s/%s", tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]), u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]), u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS])); - SAYF(bV bSTOP " custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", - tmp); - } else { - sprintf(tmp, "%s/%s, %s/%s", - u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), - u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), - u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); - - SAYF(bV bSTOP " py/custom : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", - tmp); + strcat(tmp, "unused, unused "); } - if (!afl->bytes_trim_out) { + SAYF(bV bSTOP "py/custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", + tmp); + + if (likely(afl->disable_trim)) { + + sprintf(tmp, "disabled, "); + + } else if (unlikely(!afl->bytes_trim_out)) { sprintf(tmp, "n/a, "); @@ -1015,12 +1032,13 @@ void show_stats(afl_state_t *afl) { } - if (!afl->blocks_eff_total) { + if (likely(afl->skip_deterministic)) { - u8 tmp2[128]; + strcat(tmp, "disabled"); - sprintf(tmp2, "n/a"); - strcat(tmp, tmp2); + } else if (unlikely(!afl->blocks_eff_total)) { + + strcat(tmp, "n/a"); } else { -- cgit 1.4.1 From ef33193d77cf82e892fe0b807f0433839155315c Mon Sep 17 00:00:00 2001 From: Ujjwal Kirti <64329707+ujjwalkirti@users.noreply.github.com> Date: Fri, 9 Apr 2021 17:09:53 +0530 Subject: Update ideas.md Hey, I noticed there was a spelling error in above documentation for GSOC '21. I have corrected it, you can have a look at it if you want. --- docs/ideas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ideas.md b/docs/ideas.md index 0130cf61..11c78e49 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -16,7 +16,7 @@ This might look like the afl-fuzz UI, but you can improve on it - and should! Schedulers is a mechanism that selects items from the fuzzing corpus based on strategy and randomness. One scheduler might focus on long paths, -another on rarity of edges disocvered, still another on a combination on +another on rarity of edges discovered, still another on a combination on things. Some of the schedulers in afl++ have to be ported, but you are free to come up with your own if you want to - and see how it performs. -- cgit 1.4.1 From 0c06371cda94e916f62b6456e86b849333acb338 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 11:16:12 +0200 Subject: display dictionary usage in havoc only mode --- src/afl-fuzz-stats.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index b9a94ac3..ed4787ea 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -939,6 +939,14 @@ void show_stats(afl_state_t *afl) { u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); + } else if (unlikely(!afl->extras_cnt)) { + + strcpy(tmp, "n/a"); + + } else { + + strcpy(tmp, "havoc mode"); + } SAYF(bV bSTOP " dictionary : " cRST "%-36s " bSTG bV bSTOP -- cgit 1.4.1 From 50bb931ea604a83784609dc71934a4a8f8feb156 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 11:26:27 +0200 Subject: ui custom mutator only display --- include/afl-fuzz.h | 1 - src/afl-fuzz-stats.c | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 40a7fc85..325168f2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -483,7 +483,6 @@ typedef struct afl_state { no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ - python_only, /* Python-only mode */ is_main_node, /* if this is the main node */ is_secondary_node; /* if this is a secondary instance */ diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index ed4787ea..e0e24a18 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -861,7 +861,11 @@ void show_stats(afl_state_t *afl) { " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); - if (likely(afl->skip_deterministic)) { + if (unlikely(afl->custom_only)) { + + strcpy(tmp, "disabled (custom mutator only mode)"); + + } else if (likely(afl->skip_deterministic)) { strcpy(tmp, "disabled (default, enable with -D)"); @@ -939,7 +943,7 @@ void show_stats(afl_state_t *afl) { u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); - } else if (unlikely(!afl->extras_cnt)) { + } else if (unlikely(!afl->extras_cnt || afl->custom_only)) { strcpy(tmp, "n/a"); -- cgit 1.4.1 From be880f2476963b8ebebe9d8cc196e4e74104c7a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 13:01:50 +0200 Subject: add AFL_EXIT_ON_SEED_ISSUES --- docs/Changelog.md | 3 +++ docs/env_variables.md | 3 +++ include/afl-fuzz.h | 3 ++- include/envs.h | 1 + src/afl-fuzz-init.c | 8 +++++++- src/afl-fuzz-state.c | 7 +++++++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 4139a9b3..14a0bdaf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -24,6 +24,9 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in + -i dir crashes the target or results in a timeout. By default + afl++ ignores these and uses them for splicing instead. - afl-cc: - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 8d482e20..1f4dfef9 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,9 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour + which does not allow crashes or timeout seeds in the initial -i corpus. + - `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap, afl-tmin and afl-analyze create to gather instrumentation data from the target. This must be equal or larger than the size the target was diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 325168f2..f201782a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -384,7 +384,8 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, 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_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, + afl_exit_on_seed_issues; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/envs.h b/include/envs.h index 466ab087..ebe98257 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index e505abd4..b6bfbc29 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -881,7 +881,7 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_TMOUT: - if (afl->timeout_given) { + if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) { /* if we have a timeout but a timeout value was given then always skip. The '+' meaning has been changed! */ @@ -1036,6 +1036,12 @@ void perform_dry_run(afl_state_t *afl) { } + if (afl->afl_env.afl_exit_on_seed_issues) { + + FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits."); + + } + /* Remove from fuzzing queue but keep for splicing */ struct queue_entry *p = afl->queue; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f65ff1bb..28d3339a 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -306,6 +306,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->cycle_schedules = afl->afl_env.afl_cycle_schedules = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_SEED_ISSUES", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_seed_issues = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW", afl_environment_variable_len)) { -- cgit 1.4.1 From 1fabfd5a32ce850912ce623eeabd369b59c70494 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 17:59:11 +0200 Subject: afl-whatsup -d --- afl-whatsup | 45 ++++++++++++++++++++++++++++++++++----------- docs/Changelog.md | 1 + 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/afl-whatsup b/afl-whatsup index e92b24bd..ee20fc2d 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -21,29 +21,37 @@ echo "$0 status check tool for afl-fuzz by Michal Zalewski" echo test "$1" = "-h" -o "$1" = "-hh" && { - echo $0 [-s] output_directory + echo "$0 [-s] [-d] output_directory" echo echo Options: echo -s - skip details and output summary results only + echo -d - include dead fuzzer stats echo exit 1 } -if [ "$1" = "-s" ]; then +unset SUMMARY_ONLY +unset PROCESS_DEAD - SUMMARY_ONLY=1 - DIR="$2" +while [ "$1" = "-s" -o "$1" = "-d" ]; do -else + if [ "$1" = "-s" ]; then + SUMMARY_ONLY=1 + fi - unset SUMMARY_ONLY - DIR="$1" + if [ "$1" = "-d" ]; then + PROCESS_DEAD=1 + fi + + shift -fi +done + +DIR="$1" if [ "$DIR" = "" ]; then - echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2 + echo "Usage: $0 [-s] [-d] afl_sync_dir" 1>&2 echo 1>&2 echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2 echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2 @@ -160,7 +168,12 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do fi DEAD_CNT=$((DEAD_CNT + 1)) - continue + + if [ "$PROCESS_DEAD" = "" ]; then + + continue + + fi fi @@ -257,8 +270,18 @@ echo "=============" echo echo " Fuzzers alive : $ALIVE_CNT" +if [ "$PROCESS_DEAD" = "" ]; then + + TXT="excluded from stats" + +else + + TXT="included in stats" + +fi + if [ ! "$DEAD_CNT" = "0" ]; then - echo " Dead or remote : $DEAD_CNT (excluded from stats)" + echo " Dead or remote : $DEAD_CNT ($TXT)" fi echo " Total run time : $FMT_TIME" diff --git a/docs/Changelog.md b/docs/Changelog.md index 14a0bdaf..bd14e293 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,7 @@ sending a mail to . - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - add -d (dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From 36c7c49738ae659868f70ea7d1b85804158b532f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 18:21:33 +0200 Subject: fix alive count in afl-whatsup --- afl-whatsup | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/afl-whatsup b/afl-whatsup index ee20fc2d..941b0e34 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -265,11 +265,6 @@ fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING test "$TOTAL_TIME" = "0" && TOTAL_TIME=1 -echo "Summary stats" -echo "=============" -echo -echo " Fuzzers alive : $ALIVE_CNT" - if [ "$PROCESS_DEAD" = "" ]; then TXT="excluded from stats" @@ -277,9 +272,15 @@ if [ "$PROCESS_DEAD" = "" ]; then else TXT="included in stats" + ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT)) fi +echo "Summary stats" +echo "=============" +echo +echo " Fuzzers alive : $ALIVE_CNT" + if [ ! "$DEAD_CNT" = "0" ]; then echo " Dead or remote : $DEAD_CNT ($TXT)" fi -- cgit 1.4.1 From ae9087b3909a1d6dc631e59df9f200b11c60e0a2 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 17:30:08 +0200 Subject: update havoc --- src/afl-fuzz-one.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 28ec0c46..d72d4145 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2002,7 +2002,7 @@ havoc_stage: u32 r_max, r; r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) + - (afl->a_extras_cnt ? 2 : 0); + (afl->a_extras_cnt ? 4 : 0); if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { @@ -2587,7 +2587,7 @@ havoc_stage: if (afl->a_extras_cnt) { - if (r == 0) { + if (r < 2) { /* Use the dictionary. */ @@ -2607,7 +2607,7 @@ havoc_stage: break; - } else if (r == 1) { + } else if (r < 4) { u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 extra_len = afl->a_extras[use_extra].len; @@ -2636,7 +2636,7 @@ havoc_stage: } else { - r -= 2; + r -= 4; } -- cgit 1.4.1 From 5e72568a455bde8ac389b8b234cbdbbb0d33e015 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 17:52:43 +0200 Subject: ui update --- docs/status_screen.md | 11 +++++++++-- src/afl-fuzz-stats.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/status_screen.md b/docs/status_screen.md index 0329d960..e3abcc5f 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -251,8 +251,9 @@ exceed it by a margin sufficient to be classified as hangs. | arithmetics : 53/2.54M, 0/537k, 0/55.2k | | known ints : 8/322k, 12/1.32M, 10/1.70M | | dictionary : 9/52k, 1/53k, 1/24k | - | havoc : 1903/20.0M, 0/0 | - | trim : 20.31%/9201, 17.05% | + |havoc/splice : 1903/20.0M, 0/0 | + |py/custom/rq : unused, 53/2.54M, unused | + | trim/eff : 20.31%/9201, 17.05% | +-----------------------------------------------------+ ``` @@ -268,6 +269,12 @@ goal. Finally, the third number shows the proportion of bytes that, although not possible to remove, were deemed to have no effect and were excluded from some of the more expensive deterministic fuzzing steps. +Note that when deterministic mutation mode is off (which is the default +because it is not very efficient) the first five lines display +"disabled (default, enable with -D)". + +Only what is activated will have counter shown. + ### Path geometry ``` diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index e0e24a18..009cebf6 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1074,7 +1074,7 @@ void show_stats(afl_state_t *afl) { // //} else { - SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bV RESET_G1, tmp); + SAYF(bV bSTOP " trim/eff : " cRST "%-36s " bSTG bV RESET_G1, tmp); //} -- cgit 1.4.1 From 92a308133797a1926507361e71b84f8b1eacc754 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 18:24:05 +0200 Subject: fix aflpp qemu hook --- docs/Changelog.md | 1 + utils/aflpp_driver/aflpp_qemu_driver_hook.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index bd14e293..155eec66 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,7 @@ sending a mail to . - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - add -d (dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index 823cc42d..dc58d852 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -3,8 +3,8 @@ #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) -#define REGS_RDI 7 -#define REGS_RSI 6 +#define REGS_RDI 4 +#define REGS_RSI 5 void afl_persistent_hook(uint64_t *regs, uint64_t guest_base, uint8_t *input_buf, uint32_t input_len) { -- cgit 1.4.1 From 6069cac313f4f8f4e696e815d4fe2f8bcaccccf4 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 14 Apr 2021 18:24:55 +0200 Subject: qemu driver new api --- utils/aflpp_driver/aflpp_qemu_driver_hook.c | 21 +++++++++++++++------ utils/qemu_persistent_hook/read_into_rdi.c | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index 823cc42d..d3dd98b0 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -1,21 +1,30 @@ +#include "../../qemu_mode/qemuafl/qemuafl/api.h" + #include #include +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) +#define h2g(x) ((uint64_t)(x)-guest_base) -#define REGS_RDI 7 -#define REGS_RSI 6 + // In this example the register RDI is pointing to the memory location + // of the target buffer, and the length of the input is in RSI. + // This can be seen with a debugger, e.g. gdb (and "disass main") -void afl_persistent_hook(uint64_t *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_len) { + memcpy(g2h(regs->rdi), input_buf, input_buf_len); + regs->rsi = input_buf_len; - memcpy(g2h(regs[REGS_RDI]), input_buf, input_len); - regs[REGS_RSI] = input_len; +#undef g2h +#undef h2g } int afl_persistent_hook_init(void) { + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) return 1; } diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c index f4a8ae59..c1c6642f 100644 --- a/utils/qemu_persistent_hook/read_into_rdi.c +++ b/utils/qemu_persistent_hook/read_into_rdi.c @@ -5,7 +5,7 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, uint8_t *input_buf, uint32_t input_buf_len) { -\ + #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) -- cgit 1.4.1 From f0d300b32a8a5b3adccc8209c151382244135082 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 18:36:22 +0200 Subject: add readme --- utils/aflpp_driver/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 utils/aflpp_driver/README.md diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md new file mode 100644 index 00000000..2c339d12 --- /dev/null +++ b/utils/aflpp_driver/README.md @@ -0,0 +1,25 @@ +# afl++ drivers + +## aflpp_driver + +aflpp_driver is used to compile directly libfuzzer `LLVMFuzzerTestOneInput()` +targets. + +Just do `afl-clang-fast++ -o fuzz fuzzer_harness.cc libAFLDriver.a [plus required linking]`. + +You can also sneakily do this little trick: +If this is the clang compile command to build for libfuzzer: + `clang++ -o fuzz -fsanitize=fuzzer fuzzer_harness.cc -lfoo` +then just switch `clang++` with `afl-clang-fast++` and our compiler will +magically insert libAFLDriver.a :) + + +## aflpp_qemu_driver + +aflpp_qemu_driver is used for libfuzzer `LLVMFuzzerTestOneInput()` targets that +are to be fuzzed in qemu_mode. So we compile them with clang/clang++, without +-fsantize=fuzzer or afl-clang-fast, and link in libAFLQemuDriver.a: + +`clang++ -o fuzz fuzzer_harness.cc libAFLQemuDriver.a [plus required linking]`. + +Then just do `AFL_PRELOAD=/path/to/aflpp_qemu_driver_hook.so afl-fuzz -Q ... -- ./fuzz` -- cgit 1.4.1 From fd8dc1455278bca16e852eb08ddac9a3e466b5c7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 18:49:02 +0200 Subject: update readme --- utils/aflpp_driver/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md index 2c339d12..01bd10c0 100644 --- a/utils/aflpp_driver/README.md +++ b/utils/aflpp_driver/README.md @@ -22,4 +22,9 @@ are to be fuzzed in qemu_mode. So we compile them with clang/clang++, without `clang++ -o fuzz fuzzer_harness.cc libAFLQemuDriver.a [plus required linking]`. -Then just do `AFL_PRELOAD=/path/to/aflpp_qemu_driver_hook.so afl-fuzz -Q ... -- ./fuzz` + +Then just do (where the name of the binary is `fuzz`): +``` +AFL_QEMU_PERSISTENT_ADDR=0x$(nm fuzz | grep "T LLVMFuzzerTestOneInput" | awk '{print $1}') +AFL_QEMU_PERSISTENT_HOOK=/path/to/aflpp_qemu_driver_hook.so afl-fuzz -Q ... -- ./fuzz` +``` -- cgit 1.4.1 From 4a0e0270adafbc583d491dfad74d9378a4c06bf7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 22:23:16 +0200 Subject: allow aflpp_qemu_driver_hook.o to fail --- utils/aflpp_driver/GNUmakefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index c1a087d7..8ac054a6 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -26,17 +26,17 @@ debug: ar ru libAFLDriver.a afl-performance.o aflpp_driver.o aflpp_qemu_driver.o: aflpp_qemu_driver.c - $(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c + -$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c libAFLQemuDriver.a: aflpp_qemu_driver.o - ar ru libAFLQemuDriver.a aflpp_qemu_driver.o - cp -vf libAFLQemuDriver.a ../../ + -ar ru libAFLQemuDriver.a aflpp_qemu_driver.o + -cp -vf libAFLQemuDriver.a ../../ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so + -$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - $(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + -$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c -- cgit 1.4.1 From ab0f13ed068a7ef47cc84e6871428e1812382688 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 00:11:32 +0200 Subject: fix writing stat file on exit --- src/afl-fuzz-stats.c | 43 +++++++++++++++++++++++-------------------- src/afl-fuzz.c | 1 - 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 009cebf6..fa1f3c70 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -355,18 +355,18 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, double eps) { - if (unlikely(afl->stop_soon) || - unlikely(afl->plot_prev_qp == afl->queued_paths && - afl->plot_prev_pf == afl->pending_favored && - afl->plot_prev_pnf == afl->pending_not_fuzzed && - afl->plot_prev_ce == afl->current_entry && - afl->plot_prev_qc == afl->queue_cycle && - afl->plot_prev_uc == afl->unique_crashes && - afl->plot_prev_uh == afl->unique_hangs && - afl->plot_prev_md == afl->max_depth && - afl->plot_prev_ed == afl->fsrv.total_execs) || - unlikely(!afl->queue_cycle) || - unlikely(get_cur_time() - afl->start_time <= 60)) { + if (unlikely(!afl->force_ui_update && + (afl->stop_soon || + (afl->plot_prev_qp == afl->queued_paths && + afl->plot_prev_pf == afl->pending_favored && + afl->plot_prev_pnf == afl->pending_not_fuzzed && + afl->plot_prev_ce == afl->current_entry && + afl->plot_prev_qc == afl->queue_cycle && + afl->plot_prev_uc == afl->unique_crashes && + afl->plot_prev_uh == afl->unique_hangs && + afl->plot_prev_md == afl->max_depth && + afl->plot_prev_ed == afl->fsrv.total_execs) || + !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { return; @@ -531,7 +531,8 @@ void show_stats(afl_state_t *afl) { /* Roughly every minute, update fuzzer stats and save auto tokens. */ - if (cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000) { + if (unlikely(afl->force_ui_update || + cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000)) { afl->stats_last_stats_ms = cur_ms; write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio, @@ -543,7 +544,8 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_statsd)) { - if (cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000) { + if (unlikely(afl->force_ui_update && cur_ms - afl->statsd_last_send_ms > + STATSD_UPDATE_SEC * 1000)) { /* reset counter, even if send failed. */ afl->statsd_last_send_ms = cur_ms; @@ -555,7 +557,8 @@ void show_stats(afl_state_t *afl) { /* Every now and then, write plot data. */ - if (cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000) { + if (unlikely(afl->force_ui_update || + cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000)) { afl->stats_last_plot_ms = cur_ms; maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec); @@ -564,14 +567,14 @@ void show_stats(afl_state_t *afl) { /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ - if (!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 && - !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done) { + if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 && + !afl->pending_not_fuzzed && afl->afl_env.afl_exit_when_done)) { afl->stop_soon = 2; } - if (afl->total_crashes && afl->afl_env.afl_bench_until_crash) { + if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) { afl->stop_soon = 2; @@ -583,7 +586,7 @@ void show_stats(afl_state_t *afl) { /* If we haven't started doing things, bail out. */ - if (!afl->queue_cur) { return; } + if (unlikely(!afl->queue_cur)) { return; } /* Compute some mildly useful bitmap stats. */ @@ -602,7 +605,7 @@ void show_stats(afl_state_t *afl) { SAYF(TERM_HOME); - if (afl->term_too_small) { + if (unlikely(afl->term_too_small)) { SAYF(cBRI "Your terminal is too small to display the UI.\n" diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9688c84f..d9bf2b28 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2130,7 +2130,6 @@ int main(int argc, char **argv_orig, char **envp) { stop_fuzzing: - write_stats_file(afl, 0, 0, 0, 0); afl->force_ui_update = 1; // ensure the screen is reprinted show_stats(afl); // print the screen one last time -- cgit 1.4.1 From 61a918f820da0d4c6285e8a9fe32fe2ab4c08510 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 10:43:18 +0200 Subject: remove duplicate plot file write --- src/afl-fuzz.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index d9bf2b28..a61a817a 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2125,7 +2125,6 @@ int main(int argc, char **argv_orig, char **envp) { } write_bitmap(afl); - maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); stop_fuzzing: -- cgit 1.4.1 From cd40fa1745de1aba6549dd37d1d94b0e26cce442 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 11:04:39 +0200 Subject: fix warnings --- src/afl-fuzz-stats.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index fa1f3c70..d1e5e9f8 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -427,7 +427,7 @@ void show_stats(afl_state_t *afl) { u32 t_bytes, t_bits; u32 banner_len, banner_pad; - u8 tmp[256]; + u8 tmp[256], tmp2[256]; u8 time_tmp[64]; u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX]; @@ -991,31 +991,31 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_python_module)) { - sprintf(tmp, "%s/%s, ", + sprintf(tmp, "%s/%s,", u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON])); } else { - strcpy(tmp, "unused, "); + strcpy(tmp, "unused,"); } if (unlikely(afl->afl_env.afl_custom_mutator_library)) { - sprintf(tmp, "%s%s/%s, ", tmp, + sprintf(tmp2, " %s%s/%s,", tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]), u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); } else { - strcat(tmp, "unused, "); + strcat(tmp2, " unused,"); } if (unlikely(afl->shm.cmplog_mode)) { - sprintf(tmp, "%s%s/%s, %s/%s", tmp, + sprintf(tmp, "%s %s/%s, %s/%s", tmp2, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]), u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]), @@ -1023,7 +1023,7 @@ void show_stats(afl_state_t *afl) { } else { - strcat(tmp, "unused, unused "); + sprintf(tmp, "%s unused, unused", tmp2); } -- cgit 1.4.1 From 71f3d82d430cc82c0654083b8cd1d78d59f88ca9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 11:23:46 +0200 Subject: afl-whatsup -d fix --- afl-whatsup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/afl-whatsup b/afl-whatsup index 941b0e34..be259829 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -141,7 +141,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP" . "$TMP" - RUN_UNIX=$((CUR_TIME - start_time)) + RUN_UNIX=$run_time RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24)) RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24)) @@ -168,6 +168,7 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do fi DEAD_CNT=$((DEAD_CNT + 1)) + last_path=0 if [ "$PROCESS_DEAD" = "" ]; then -- cgit 1.4.1 From b815c32f0ef789dd6d33f5de4d0b524664d41195 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 12:22:05 +0200 Subject: fix ui --- src/afl-fuzz-stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d1e5e9f8..a1559eac 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1003,13 +1003,13 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_custom_mutator_library)) { - sprintf(tmp2, " %s%s/%s,", tmp, + sprintf(tmp2, "%s %s/%s,", tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]), u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); } else { - strcat(tmp2, " unused,"); + sprintf(tmp2, "%s unused,", tmp); } -- cgit 1.4.1 From f2a83c4a508cb6c81f9a7f387b693d057af3a726 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 13:20:57 +0200 Subject: update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c94872be..e7582aff 100644 --- a/README.md +++ b/README.md @@ -606,7 +606,8 @@ For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`) - * one should fuzz the target with CMPLOG/redqueen (see above) + * one or two should fuzz the target with CMPLOG/redqueen (see above), at + least one cmplog instance should follow transformations (`-l AT`) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV fuzzer and you want them to share their intermediate results, the main -- cgit 1.4.1 From 9d3a2b693a8725983a809af3799b190781130c30 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 15 Apr 2021 14:10:04 +0200 Subject: qemuafl --- qemu_mode/QEMUAFL_VERSION | 2 +- qemu_mode/qemuafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION index 8d95c359..0fb33ae2 100644 --- a/qemu_mode/QEMUAFL_VERSION +++ b/qemu_mode/QEMUAFL_VERSION @@ -1 +1 @@ -ddc4a9748d +d73b0336b4 diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index ddc4a974..d73b0336 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit ddc4a9748d59857753fb33c30a356f354595f36d +Subproject commit d73b0336b451fd034e5f469089fb7ee96c80adf2 -- cgit 1.4.1 From d0390f3b7651efefeecf80ebf2b1a740c077f21f Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 15 Apr 2021 14:42:54 +0200 Subject: fix compcovtest --- qemu_mode/libcompcov/compcovtest.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index d70bba91..8346c5b9 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -20,22 +20,29 @@ // solution: echo -ne 'The quick brown fox jumps over the lazy // dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest +#include "../../include/config.h" + #include #include #include #include -int main() { - - char buffer[44] = {/* zero padding */}; - fread(buffer, 1, sizeof(buffer) - 1, stdin); +int main(int argc, char**argv) { + + static char buffer[MAX_FILE] = {/* zero padding */}; + + FILE* file = stdin; + if (argc > 1) + file = fopen(argv[1], "r"); + + fread(buffer, 1, sizeof(buffer) - 1, file); if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || strncmp(&buffer[20], "jumps over ", 11) != 0 || strcmp(&buffer[31], "the lazy dog") != 0) { - + return 1; - + } uint64_t x = 0; @@ -50,18 +57,18 @@ int main() { fread(&z, sizeof(z), 1, stdin); switch (z) { - + case 0xBEEF: break; default: return 4; - + } printf("Puzzle solved, congrats!\n"); abort(); return 0; - + } - + -- cgit 1.4.1 From 43e16cf13dfffa27f9cde49a3bba026cef96b1c4 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 15 Apr 2021 15:05:14 +0200 Subject: fix compcovtest --- qemu_mode/libcompcov/compcovtest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index 8346c5b9..6fe501c0 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -29,7 +29,7 @@ int main(int argc, char**argv) { - static char buffer[MAX_FILE] = {/* zero padding */}; + char buffer[44] = {/* zero padding */}; FILE* file = stdin; if (argc > 1) -- cgit 1.4.1 From 45b5e3622e4339b806a8f3d44bcde5c89f58677e Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 15 Apr 2021 15:12:32 +0200 Subject: fix compcovtest --- qemu_mode/libcompcov/compcovtest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index 6fe501c0..69c6aa09 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -46,15 +46,15 @@ int main(int argc, char**argv) { } uint64_t x = 0; - fread(&x, sizeof(x), 1, stdin); + fread(&x, sizeof(x), 1, file); if (x != 0xCAFEBABECAFEBABE) { return 2; } uint32_t y = 0; - fread(&y, sizeof(y), 1, stdin); + fread(&y, sizeof(y), 1, file); if (y != 0xDEADC0DE) { return 3; } uint16_t z = 0; - fread(&z, sizeof(z), 1, stdin); + fread(&z, sizeof(z), 1, file); switch (z) { -- cgit 1.4.1 From 4f93220c4bfbffc51e18159d30e08884a4d7dfc1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Apr 2021 16:50:44 +0200 Subject: cmplog -l3: disable trimming, forcing input2stage for all --- src/afl-fuzz-redqueen.c | 26 +++++++++++++++++++++++++- src/afl-fuzz.c | 8 ++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 9bfbf95b..cf1e5ea5 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -437,7 +437,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, if (taint) { - if (afl->colorize_success && + if (afl->colorize_success && afl->cmplog_lvl < 3 && (len / positions == 1 && positions > CMPLOG_POSITIONS_MAX && afl->active_paths / afl->colorize_success > CMPLOG_CORPUS_PERCENT)) { @@ -1749,6 +1749,12 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, #endif +#ifdef _DEBUG + if (o->v0 != orig_o->v0 || o->v1 != orig_o->v1) + fprintf(stderr, "key=%u idx=%u o0=%llu v0=%llu o1=%llu v1=%llu\n", key, + idx, orig_o->v0, o->v0, orig_o->v1, o->v1); +#endif + // even for u128 and _ExtInt we do cmp_extend_encoding() because // if we got here their own special trials failed and it might just be // a cast from e.g. u64 to u128 from the input data. @@ -2365,6 +2371,24 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, status = 0; +#ifdef _DEBUG + int w; + fprintf(stderr, "key=%u idx=%u len=%u o0=", key, idx, + SHAPE_BYTES(h->shape)); + for (w = 0; w < SHAPE_BYTES(h->shape); ++w) + fprintf(stderr, "%02x", orig_o->v0[w]); + fprintf(stderr, " v0="); + for (w = 0; w < SHAPE_BYTES(h->shape); ++w) + fprintf(stderr, "%02x", o->v0[w]); + fprintf(stderr, " o1="); + for (w = 0; w < SHAPE_BYTES(h->shape); ++w) + fprintf(stderr, "%02x", orig_o->v1[w]); + fprintf(stderr, " v1="); + for (w = 0; w < SHAPE_BYTES(h->shape); ++w) + fprintf(stderr, "%02x", o->v1[w]); + fprintf(stderr, "\n"); +#endif + if (unlikely(rtn_extend_encoding( afl, o->v0, o->v1, orig_o->v0, orig_o->v1, SHAPE_BYTES(h->shape), idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a61a817a..2b035a23 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -855,6 +855,14 @@ int main(int argc, char **argv_orig, char **envp) { break; case '3': afl->cmplog_lvl = 3; + + if (!afl->disable_trim) { + + ACTF("Deactivating trimming due CMPLOG level 3"); + afl->disable_trim = 1; + + } + break; case 'a': case 'A': -- cgit 1.4.1 From c8e96e52536d47ee41967657202574d8e61562ee Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 15 Apr 2021 23:56:58 +0200 Subject: autoformat with black --- frida_mode/test/testinstr.py | 49 ++++--- unicorn_mode/helper_scripts/ida_context_loader.py | 84 +++++++----- utils/autodict_ql/autodict-ql.py | 154 ++++++++++++---------- utils/autodict_ql/litan.py | 126 +++++++++++------- utils/autodict_ql/memcmp-strings.py | 64 +++++---- utils/autodict_ql/stan-strings.py | 64 +++++---- utils/autodict_ql/strcmp-strings.py | 64 +++++---- utils/autodict_ql/strncmp-strings.py | 64 +++++---- 8 files changed, 409 insertions(+), 260 deletions(-) diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/testinstr.py index 8f5fe886..f648808b 100755 --- a/frida_mode/test/testinstr.py +++ b/frida_mode/test/testinstr.py @@ -1,32 +1,49 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import argparse from elftools.elf.elffile import ELFFile + def process_file(file, section, base): - with open(file, 'rb') as f: + with open(file, "rb") as f: for sect in ELFFile(f).iter_sections(): - if (sect.name == section): - start = base + sect.header['sh_offset'] - end = start + sect.header['sh_size'] - print ("0x%016x-0x%016x" % (start, end)) + if sect.name == section: + start = base + sect.header["sh_offset"] + end = start + sect.header["sh_size"] + print("0x%016x-0x%016x" % (start, end)) return - print ("Section '%s' not found in '%s'" % (section, file)) + print("Section '%s' not found in '%s'" % (section, file)) + def hex_value(x): return int(x, 16) + def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--section', dest='section', type=str, - help='elf section name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument( + "-f", "--file", dest="file", type=str, help="elf file name", required=True + ) + parser.add_argument( + "-s", + "--section", + dest="section", + type=str, + help="elf section name", + required=True, + ) + parser.add_argument( + "-b", + "--base", + dest="base", + type=hex_value, + help="elf base address", + required=True, + ) args = parser.parse_args() - process_file (args.file, args.section, args.base) + process_file(args.file, args.section, args.base) + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/unicorn_mode/helper_scripts/ida_context_loader.py b/unicorn_mode/helper_scripts/ida_context_loader.py index 31d47a90..d7984c77 100644 --- a/unicorn_mode/helper_scripts/ida_context_loader.py +++ b/unicorn_mode/helper_scripts/ida_context_loader.py @@ -34,13 +34,11 @@ import ida_segment class ContextLoaderError(Exception): - """Base "catch all" exception for this script - """ + """Base "catch all" exception for this script""" class ArchNotSupportedError(ContextLoaderError): - """Exception raised if the input file CPU architecture isn't supported fully - """ + """Exception raised if the input file CPU architecture isn't supported fully""" def parse_mapping_index(filepath: str): @@ -51,13 +49,16 @@ def parse_mapping_index(filepath: str): """ if filepath is None: - raise ContextLoaderError('_index.json file was not selected') + raise ContextLoaderError("_index.json file was not selected") try: - with open(filepath, 'rb') as _file: + with open(filepath, "rb") as _file: return json.load(_file) except Exception as ex: - raise ContextLoaderError('Failed to parse json file {}'.format(filepath)) from ex + raise ContextLoaderError( + "Failed to parse json file {}".format(filepath) + ) from ex + def get_input_name(): """Get the name of the input file @@ -68,19 +69,21 @@ def get_input_name(): input_filepath = ida_nalt.get_input_file_path() return Path(input_filepath).name + def write_segment_bytes(start: int, filepath: str): - """"Read data from context file and write it to the IDA segment + """ "Read data from context file and write it to the IDA segment :param start: Start address :param filepath: Path to context file """ - with open(filepath, 'rb') as _file: + with open(filepath, "rb") as _file: data = _file.read() decompressed_data = zlib.decompress(data) ida_bytes.put_bytes(start, decompressed_data) + def create_segment(context_dir: str, segment: dict, is_be: bool): """Create segment in IDA and map in the data from the file @@ -90,23 +93,30 @@ def create_segment(context_dir: str, segment: dict, is_be: bool): """ input_name = get_input_name() - if Path(segment['name']).name != input_name: + if Path(segment["name"]).name != input_name: ida_seg = idaapi.segment_t() - ida_seg.start_ea = segment['start'] - ida_seg.end_ea = segment['end'] + ida_seg.start_ea = segment["start"] + ida_seg.end_ea = segment["end"] ida_seg.bitness = 1 if is_be else 0 - if segment['permissions']['r']: + if segment["permissions"]["r"]: ida_seg.perm |= ida_segment.SEGPERM_READ - if segment['permissions']['w']: + if segment["permissions"]["w"]: ida_seg.perm |= ida_segment.SEGPERM_WRITE - if segment['permissions']['x']: + if segment["permissions"]["x"]: ida_seg.perm |= ida_segment.SEGPERM_EXEC - idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'CODE', idaapi.ADDSEG_OR_DIE) + idaapi.add_segm_ex( + ida_seg, Path(segment["name"]).name, "CODE", idaapi.ADDSEG_OR_DIE + ) else: - idaapi.add_segm_ex(ida_seg, Path(segment['name']).name, 'DATA', idaapi.ADDSEG_OR_DIE) + idaapi.add_segm_ex( + ida_seg, Path(segment["name"]).name, "DATA", idaapi.ADDSEG_OR_DIE + ) + + if segment["content_file"]: + write_segment_bytes( + segment["start"], PurePath(context_dir, segment["content_file"]) + ) - if segment['content_file']: - write_segment_bytes(segment['start'], PurePath(context_dir, segment['content_file'])) def create_segments(index: dict, context_dir: str): """Iterate segments in index JSON, create the segment in IDA, and map in the data from the file @@ -117,9 +127,10 @@ def create_segments(index: dict, context_dir: str): info = idaapi.get_inf_structure() is_be = info.is_be() - for segment in index['segments']: + for segment in index["segments"]: create_segment(context_dir, segment, is_be) + def rebase_program(index: dict): """Rebase the program to the offset specified in the context _index.json @@ -128,20 +139,21 @@ def rebase_program(index: dict): input_name = get_input_name() new_base = None - for segment in index['segments']: - if not segment['name']: + for segment in index["segments"]: + if not segment["name"]: continue - segment_name = Path(segment['name']).name + segment_name = Path(segment["name"]).name if input_name == segment_name: - new_base = segment['start'] + new_base = segment["start"] break if not new_base: - raise ContextLoaderError('Input file is not in _index.json') + raise ContextLoaderError("Input file is not in _index.json") current_base = idaapi.get_imagebase() - ida_segment.rebase_program(new_base-current_base, 8) + ida_segment.rebase_program(new_base - current_base, 8) + def get_pc_by_arch(index: dict) -> int: """Queries the input file CPU architecture and attempts to lookup the address of the program @@ -153,13 +165,14 @@ def get_pc_by_arch(index: dict) -> int: progctr = None info = idaapi.get_inf_structure() - if info.procname == 'metapc': + if info.procname == "metapc": if info.is_64bit(): - progctr = index['regs']['rax'] + progctr = index["regs"]["rax"] elif info.is_32bit(): - progctr = index['regs']['eax'] + progctr = index["regs"]["eax"] return progctr + def write_reg_info(index: dict): """Write register info as line comment at instruction pointed to by the program counter and change focus to that location @@ -167,17 +180,19 @@ def write_reg_info(index: dict): :param index: _index.json JSON data """ - cmt = '' - for reg, val in index['regs'].items(): + cmt = "" + for reg, val in index["regs"].items(): cmt += f"{reg.ljust(6)} : {hex(val)}\n" progctr = get_pc_by_arch(index) if progctr is None: raise ArchNotSupportedError( - 'Architecture not fully supported, skipping register status comment') + "Architecture not fully supported, skipping register status comment" + ) ida_bytes.set_cmt(progctr, cmt, 0) ida_kernwin.jumpto(progctr) + def main(filepath): """Main - parse _index.json input and map context files into the database @@ -193,5 +208,6 @@ def main(filepath): except ContextLoaderError as ex: print(ex) -if __name__ == '__main__': - main(ida_kernwin.ask_file(1, '*.json', 'Import file name')) + +if __name__ == "__main__": + main(ida_kernwin.ask_file(1, "*.json", "Import file name")) diff --git a/utils/autodict_ql/autodict-ql.py b/utils/autodict_ql/autodict-ql.py index 0fe7eabf..f64e3fae 100644 --- a/utils/autodict_ql/autodict-ql.py +++ b/utils/autodict_ql/autodict-ql.py @@ -11,7 +11,7 @@ import os import string -import binascii +import binascii import codecs import errno import struct @@ -21,6 +21,7 @@ import subprocess from binascii import unhexlify + def ensure_dir(dir): try: os.makedirs(dir) @@ -28,109 +29,118 @@ def ensure_dir(dir): if e.errno != errno.EEXIST: raise + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - - #parser.add_argument("tokenpath", - #help="Destination directory for tokens") - parser.add_argument("cur", - help = "Current Path") - parser.add_argument("db", - help = "CodeQL database Path") - parser.add_argument("tokenpath", - help="Destination directory for tokens") + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + ) + ) + + # parser.add_argument("tokenpath", + # help="Destination directory for tokens") + parser.add_argument("cur", help="Current Path") + parser.add_argument("db", help="CodeQL database Path") + parser.add_argument("tokenpath", help="Destination directory for tokens") return parser.parse_args() -def static_analysis(file,file2,cur,db) : - with open(cur+"/"+file, "w") as f: - print(cur+"/"+file) - stream = os.popen("codeql query run " + cur +"/"+ file2 + " -d " + db ) + +def static_analysis(file, file2, cur, db): + with open(cur + "/" + file, "w") as f: + print(cur + "/" + file) + stream = os.popen("codeql query run " + cur + "/" + file2 + " -d " + db) output = stream.read() f.write(output) f.close() -def copy_tokens(cur, tokenpath) : - subprocess.call(["mv " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["mv " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["mv " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["mv " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["mv " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."] ,shell=True) - subprocess.call(["rm -rf strcmp-strs memcmp-strs strncmp-strs lits strtool-strs"],shell=True) - subprocess.call(["rm *.out"],shell=True) - subprocess.call(["find "+tokenpath+" -size 0 -delete"],shell=True) - - - -def codeql_analysis(cur, db) : - static_analysis("litout.out","litool.ql", cur, db) - static_analysis("strcmp-strings.out","strcmp-str.ql", cur, db) - static_analysis("strncmp-strings.out","strncmp-str.ql", cur, db) - static_analysis("memcmp-strings.out","memcmp-str.ql", cur, db) - static_analysis("strtool-strings.out","strtool.ql", cur, db) - start_autodict(0,cur) +def copy_tokens(cur, tokenpath): + subprocess.call( + ["mv " + cur + "/" + "strcmp-strs/*" + " " + cur + "/" + tokenpath + "/."], + shell=True, + ) + subprocess.call( + ["mv " + cur + "/" + "strncmp-strs/*" + " " + cur + "/" + tokenpath + "/."], + shell=True, + ) + subprocess.call( + ["mv " + cur + "/" + "memcmp-strs/*" + " " + cur + "/" + tokenpath + "/."], + shell=True, + ) + subprocess.call( + ["mv " + cur + "/" + "lits/*" + " " + cur + "/" + tokenpath + "/."], shell=True + ) + subprocess.call( + ["mv " + cur + "/" + "strtool-strs/*" + " " + cur + "/" + tokenpath + "/."], + shell=True, + ) + subprocess.call( + ["rm -rf strcmp-strs memcmp-strs strncmp-strs lits strtool-strs"], shell=True + ) + subprocess.call(["rm *.out"], shell=True) + subprocess.call(["find " + tokenpath + " -size 0 -delete"], shell=True) + + +def codeql_analysis(cur, db): + static_analysis("litout.out", "litool.ql", cur, db) + static_analysis("strcmp-strings.out", "strcmp-str.ql", cur, db) + static_analysis("strncmp-strings.out", "strncmp-str.ql", cur, db) + static_analysis("memcmp-strings.out", "memcmp-str.ql", cur, db) + static_analysis("strtool-strings.out", "strtool.ql", cur, db) + start_autodict(0, cur) def start_autodict(tokenpath, cur): - command = [ - 'python3', - cur + '/litan.py', - cur+'/lits/', - cur+'/litout.out' - ] + command = ["python3", cur + "/litan.py", cur + "/lits/", cur + "/litout.out"] worker1 = subprocess.Popen(command) print(worker1.communicate()) - + command1 = [ - 'python3', - cur + '/strcmp-strings.py', - cur + '/strcmp-strs/', - cur + '/strcmp-strings.out' - ] + "python3", + cur + "/strcmp-strings.py", + cur + "/strcmp-strs/", + cur + "/strcmp-strings.out", + ] worker2 = subprocess.Popen(command1) print(worker2.communicate()) command2 = [ - 'python3', - cur + '/strncmp-strings.py', - cur + '/strncmp-strs/', - cur + '/strncmp-strings.out' - ] + "python3", + cur + "/strncmp-strings.py", + cur + "/strncmp-strs/", + cur + "/strncmp-strings.out", + ] worker3 = subprocess.Popen(command2) print(worker3.communicate()) - - command5 = [ - 'python3', - cur + '/memcmp-strings.py', - cur + '/memcmp-strs/', - cur + '/memcmp-strings.out' - ] + "python3", + cur + "/memcmp-strings.py", + cur + "/memcmp-strs/", + cur + "/memcmp-strings.out", + ] worker6 = subprocess.Popen(command5) print(worker6.communicate()) - - command8 = [ - 'python3', - cur + '/stan-strings.py', - cur + '/strtool-strs/', - cur + '/strtool-strings.out' - ] + "python3", + cur + "/stan-strings.py", + cur + "/strtool-strs/", + cur + "/strtool-strings.out", + ] worker9 = subprocess.Popen(command8) print(worker9.communicate()) - def main(): - args = parse_args() + args = parse_args() ensure_dir(args.tokenpath) - #copy_tokens(args.cur, args.tokenpath) + # copy_tokens(args.cur, args.tokenpath) codeql_analysis(args.cur, args.db) copy_tokens(args.cur, args.tokenpath) - #start_autodict(args.tokenpath, args.cur) -if __name__ == '__main__': - main() \ No newline at end of file + # start_autodict(args.tokenpath, args.cur) + + +if __name__ == "__main__": + main() diff --git a/utils/autodict_ql/litan.py b/utils/autodict_ql/litan.py index 18c04c34..7033d363 100644 --- a/utils/autodict_ql/litan.py +++ b/utils/autodict_ql/litan.py @@ -4,7 +4,7 @@ # Author : Microsvuln - Arash.vre@gmail.com import string import os -import binascii +import binascii import codecs import struct import errno @@ -12,75 +12,101 @@ import argparse import re import base64 from binascii import unhexlify + + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt")) - parser.add_argument("corpdir", - help="The path to the corpus directory to generate files.") - parser.add_argument("infile", - help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt") - return parser.parse_args() + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file to analysis and output folder to save corpdirus for constants in the overall project ------- Example usage : python2 thisfile.py outdir o.txt" + ) + ) + parser.add_argument( + "corpdir", help="The path to the corpus directory to generate files." + ) + parser.add_argument( + "infile", + help="Specify file output of codeql analysis - ex. ooo-hex.txt, analysis take place on this file, example : python2 thisfile.py outdir out.txt", + ) + return parser.parse_args() + + def ensure_dir(dir): try: os.makedirs(dir) except OSError as e: if e.errno == errno.EEXIST: - #print "[-] Directory exists, specify another directory" + # print "[-] Directory exists, specify another directory" exit(1) + + def do_analysis1(corpdir, infile): - with open(infile, "rb") as f: - lines = f.readlines()[1:] - f.close() + with open(infile, "rb") as f: + lines = f.readlines()[1:] + f.close() new_lst = [] n = 1 for i, num in enumerate(lines): if i != 0: - new_lst.append(num) + new_lst.append(num) str1 = str(num) - print ("num is " + str1) - str1 = str1.rstrip('\n\n') - #str1 = str1.replace("0x",""); - str1 = str1.replace("|","") - str1 = str1.rstrip('\r\n') - str1 = str1.rstrip('\n') - str1 = str1.replace(" ","") - #str1 = str1.translate(None, string.punctuation) - translator=str.maketrans('','',string.punctuation) - str1=str1.translate(translator) + print("num is " + str1) + str1 = str1.rstrip("\n\n") + # str1 = str1.replace("0x",""); + str1 = str1.replace("|", "") + str1 = str1.rstrip("\r\n") + str1 = str1.rstrip("\n") + str1 = str1.replace(" ", "") + # str1 = str1.translate(None, string.punctuation) + translator = str.maketrans("", "", string.punctuation) + str1 = str1.translate(translator) str1 = str1[1:] str1 = str1[:-1] print("After cleanup : " + str1) - if (str1 != '0') and (str1 != 'ffffffff') and (str1 != 'fffffffe') or (len(str1) == 4) or (len(str1) == 8): - print ("first : "+str1) - if len(str1) > 8 : + if ( + (str1 != "0") + and (str1 != "ffffffff") + and (str1 != "fffffffe") + or (len(str1) == 4) + or (len(str1) == 8) + ): + print("first : " + str1) + if len(str1) > 8: str1 = str1[:-1] - elif (len(str1) == 5) : + elif len(str1) == 5: str1 = str1 = "0" try: - #str1 = str1.decode("hex") - with open(corpdir+'/lit-seed{0}'.format(n), 'w') as file: - str1 = str1.replace("0x",""); - print (str1) - str1 = int(str1,base=16) - str1 = str1.to_bytes(4, byteorder='little') - file.write(str(str1)) - file.close() - with open (corpdir+'/lit-seed{0}'.format(n), 'r') as q : - a = q.readline() - a = a[1:] - print ("AFL++ Autodict-QL by Microsvuln : Writing Token :" + str(a)) - q.close() - with open (corpdir+'/lit-seed{0}'.format(n), 'w') as w1 : - w1.write(str(a)) - print ("Done!") - w1.close() - except: - print("Error!") - n = n+1 + # str1 = str1.decode("hex") + with open(corpdir + "/lit-seed{0}".format(n), "w") as file: + str1 = str1.replace("0x", "") + print(str1) + str1 = int(str1, base=16) + str1 = str1.to_bytes(4, byteorder="little") + file.write(str(str1)) + file.close() + with open(corpdir + "/lit-seed{0}".format(n), "r") as q: + a = q.readline() + a = a[1:] + print( + "AFL++ Autodict-QL by Microsvuln : Writing Token :" + + str(a) + ) + q.close() + with open( + corpdir + "/lit-seed{0}".format(n), "w" + ) as w1: + w1.write(str(a)) + print("Done!") + w1.close() + except: + print("Error!") + n = n + 1 + def main(): - args = parse_args() + args = parse_args() ensure_dir(args.corpdir) do_analysis1(args.corpdir, args.infile) -if __name__ == '__main__': - main() \ No newline at end of file + + +if __name__ == "__main__": + main() diff --git a/utils/autodict_ql/memcmp-strings.py b/utils/autodict_ql/memcmp-strings.py index d1047caa..270a697c 100644 --- a/utils/autodict_ql/memcmp-strings.py +++ b/utils/autodict_ql/memcmp-strings.py @@ -5,7 +5,7 @@ import os import string -import binascii +import binascii import codecs import errno import struct @@ -13,6 +13,7 @@ import argparse import re from binascii import unhexlify + def ensure_dir(dir): try: os.makedirs(dir) @@ -20,44 +21,63 @@ def ensure_dir(dir): if e.errno != errno.EEXIST: raise + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - parser.add_argument("corpdir", - help="The path to the corpus directory to generate strings.") - parser.add_argument("infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + ) + ) + parser.add_argument( + "corpdir", help="The path to the corpus directory to generate strings." + ) + parser.add_argument( + "infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + ) return parser.parse_args() def do_string_analysis(corpdir, infile1): - with open(infile1, "r") as f1: - lines = f1.readlines()[1:] - f1.close() + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() new_lst1 = [] n = 1 for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - #print("num : %s" % num1) + # print("num : %s" % num1) str11 = str(num1) - str11 = str11.replace("|","") - str11 = str11.replace("\n","") + str11 = str11.replace("|", "") + str11 = str11.replace("\n", "") str11 = str11.lstrip() str11 = str11.rstrip() str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : + if ( + (" " in str11) + or (")" in str11) + or ("(" in str11) + or ("<" in str11) + or (">" in str11) + ): print("Space / Paranthesis String : %s" % str11) - else : - with open(corpdir+'/memcmp-str{0}'.format(n), 'w') as file: - file.write(str11) - print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) - n=n+1 + else: + with open(corpdir + "/memcmp-str{0}".format(n), "w") as file: + file.write(str11) + print( + "AFL++ Autodict-QL by Microsvuln : Writing Token : %s" + % str11 + ) + n = n + 1 + def main(): - args = parse_args() + args = parse_args() ensure_dir(args.corpdir) do_string_analysis(args.corpdir, args.infile) -if __name__ == '__main__': - main() \ No newline at end of file + + +if __name__ == "__main__": + main() diff --git a/utils/autodict_ql/stan-strings.py b/utils/autodict_ql/stan-strings.py index 65d08c97..81cb0b97 100644 --- a/utils/autodict_ql/stan-strings.py +++ b/utils/autodict_ql/stan-strings.py @@ -5,7 +5,7 @@ import os import string -import binascii +import binascii import codecs import errno import struct @@ -13,6 +13,7 @@ import argparse import re from binascii import unhexlify + def ensure_dir(dir): try: os.makedirs(dir) @@ -20,44 +21,63 @@ def ensure_dir(dir): if e.errno != errno.EEXIST: raise + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - parser.add_argument("corpdir", - help="The path to the corpus directory to generate strings.") - parser.add_argument("infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + ) + ) + parser.add_argument( + "corpdir", help="The path to the corpus directory to generate strings." + ) + parser.add_argument( + "infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + ) return parser.parse_args() def do_string_analysis(corpdir, infile1): - with open(infile1, "r") as f1: - lines = f1.readlines()[1:] - f1.close() + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() new_lst1 = [] n = 1 for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - #print("num : %s" % num1) + # print("num : %s" % num1) str11 = str(num1) - str11 = str11.replace("|","") - str11 = str11.replace("\n","") + str11 = str11.replace("|", "") + str11 = str11.replace("\n", "") str11 = str11.lstrip() str11 = str11.rstrip() str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : + if ( + (" " in str11) + or (")" in str11) + or ("(" in str11) + or ("<" in str11) + or (">" in str11) + ): print("Space / Paranthesis String : %s" % str11) - else : - with open(corpdir+'/seed-str{0}'.format(n), 'w') as file: - file.write(str11) - print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) - n=n+1 + else: + with open(corpdir + "/seed-str{0}".format(n), "w") as file: + file.write(str11) + print( + "AFL++ Autodict-QL by Microsvuln : Writing Token : %s" + % str11 + ) + n = n + 1 + def main(): - args = parse_args() + args = parse_args() ensure_dir(args.corpdir) do_string_analysis(args.corpdir, args.infile) -if __name__ == '__main__': - main() \ No newline at end of file + + +if __name__ == "__main__": + main() diff --git a/utils/autodict_ql/strcmp-strings.py b/utils/autodict_ql/strcmp-strings.py index 88128dbb..9c2520c9 100644 --- a/utils/autodict_ql/strcmp-strings.py +++ b/utils/autodict_ql/strcmp-strings.py @@ -5,7 +5,7 @@ import os import string -import binascii +import binascii import codecs import errno import struct @@ -13,6 +13,7 @@ import argparse import re from binascii import unhexlify + def ensure_dir(dir): try: os.makedirs(dir) @@ -20,44 +21,63 @@ def ensure_dir(dir): if e.errno != errno.EEXIST: raise + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - parser.add_argument("corpdir", - help="The path to the corpus directory to generate strings.") - parser.add_argument("infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + ) + ) + parser.add_argument( + "corpdir", help="The path to the corpus directory to generate strings." + ) + parser.add_argument( + "infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + ) return parser.parse_args() def do_string_analysis(corpdir, infile1): - with open(infile1, "r") as f1: - lines = f1.readlines()[1:] - f1.close() + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() new_lst1 = [] n = 1 for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - #print("num : %s" % num1) + # print("num : %s" % num1) str11 = str(num1) - str11 = str11.replace("|","") - str11 = str11.replace("\n","") + str11 = str11.replace("|", "") + str11 = str11.replace("\n", "") str11 = str11.lstrip() str11 = str11.rstrip() str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : + if ( + (" " in str11) + or (")" in str11) + or ("(" in str11) + or ("<" in str11) + or (">" in str11) + ): print("Space / Paranthesis String : %s" % str11) - else : - with open(corpdir+'/strcmp-str{0}'.format(n), 'w') as file: - file.write(str11) - print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) - n=n+1 + else: + with open(corpdir + "/strcmp-str{0}".format(n), "w") as file: + file.write(str11) + print( + "AFL++ Autodict-QL by Microsvuln : Writing Token : %s" + % str11 + ) + n = n + 1 + def main(): - args = parse_args() + args = parse_args() ensure_dir(args.corpdir) do_string_analysis(args.corpdir, args.infile) -if __name__ == '__main__': - main() \ No newline at end of file + + +if __name__ == "__main__": + main() diff --git a/utils/autodict_ql/strncmp-strings.py b/utils/autodict_ql/strncmp-strings.py index 0ad0e697..6206b4c4 100644 --- a/utils/autodict_ql/strncmp-strings.py +++ b/utils/autodict_ql/strncmp-strings.py @@ -5,7 +5,7 @@ import os import string -import binascii +import binascii import codecs import errno import struct @@ -13,6 +13,7 @@ import argparse import re from binascii import unhexlify + def ensure_dir(dir): try: os.makedirs(dir) @@ -20,44 +21,63 @@ def ensure_dir(dir): if e.errno != errno.EEXIST: raise + def parse_args(): - parser = argparse.ArgumentParser(description=( - "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" )) - parser.add_argument("corpdir", - help="The path to the corpus directory to generate strings.") - parser.add_argument("infile", - help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt") + parser = argparse.ArgumentParser( + description=( + "Helper - Specify input file analysis and output folder to save corpus for strings in the overall project --------------------------------------------------------------------------- Example usage : python2 thisfile.py outdir str.txt" + ) + ) + parser.add_argument( + "corpdir", help="The path to the corpus directory to generate strings." + ) + parser.add_argument( + "infile", + help="Specify file output of codeql analysis - ex. ooo-atr.txt, analysis take place on this file, example : python2 thisfile.py outdir strings.txt", + ) return parser.parse_args() def do_string_analysis(corpdir, infile1): - with open(infile1, "r") as f1: - lines = f1.readlines()[1:] - f1.close() + with open(infile1, "r") as f1: + lines = f1.readlines()[1:] + f1.close() new_lst1 = [] n = 1 for i, num1 in enumerate(lines): if i != 0: new_lst1.append(num1) - #print("num : %s" % num1) + # print("num : %s" % num1) str11 = str(num1) - str11 = str11.replace("|","") - str11 = str11.replace("\n","") + str11 = str11.replace("|", "") + str11 = str11.replace("\n", "") str11 = str11.lstrip() str11 = str11.rstrip() str11 = str(str11) - if ((" " in str11 ) or (")" in str11) or ("(" in str11) or ("<" in str11) or (">" in str11)) : + if ( + (" " in str11) + or (")" in str11) + or ("(" in str11) + or ("<" in str11) + or (">" in str11) + ): print("Space / Paranthesis String : %s" % str11) - else : - with open(corpdir+'/strncmp-str{0}'.format(n), 'w') as file: - file.write(str11) - print("AFL++ Autodict-QL by Microsvuln : Writing Token : %s" % str11) - n=n+1 + else: + with open(corpdir + "/strncmp-str{0}".format(n), "w") as file: + file.write(str11) + print( + "AFL++ Autodict-QL by Microsvuln : Writing Token : %s" + % str11 + ) + n = n + 1 + def main(): - args = parse_args() + args = parse_args() ensure_dir(args.corpdir) do_string_analysis(args.corpdir, args.infile) -if __name__ == '__main__': - main() \ No newline at end of file + + +if __name__ == "__main__": + main() -- cgit 1.4.1 From e41d1183cca02fb4d6398df4fc3e028dfd9c5f72 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 00:41:32 +0200 Subject: fix nits --- GNUmakefile | 2 +- docs/env_variables.md | 4 ++-- qemu_mode/build_qemu_support.sh | 2 ++ src/afl-fuzz-stats.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index a87b2f7b..804bfe08 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -550,7 +550,7 @@ all_done: test_build @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." - @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecific for MacOs.\n\n"; fi + @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null .NOTPARALLEL: clean all diff --git a/docs/env_variables.md b/docs/env_variables.md index 1f4dfef9..0100ffac 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -382,8 +382,8 @@ checks or alter some of the more exotic semantics of the tool: may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), Unicorn mode (-U) and Frida mode (-O), `AFL_PATH` will - be searched for afl-qemu-trace. + - In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will + be searched for afl-qemu-trace and afl-frida-trace.so. - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip prepending `afl-qemu-trace` to your command line. Use this if you wish to use a diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 38085389..6436d43a 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -360,6 +360,8 @@ if ! command -v "$CROSS" > /dev/null ; then make -C unsigaction && echo "[+] unsigaction ready" echo "[+] Building libqasan ..." make -C libqasan && echo "[+] unsigaction ready" + echo "[+] Building qemu libfuzzer helpers ..." + make -C ../utils/aflpp_driver else echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction" fi diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index a1559eac..52d9de87 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -866,7 +866,7 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->custom_only)) { - strcpy(tmp, "disabled (custom mutator only mode)"); + strcpy(tmp, "disabled (custom-mutator-only mode)"); } else if (likely(afl->skip_deterministic)) { -- cgit 1.4.1 From 950648c513d031b5c829565255a7c157a33ba7c3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 16 Apr 2021 07:06:37 +0100 Subject: Changes following code review --- frida_mode/src/instrument.c | 8 +++++++- frida_mode/src/ranges.c | 3 +-- frida_mode/test/testinstr.c | 7 +++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c index 042fdab8..22910062 100644 --- a/frida_mode/src/instrument.c +++ b/frida_mode/src/instrument.c @@ -174,7 +174,13 @@ void instrument_coverage_optimize(const cs_insn * instr, static void on_basic_block(GumCpuContext *context, gpointer user_data) { - /* Avoid stack operations in potentially performance critical code */ + /* + * This function is performance critical as it is called to instrument every + * basic block. By moving our print buffer to a global, we avoid it affecting + * the critical path with additional stack adjustments if tracing is not + * enabled. If tracing is enabled, then we're printing a load of diagnostic + * information so this overhead is unlikely to be noticeable. + */ static char buffer[200]; int len; guint64 current_pc = (guint64)user_data; diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index fc14710f..49ef5a62 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -29,8 +29,7 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) { gchar **tokens; int token_count; tokens = g_strsplit(token, "-", 2); - for (token_count = 0; tokens[token_count] != NULL; token_count++) - ; + for (token_count = 0; tokens[token_count] != NULL; token_count++) {} if (token_count != 2) { diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/testinstr.c index 2c3d5144..37d47f91 100644 --- a/frida_mode/test/testinstr.c +++ b/frida_mode/test/testinstr.c @@ -78,6 +78,13 @@ int main(int argc, char **argv) { } buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + n_read = read(fd, buf, len); if (n_read != len) { -- cgit 1.4.1 From 624c1dce465ffd8d3971282cf136c3df259f62ec Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 11:38:37 +0200 Subject: fix nits --- qemu_mode/libcompcov/compcovtest.cc | 157 +++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index 69c6aa09..b446ebfa 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -1,74 +1,83 @@ -///////////////////////////////////////////////////////////////////////// -// -// Author: Mateusz Jurczyk (mjurczyk@google.com) -// -// Copyright 2019-2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// solution: echo -ne 'The quick brown fox jumps over the lazy -// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest - -#include "../../include/config.h" - -#include -#include -#include -#include - -int main(int argc, char**argv) { - - char buffer[44] = {/* zero padding */}; - - FILE* file = stdin; - if (argc > 1) - file = fopen(argv[1], "r"); - - fread(buffer, 1, sizeof(buffer) - 1, file); - - if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || - strncmp(&buffer[20], "jumps over ", 11) != 0 || - strcmp(&buffer[31], "the lazy dog") != 0) { - - return 1; - - } - - uint64_t x = 0; - fread(&x, sizeof(x), 1, file); - if (x != 0xCAFEBABECAFEBABE) { return 2; } - - uint32_t y = 0; - fread(&y, sizeof(y), 1, file); - if (y != 0xDEADC0DE) { return 3; } - - uint16_t z = 0; - fread(&z, sizeof(z), 1, file); - - switch (z) { - - case 0xBEEF: - break; - - default: - return 4; - - } - - printf("Puzzle solved, congrats!\n"); - abort(); - return 0; - -} - +///////////////////////////////////////////////////////////////////////// +// +// Author: Mateusz Jurczyk (mjurczyk@google.com) +// +// Copyright 2019-2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// solution: echo -ne 'The quick brown fox jumps over the lazy +// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest + +#include "../../include/config.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) { + + char buffer[44] = {/* zero padding */}; + + FILE *file = stdin; + + if (argc > 1) { + + if ((file = fopen(argv[1], "r")) == NULL) { + + perror(argv[1]); + exit(-1); + + } + + } + + fread(buffer, 1, sizeof(buffer) - 1, file); + + if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || + strncmp(&buffer[20], "jumps over ", 11) != 0 || + strcmp(&buffer[31], "the lazy dog") != 0) { + + return 1; + + } + + uint64_t x = 0; + fread(&x, sizeof(x), 1, file); + if (x != 0xCAFEBABECAFEBABE) { return 2; } + + uint32_t y = 0; + fread(&y, sizeof(y), 1, file); + if (y != 0xDEADC0DE) { return 3; } + + uint16_t z = 0; + fread(&z, sizeof(z), 1, file); + + switch (z) { + + case 0xBEEF: + break; + + default: + return 4; + + } + + printf("Puzzle solved, congrats!\n"); + abort(); + return 0; + +} + -- cgit 1.4.1 From 89d4565092367753c70849bb85b220db48ed2710 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 11:45:22 +0200 Subject: update docs --- README.md | 10 +++++----- TODO.md | 1 - docs/Changelog.md | 6 ++++-- docs/ideas.md | 43 +++++++------------------------------------ 4 files changed, 16 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index e7582aff..583db85f 100644 --- a/README.md +++ b/README.md @@ -99,15 +99,15 @@ behaviours and defaults: | Ngram prev_loc Coverage | | x(6) | | | | | | Context Coverage | | x(6) | | | | | | Auto Dictionary | | x(7) | | | | | - | Snapshot LKM Support | | x(8) | x(8) | | (x)(5) | | + | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | - 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8 + 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin 3. (currently unassigned) - 4. with pcguard mode and LTO mode for LLVM >= 11 + 4. with pcguard mode and LTO mode for LLVM 11 and newer 5. upcoming, development in the branch - 6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1 - 7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x` + 6. not compatible with LTO instrumentation and needs at least LLVM v4.1 + 7. automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x` 8. the snapshot LKM is currently unmaintained due to too many kernel changes coming too fast :-( Among others, the following features and patches have been integrated: diff --git a/TODO.md b/TODO.md index 96b24521..c828d214 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,6 @@ - intel-pt tracer - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - - cmplog: too much tainted bytes, directly add to dict and skip? - parallel builds for source-only targets ## Further down the road diff --git a/docs/Changelog.md b/docs/Changelog.md index 155eec66..9c9a3976 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,8 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - cmplog level 3 (-l 3) now performs redqueen on everything. + use with care. - better fuzzing strategy yields for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing @@ -28,11 +30,11 @@ sending a mail to . -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - afl-cc: - - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! + - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - - add -d (dead fuzzer stats) to afl-whatsup + - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/ideas.md b/docs/ideas.md index 11c78e49..e25d3ba6 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -3,42 +3,6 @@ In the following, we describe a variety of ideas that could be implemented for future AFL++ versions. -# GSoC 2021 - -All GSoC 2021 projects will be in the Rust development language! - -## UI for libaflrs - -Write a user interface to libaflrs, the upcoming backend of afl++. -This might look like the afl-fuzz UI, but you can improve on it - and should! - -## Schedulers for libaflrs - -Schedulers is a mechanism that selects items from the fuzzing corpus based -on strategy and randomness. One scheduler might focus on long paths, -another on rarity of edges discovered, still another on a combination on -things. Some of the schedulers in afl++ have to be ported, but you are free -to come up with your own if you want to - and see how it performs. - -## Forkserver support for libaflrs - -The current libaflrs implementation fuzzes in-memory, however obviously we -want to support afl instrumented binaries as well. -Hence a forkserver support needs to be implemented - forking off the target -and talking to the target via a socketpair and the communication protocol -within. - -## More Observers for libaflrs - -An observer is measuring functionality that looks at the target being fuzzed -and documents something about it. In traditional fuzzing this is the coverage -in the target, however we want to add various more observers, e.g. stack depth, -heap usage, etc. - this is a topic for an experienced Rust developer. - -# Generic ideas and wishlist - NOT PART OF GSoC 2021 ! - -The below list is not part of GSoC 2021. - ## Analysis software Currently analysis is done by using afl-plot, which is rather outdated. @@ -65,6 +29,13 @@ the current Unicorn instrumentation. Mentor: any +## Support other programming languages + +Other programming languages also use llvm hence they could (easily?) supported +for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ... + +Mentor: vanhauser-thc + ## Machine Learning Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-) -- cgit 1.4.1 From 846a46e06052c13e3036fbee05866d165adb19cc Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 16 Apr 2021 12:12:52 +0200 Subject: review --- utils/autodict_ql/readme.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 8c24d65c..31a20352 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -2,13 +2,13 @@ ## What is this? -`Autodict-QL` is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (Unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses the CodeQL (A powerful semantic code analysis engine) to fetch information from a code base. +`Autodict-QL` is a plugin system that enables fast generation of Tokens/Dictionaries in a handy way that can be manipulated by the user (unlike The LLVM Passes that are hard to modify). This means that autodict-ql is a scriptable feature which basically uses CodeQL (a powerful semantic code analysis engine) to fetch information from a code base. -Tokens are useful when you perform fuzzing on different parsers. AFL++ `-x` switch enables the usage of dictionaries through your fuzzing campagin. if you are not familiar with Dictionaries in fuzzing, take a look [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries) . +Tokens are useful when you perform fuzzing on different parsers. The AFL++ `-x` switch enables the usage of dictionaries through your fuzzing campaign. If you are not familiar with Dictionaries in fuzzing, take a look [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/dictionaries) . ## Why CodeQL ? -We basically developed this plugin on top of CodeQL engine because it gives the user scripting features, it's easier and it's independent of the LLVM system. This means that a user can write his CodeQL scripts or modify the current scripts to improve or change the token generation algorithms based on different program analysis concepts. +We basically developed this plugin on top of the CodeQL engine because it gives the user scripting features, it's easier and it's independent of the LLVM system. This means that a user can write his CodeQL scripts or modify the current scripts to improve or change the token generation algorithms based on different program analysis concepts. ## CodeQL scripts @@ -16,7 +16,7 @@ Currently, we pushed some scripts as defaults for Token generation. In addition, Currently we provided the following CodeQL scripts : -`strcmp-str.ql` is used to extract strings that are related to `strcmp` function. +`strcmp-str.ql` is used to extract strings that are related to the `strcmp` function. `strncmp-str.ql` is used to extract the strings from the `strncmp` function. @@ -24,18 +24,18 @@ Currently we provided the following CodeQL scripts : `litool.ql` extracts Magic numbers as Hexadecimal format. -`strtool.ql` extracts strings with uses of a regex and dataflow concept to capture the string comparison functions. if strcmp is rewritten in a project as Mystrcmp or something like strmycmp, then this script can catch the arguments and these are valuable tokens. +`strtool.ql` extracts strings with uses of a regex and dataflow concept to capture the string comparison functions. If `strcmp` is rewritten in a project as Mystrcmp or something like strmycmp, then this script can catch the arguments and these are valuable tokens. You can write other CodeQL scripts to extract possible effective tokens if you think they can be useful. ## Usage -Before proceed to installation make sure that you have the following packages by installing them : +Before you proceed to installation make sure that you have the following packages by installing them : ```shell sudo apt install build-essential libtool-bin python3-dev python3 automake git vim wget -y ``` -The usage of Autodict-QL is pretty easy. But let's describe it as : +The usage of Autodict-QL is pretty easy. But let's describe it as: 1. First of all, you need to have CodeQL installed on the system. we make this possible with `build-codeql.sh` bash script. This script will install CodeQL completety and will set the required environment variables for your system. Do the following : @@ -45,7 +45,7 @@ Do the following : # source ~/.bashrc # codeql ``` -Then you should get : +Then you should get: ```shell Usage: codeql ... @@ -73,29 +73,29 @@ Commands: github Commands useful for interacting with the GitHub API through CodeQL. ``` -2. Compile your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard . - - First you need to create a CodeQL database of the project codebase, suppose we want to compile the libxml with codeql. go to libxml and issue the following commands: +2. Compile your project with CodeQL: For using the Autodict-QL plugin, you need to compile the source of the target you want to fuzz with CodeQL. This is not something hard. + - First you need to create a CodeQL database of the project codebase, suppose we want to compile `libxml` with codeql. Go to libxml and issue the following commands: - `./configure --disable-shared` - `codeql create database libxml-db --language=cpp --command=make` - Now you have the CodeQL database of the project :-) -3. The final step is to update the CodeQL database you created in the step 2 (Suppose we are in `aflplusplus/utils/autodict_ql/` directory) : +3. The final step is to update the CodeQL database you created in step 2 (Suppose we are in `aflplusplus/utils/autodict_ql/` directory): - `codeql database upgrade /home/user/libxml/libxml-db` -4. Everything is set! Now you should issue the following to get the tokens : +4. Everything is set! Now you should issue the following to get the tokens: - `python3 autodict-ql.py [CURRECT_DIR] [CODEQL_DATABASE_PATH] [TOKEN_PATH]` - example : `python3 /home/user/AFLplusplus/utils/autodict_ql/autodict-ql.py $PWD /home/user/libxml/libxml-db tokens` - - This will create the final `tokens` dir for you and you are done, then pass the tokens path to afl `-x` flag. + - This will create the final `tokens` dir for you and you are done, then pass the tokens path to AFL++'s `-x` flag. 5. Done! ## More on dictionaries and tokens -Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. -On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. +Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extract useful tokens, in addition with LTO instrumentation mode, this dict2file is automatically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. In addition it's independent from LLVM system. +On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. For example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionaries, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generate dictionaries based on the target. -I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` and `dict2file` are working based on the target. +I've personally prefered to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manually generated dictionaries as `Autodict-QL` and `dict2file` are working based on the target. In overall, fuzzing with dictionaries and well-generated tokens will give better results. There are 2 important points to remember : -- If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chance to discover new bugs. -- Do not remember to set the `AFL_MAX_DET_EXTRAS` to the number of generated dictionaries, if you forget to set this environment variable, then AFL++ use just 200 tokens and use the rest of them probablistically. So this will guarantees that your tokens will be used by AFL++. +- If you combine `Autodict-QL` with AFL++ cmplog, you will get much better code coverage and hence better chances to discover new bugs. +- Do not forget to set `AFL_MAX_DET_EXTRAS` at least to the number of generated dictionaries. If you forget to set this environment variable, then AFL++ uses just 200 tokens and use the rest of them only probabilistically. So this will guarantee that your tokens will be used by AFL++. -- cgit 1.4.1 From 523aaaebefb34737cbc0964a284b0ca67f477ad3 Mon Sep 17 00:00:00 2001 From: Microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Fri, 16 Apr 2021 15:39:45 +0430 Subject: Add newline Add newline --- utils/autodict_ql/build-codeql.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/build-codeql.sh b/utils/autodict_ql/build-codeql.sh index 450207f6..6ae4b362 100644 --- a/utils/autodict_ql/build-codeql.sh +++ b/utils/autodict_ql/build-codeql.sh @@ -14,4 +14,4 @@ export "PATH=~/codeql-home/codeql-cli/:$PATH" echo "export PATH=~/codeql-home/codeql-cli/:$PATH" >> ~/.bashrc codeql resolve languages codeql resolve qlpacks -codeql \ No newline at end of file +codeql -- cgit 1.4.1 From 2019b42ceda386ce63e36312ea0606b216019bac Mon Sep 17 00:00:00 2001 From: Microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Fri, 16 Apr 2021 15:41:12 +0430 Subject: Update readme fix typo in readme --- utils/autodict_ql/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/readme.md b/utils/autodict_ql/readme.md index 8c24d65c..3402a210 100644 --- a/utils/autodict_ql/readme.md +++ b/utils/autodict_ql/readme.md @@ -88,7 +88,7 @@ Commands: ## More on dictionaries and tokens -Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automtically generates token extraction. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. +Core developer of the AFL++ project Marc Heuse also developed a similar tool named `dict2file` which is a LLVM pass which can automatically extracts useful tokens, in addition with LTO instrumentation mode, this dict2file is automatically generating tokens. `Autodict-QL` plugin gives you scripting capability and you can do whatever you want to extract from the Codebase and it's up to you. in addition it's independent from LLVM system. On the other hand, you can also use Google dictionaries which have been made public in May 2020, but the problem of using Google dictionaries is that they are limited to specific file format and speicifications. for example, for testing binutils and ELF file format or AVI in FFMPEG, there are no prebuilt dictionary, so it is highly recommended to use `Autodict-QL` or `Dict2File` features to automatically generating dictionaries based on the target. I've personally prefer to use `Autodict-QL` or `dict2file` rather than Google dictionaries or any other manully generated dictionaries as `Autodict-QL` and `dict2file` are working based on the target. -- cgit 1.4.1 From 98989f1088d04dd4c0d21834c38b7683f1cfb42d Mon Sep 17 00:00:00 2001 From: Microsvuln <55649192+Microsvuln@users.noreply.github.com> Date: Fri, 16 Apr 2021 15:45:22 +0430 Subject: Add new line Add new line --- utils/autodict_ql/litool.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/autodict_ql/litool.ql b/utils/autodict_ql/litool.ql index b7f4bf33..76f429c1 100644 --- a/utils/autodict_ql/litool.ql +++ b/utils/autodict_ql/litool.ql @@ -7,4 +7,4 @@ class HexOrOctLiteral extends Literal{ } from HexOrOctLiteral lit -select lit.getValueText() \ No newline at end of file +select lit.getValueText() -- cgit 1.4.1 From b03424073e45097c89028977b6a0b3589914568a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 13:49:26 +0200 Subject: fixes --- GNUmakefile | 10 +++++----- src/afl-fuzz.c | 14 +++++++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 804bfe08..5569825f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -247,17 +247,17 @@ ifneq "$(filter Linux GNU%,$(SYS))" "" LDFLAGS += -ldl -lrt -lm endif -ifneq "$(findstring FreeBSD, $(ARCH))" "" +ifneq "$(findstring FreeBSD, $(SYS))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring NetBSD, $(ARCH))" "" +ifneq "$(findstring NetBSD, $(SYS))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring OpenBSD, $(ARCH))" "" +ifneq "$(findstring OpenBSD, $(SYS))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif @@ -489,7 +489,7 @@ unit_clean: @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o .PHONY: unit -ifneq "$(ARCH)" "Darwin" +ifneq "$(SYS)" "Darwin" unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else unit: @@ -550,7 +550,7 @@ all_done: test_build @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." - @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi + @if [ "$(SYS)" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null .NOTPARALLEL: clean all diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 2b035a23..3606533d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -176,6 +176,14 @@ static void usage(u8 *argv0, int more_help) { #define DYN_COLOR #endif +#ifdef AFL_PERSISTENT_RECORD + #define PERSISTENT_MSG \ + "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \ + "out/crashes\n" +#else + #define PERSISTENT_MSG +#endif + SAYF( "Environment variables used:\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" @@ -223,9 +231,9 @@ static void usage(u8 *argv0, int more_help) { "AFL_PATH: path to AFL support binaries\n" "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_QUIET: suppress forkserver status messages\n" -#ifdef AFL_PERSISTENT_RECORD - "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in out/crashes\n" -#endif + + PERSISTENT_MSG + "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 3c68208dd3f19567239cba8f5ae781f79f64e99c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 14:53:11 +0200 Subject: fix compcovtest --- qemu_mode/libcompcov/compcovtest.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index b446ebfa..92e3864c 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -77,6 +77,9 @@ int main(int argc, char **argv) { printf("Puzzle solved, congrats!\n"); abort(); + + if (argc > 1) { fclose(file); } + return 0; } -- cgit 1.4.1 From c30999562e0a0e03d1412b16fb33b5874ed96914 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 15:02:36 +0200 Subject: fix compcovtest --- qemu_mode/libcompcov/compcovtest.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/qemu_mode/libcompcov/compcovtest.cc b/qemu_mode/libcompcov/compcovtest.cc index 92e3864c..3c975e15 100644 --- a/qemu_mode/libcompcov/compcovtest.cc +++ b/qemu_mode/libcompcov/compcovtest.cc @@ -50,17 +50,28 @@ int main(int argc, char **argv) { strncmp(&buffer[20], "jumps over ", 11) != 0 || strcmp(&buffer[31], "the lazy dog") != 0) { + if (argc > 1) { fclose(file); } return 1; } uint64_t x = 0; fread(&x, sizeof(x), 1, file); - if (x != 0xCAFEBABECAFEBABE) { return 2; } + if (x != 0xCAFEBABECAFEBABE) { + + if (argc > 1) { fclose(file); } + return 2; + + } uint32_t y = 0; fread(&y, sizeof(y), 1, file); - if (y != 0xDEADC0DE) { return 3; } + if (y != 0xDEADC0DE) { + + if (argc > 1) { fclose(file); } + return 3; + + } uint16_t z = 0; fread(&z, sizeof(z), 1, file); @@ -71,6 +82,7 @@ int main(int argc, char **argv) { break; default: + if (argc > 1) { fclose(file); } return 4; } -- cgit 1.4.1 From 6e75832082c331b6191db2df970f5088b8773214 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 20:55:19 +0200 Subject: code format for frida mode --- GNUmakefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GNUmakefile b/GNUmakefile index 5569825f..9d98aa00 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -513,6 +513,9 @@ code-format: ./.custom-format.py -i qemu_mode/libcompcov/*.h ./.custom-format.py -i qemu_mode/libqasan/*.c ./.custom-format.py -i qemu_mode/libqasan/*.h + ./.custom-format.py -i frida_mode/src/*.c + ./.custom-format.py -i frida_mode/include/*.h + -./.custom-format.py -i frida_mode/src/*/*.c ./.custom-format.py -i *.h ./.custom-format.py -i *.c -- cgit 1.4.1 From 495cbd42b7e4e9d873178a09b7183be893fffb1d Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 16 Apr 2021 21:57:44 +0200 Subject: reworked formatting in order to avoid gcc 8.3.0 warnings --- src/afl-fuzz-stats.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 52d9de87..22c0cbd2 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -427,7 +427,7 @@ void show_stats(afl_state_t *afl) { u32 t_bytes, t_bits; u32 banner_len, banner_pad; - u8 tmp[256], tmp2[256]; + u8 tmp[256]; u8 time_tmp[64]; u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX]; @@ -1003,27 +1003,32 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_custom_mutator_library)) { - sprintf(tmp2, "%s %s/%s,", tmp, - u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]), - u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); + strcat(tmp, " "); + strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON])); + strcat(tmp, "/"); + strcat(tmp, u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); + strcat(tmp, ","); } else { - sprintf(tmp2, "%s unused,", tmp); + strcat(tmp, " unused,"); } if (unlikely(afl->shm.cmplog_mode)) { - sprintf(tmp, "%s %s/%s, %s/%s", tmp2, - u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]), - u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]), - u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]), - u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS])); + strcat(tmp, " "); + strcat(tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION])); + strcat(tmp, "/"); + strcat(tmp, u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION])); + strcat(tmp, ", "); + strcat(tmp, u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS])); + strcat(tmp, "/"); + strcat(tmp, u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS])); } else { - sprintf(tmp, "%s unused, unused", tmp2); + strcat(tmp, " unused, unused"); } -- cgit 1.4.1 From b6643a8ad155d8e9002e456260f83d2d369ac4bf Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 16 Apr 2021 22:20:01 +0200 Subject: add idea of thread-safe target feedback --- TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 7e420d23..5a5e7c4e 100644 --- a/TODO.md +++ b/TODO.md @@ -36,4 +36,5 @@ qemu_mode: up edge numbers that both following cmp paths have been found and then disable working on this edge id -> cmplog_intelligence branch - use cmplog colorization taint result for havoc locations? - + - new instrumentation option for a thread-safe variant of feedback to shared mem. + The user decides, if this is needed (eg the target is multithreaded). -- cgit 1.4.1 From 2bd7206ec561207ad37687a7aed5c0eb323c9fd8 Mon Sep 17 00:00:00 2001 From: veritas501 Date: Mon, 19 Apr 2021 10:49:28 +0800 Subject: fix-typo: "WIn32" -> "Win32" --- qemu_mode/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu_mode/README.md b/qemu_mode/README.md index a14cbe64..4aa2133e 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -141,7 +141,7 @@ To enable it you must pass on the command line of afl-fuzz: ## 9) Wine mode -AFL++ QEMU can use Wine to fuzz WIn32 PE binaries. Use the -W flag of afl-fuzz. +AFL++ QEMU can use Wine to fuzz Win32 PE binaries. Use the -W flag of afl-fuzz. Note that some binaries require user interaction with the GUI and must be patched. -- cgit 1.4.1 From 86a8ef168dda766d2f25f15c15c4d3ecf21d0667 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 22:58:54 +0200 Subject: fix custom trim for increasing data --- src/afl-fuzz-mutators.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index a47b4f5f..c99d9a4d 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -397,8 +397,14 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen && cksum == q->exec_cksum)) { - q->len = retlen; + if (afl_realloc((void **)&in_buf, retlen) == NULL) { + + FATAL("can not allocate memory for trim"); + + } + memcpy(in_buf, retbuf, retlen); + q->len = retlen; /* Let's save a clean trace, which will be needed by update_bitmap_score once we're done with the trimming stuff. */ -- cgit 1.4.1 From 3b5fa3632b0e482b2915709d7fbec827e1d997b9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 19 Apr 2021 11:05:42 +0200 Subject: drop support for llvm < 6.0 --- GNUmakefile.llvm | 8 ++++---- README.md | 4 ++-- docs/Changelog.md | 1 + instrumentation/README.llvm.md | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 61c17e92..2d50badc 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -36,7 +36,7 @@ ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" - $(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") + $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") endif else LLVM_CONFIG ?= llvm-config @@ -45,7 +45,7 @@ endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^[0-2]\.' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 ) LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 ) @@ -61,7 +61,7 @@ ifeq "$(LLVMVER)" "" endif ifeq "$(LLVM_UNSUPPORTED)" "1" - $(error llvm_mode only supports llvm from version 3.4 onwards) + $(error llvm_mode only supports llvm from version 6.0 onwards) endif ifeq "$(LLVM_TOO_NEW)" "1" @@ -346,7 +346,7 @@ no_build: test_deps: @echo "[*] Checking for working 'llvm-config'..." ifneq "$(LLVM_APPLE_XCODE)" "1" - @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 ) + @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 ) endif @echo "[*] Checking for working '$(CC)'..." @type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 ) diff --git a/README.md b/README.md index 583db85f..4a0f3574 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. @@ -293,7 +293,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ diff --git a/docs/Changelog.md b/docs/Changelog.md index 9c9a3976..520b13b1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -30,6 +30,7 @@ sending a mail to . -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - afl-cc: + - We do not support llvm versions prior 6.0 anymore - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index adce6c1d..0937a328 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -6,7 +6,7 @@ ## 1) Introduction -! llvm_mode works with llvm versions 3.4 up to 12 ! +! llvm_mode works with llvm versions 6.0 up to 12 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude -- cgit 1.4.1