From a6adb6be2c41df57dd2912c06940231506a6f030 Mon Sep 17 00:00:00 2001 From: b1gr3db <73140724+b1gr3db@users.noreply.github.com> Date: Fri, 13 Aug 2021 13:53:22 -0400 Subject: Fixed spelling of quarantine --- qemu_mode/libqasan/malloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu_mode/libqasan/malloc.c b/qemu_mode/libqasan/malloc.c index 6fe6fc8c..5893a4e5 100644 --- a/qemu_mode/libqasan/malloc.c +++ b/qemu_mode/libqasan/malloc.c @@ -106,7 +106,7 @@ static pthread_spinlock_t quarantine_lock; #endif // need qasan disabled -static int quanratine_push(struct chunk_begin *ck) { +static int quarantine_push(struct chunk_begin *ck) { if (ck->requested_size >= QUARANTINE_MAX_BYTES) return 0; @@ -236,7 +236,7 @@ void __libqasan_free(void *ptr) { QASAN_STORE(ptr, n); int state = QASAN_SWAP(QASAN_DISABLED); // disable qasan for this thread - if (!quanratine_push(p)) { + if (!quarantine_push(p)) { if (p->aligned_orig) backend_free(p->aligned_orig); -- cgit 1.4.1 From 6191af744002ec06661dc996a61eeb11e4a58a79 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 17 Aug 2021 10:29:22 +0200 Subject: uninstall makefile target --- .gitignore | 7 +++++++ GNUmakefile | 14 ++++++++++++++ docs/Changelog.md | 1 + 3 files changed, 22 insertions(+) diff --git a/.gitignore b/.gitignore index 5627d8ab..5268bb37 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ afl-showmap.8 afl-system-config.8 afl-tmin.8 afl-whatsup.8 +afl-persistent-config.8 afl-c++ afl-cc afl-lto @@ -87,3 +88,9 @@ utils/afl_network_proxy/afl-network-client utils/afl_network_proxy/afl-network-server utils/plot_ui/afl-plot-ui *.o.tmp +utils/afl_proxy/afl-proxy +utils/optimin/build +utils/optimin/optimin +utils/persistent_mode/persistent_demo +utils/persistent_mode/persistent_demo_new +utils/persistent_mode/test-instr diff --git a/GNUmakefile b/GNUmakefile index 66fc0f07..2161e68d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -353,6 +353,7 @@ help: @echo "install: installs everything you have compiled with the build option above" @echo "clean: cleans everything compiled (not downloads when on a checkout)" @echo "deepclean: cleans everything including downloads" + @echo "uninstall: uninstall afl++ from the system" @echo "code-format: format the code, do this before you commit and send a PR please!" @echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem" @echo "unit: perform unit tests (based on cmocka and GNU linker)" @@ -691,3 +692,16 @@ endif install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH) cp -r testcases/ $${DESTDIR}$(MISC_PATH) cp -r dictionaries/ $${DESTDIR}$(MISC_PATH) + +.PHONY: uninstall +uninstall: + -cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto* + -cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt + -rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries + -sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f" + -cd $${DESTDIR}$(MAN_PATH) && rm -f $(MANPAGES) + -rmdir $${DESTDIR}$(BIN_PATH) 2>/dev/null + -rmdir $${DESTDIR}$(HELPER_PATH) 2>/dev/null + -rmdir $${DESTDIR}$(MISC_PATH) 2>/dev/null + -rmdir $${DESTDIR}$(DOC_PATH) 2>/dev/null + -rmdir $${DESTDIR}$(MAN_PATH) 2>/dev/null diff --git a/docs/Changelog.md b/docs/Changelog.md index daa014e4..3a2658f0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -23,6 +23,7 @@ sending a mail to . - added xml, curl and exotic string functions to llvm dictionary features - fix AFL_PRELOAD issues on MacOS - removed utils/afl_frida because frida_mode/ is now so much better + - added uninstall target to makefile (todo: update new readme!) ### Version ++3.14c (release) -- cgit 1.4.1 From 2a68d37b4f545698d745086077db5ca9d25dc5dd Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 17 Aug 2021 14:37:59 +0200 Subject: fix typo --- src/afl-fuzz-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index a9deb22d..1d32d966 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1339,7 +1339,7 @@ void show_init_stats(afl_state_t *afl) { } - ACTF("No -t option specified, so I'll use exec timeout of %u ms.", + ACTF("No -t option specified, so I'll use exec an timeout of %u ms.", afl->fsrv.exec_tmout); afl->timeout_given = 1; -- cgit 1.4.1 From 5f20137e9dfdc1f77e6b579b8a614907b18fbf97 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 17 Aug 2021 18:30:30 +0100 Subject: Add support for generating coverage information --- frida_mode/README.md | 3 +- frida_mode/frida.map | 1 + frida_mode/include/instrument.h | 6 + frida_mode/src/instrument/instrument.c | 4 + frida_mode/src/instrument/instrument_coverage.c | 375 ++++++++++++++++++++++++ frida_mode/src/js/api.js | 9 + frida_mode/src/js/js_api.c | 7 + frida_mode/ts/lib/afl.ts | 14 + include/envs.h | 1 + 9 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 frida_mode/src/instrument/instrument_coverage.c diff --git a/frida_mode/README.md b/frida_mode/README.md index 83612210..af79de07 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -131,7 +131,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent (only on CMP, SUB and CALL instructions) performance is not quite so critical. ## Advanced configuration options - +* `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRio format coverage +information (e.g. to be loaded within IDA lighthouse). * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks and their instrumented counterparts during block compilation. ``` diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 7223d50e..cf304885 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -10,6 +10,7 @@ js_api_error; js_api_set_debug_maps; js_api_set_entrypoint; + js_api_set_instrument_coverage_file; js_api_set_instrument_debug_file; js_api_set_instrument_jit; js_api_set_instrument_libraries; diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 29f14da9..2e8d6b6d 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -6,6 +6,7 @@ #include "config.h" extern char * instrument_debug_filename; +extern char * instrument_coverage_filename; extern gboolean instrument_tracing; extern gboolean instrument_optimize; extern gboolean instrument_unique; @@ -38,6 +39,11 @@ void instrument_debug_end(GumStalkerOutput *output); void instrument_flush(GumStalkerOutput *output); gpointer instrument_cur(GumStalkerOutput *output); +void instrument_coverage_config(void); +void instrument_coverage_init(void); +void instrument_coverage_start(uint64_t address); +void instrument_coverage_end(uint64_t address); + void instrument_on_fork(); guint64 instrument_get_offset_hash(GumAddress current_rip); diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index fddff19a..c0f1b2c9 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -171,6 +171,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, if (unlikely(begin)) { instrument_debug_start(instr->address, output); + instrument_coverage_start(instr->address); if (likely(entry_reached)) { @@ -216,6 +217,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, instrument_flush(output); instrument_debug_end(output); + instrument_coverage_end(instr->address); } @@ -228,6 +230,7 @@ void instrument_config(void) { instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED"); instrument_debug_config(); + instrument_coverage_config(); asan_config(); cmplog_config(); @@ -317,6 +320,7 @@ void instrument_init(void) { instrument_hash_zero = instrument_get_offset_hash(0); instrument_debug_init(); + instrument_coverage_init(); asan_init(); cmplog_init(); diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c new file mode 100644 index 00000000..68284e71 --- /dev/null +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -0,0 +1,375 @@ +#include +#include +#include + +#include "frida-gumjs.h" + +#include "debug.h" + +#include "instrument.h" +#include "util.h" + +char *instrument_coverage_filename = NULL; + +static int coverage_fd = -1; +static int coverage_pipes[2] = {0}; +static uint64_t coverage_last_start = 0; +static GHashTable *coverage_hash = NULL; +static GArray * coverage_modules = NULL; +static guint coverage_marked_modules = 0; +static guint coverage_marked_entries = 0; + +typedef struct { + + GumAddress base_address; + GumAddress limit; + gsize size; + char name[PATH_MAX + 1]; + char path[PATH_MAX + 1]; + bool referenced; + guint16 id; + +} coverage_module_t; + +typedef struct { + + uint64_t start; + uint64_t end; + coverage_module_t *module; + +} coverage_data_t; + +typedef struct { + + guint32 offset; + guint16 length; + guint16 module; + +} coverage_event_t; + +static gboolean coverage_module(const GumModuleDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + coverage_module_t coverage = {0}; + + coverage.base_address = details->range->base_address; + coverage.size = details->range->size; + coverage.limit = coverage.base_address + coverage.size; + + if (details->name != NULL) strncpy(coverage.name, details->name, PATH_MAX); + + if (details->path != NULL) strncpy(coverage.path, details->path, PATH_MAX); + + coverage.referenced = false; + coverage.id = 0; + + g_array_append_val(coverage_modules, coverage); + return TRUE; + +} + +static gint coverage_sort(gconstpointer a, gconstpointer b) { + + coverage_module_t *ma = (coverage_module_t *)a; + coverage_module_t *mb = (coverage_module_t *)b; + + if (ma->base_address < mb->base_address) return -1; + + if (ma->base_address > mb->base_address) return 1; + + return 0; + +} + +static void coverage_get_ranges(void) { + + OKF("Coverage - Collecting ranges"); + + coverage_modules = + g_array_sized_new(false, false, sizeof(coverage_module_t), 100); + gum_process_enumerate_modules(coverage_module, NULL); + g_array_sort(coverage_modules, coverage_sort); + + for (guint i = 0; i < coverage_modules->len; i++) { + + coverage_module_t *module = + &g_array_index(coverage_modules, coverage_module_t, i); + OKF("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X", + i, module->base_address, module->limit); + + } + +} + +static void instrument_coverage_mark(void *key, void *value, void *user_data) { + + UNUSED_PARAMETER(key); + UNUSED_PARAMETER(user_data); + coverage_data_t *val = (coverage_data_t *)value; + guint i; + + for (i = 0; i < coverage_modules->len; i++) { + + coverage_module_t *module = + &g_array_index(coverage_modules, coverage_module_t, i); + if (val->start > module->limit) continue; + + if (val->end >= module->limit) break; + + val->module = module; + coverage_marked_entries++; + module->referenced = true; + return; + + } + + OKF("Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X %u %u", + val->start, val->end, i, coverage_modules->len); + +} + +static void coverage_write(void *data, size_t size) { + + ssize_t written; + size_t remain = size; + + for (char *cursor = (char *)data; remain > 0; + remain -= written, cursor += written) { + + written = write(coverage_fd, cursor, remain); + + if (written < 0) { + + FATAL("Coverage - Failed to write: %s (%d)\n", (char *)data, errno); + + } + + } + +} + +static void coverage_format(char *format, ...) { + + va_list ap; + char buffer[4096] = {0}; + int ret; + int len; + + va_start(ap, format); + ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); + va_end(ap); + + if (ret < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + + coverage_write(buffer, len); + +} + +static void coverage_write_modules() { + + guint emitted = 0; + for (guint i = 0; i < coverage_modules->len; i++) { + + coverage_module_t *module = + &g_array_index(coverage_modules, coverage_module_t, i); + if (!module->referenced) continue; + + coverage_format("%3u, ", emitted); + coverage_format("%016" G_GINT64_MODIFIER "X, ", module->base_address); + coverage_format("%016" G_GINT64_MODIFIER "X, ", module->limit); + /* entry */ + coverage_format("%016" G_GINT64_MODIFIER "X, ", 0); + /* checksum */ + coverage_format("%016" G_GINT64_MODIFIER "X, ", 0); + /* timestamp */ + coverage_format("%08" G_GINT32_MODIFIER "X, ", 0); + coverage_format("%s\n", module->path); + emitted++; + + } + +} + +static void coverage_write_events(void *key, void *value, void *user_data) { + + UNUSED_PARAMETER(key); + UNUSED_PARAMETER(user_data); + coverage_data_t *val = (coverage_data_t *)value; + coverage_event_t evt = { + + .offset = val->start - val->module->base_address, + .length = val->end - val->start, + .module = val->module->id, + + }; + + coverage_write(&evt, sizeof(coverage_event_t)); + +} + +static void coverage_write_header() { + + char version[] = "DRCOV VERSION: 2\n"; + char flavour[] = "DRCOV FLAVOR: frida\n"; + char columns[] = "Columns: id, base, end, entry, checksum, timestamp, path\n"; + coverage_write(version, sizeof(version) - 1); + coverage_write(flavour, sizeof(flavour) - 1); + coverage_format("Module Table: version 2, count %u\n", + coverage_marked_modules); + coverage_write(columns, sizeof(columns) - 1); + coverage_write_modules(); + coverage_format("BB Table: %u bbs\n", coverage_marked_entries); + g_hash_table_foreach(coverage_hash, coverage_write_events, NULL); + +} + +static void coverage_mark_modules() { + + guint i; + for (i = 0; i < coverage_modules->len; i++) { + + coverage_module_t *module = + &g_array_index(coverage_modules, coverage_module_t, i); + + OKF("Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%u:%s)", + i, module->referenced ? 'X' : ' ', module->base_address, module->limit, + module->id, module->path); + + if (!module->referenced) { continue; } + + module->id = coverage_marked_modules; + coverage_marked_modules++; + + } + +} + +static void instrument_coverage_run() { + + int bytes; + coverage_data_t data; + coverage_data_t *value; + OKF("Coverage - Running"); + + if (close(coverage_pipes[STDOUT_FILENO]) != 0) { + + FATAL("Failed to close parent read pipe"); + + } + + for (bytes = + read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t)); + bytes == sizeof(coverage_data_t); + bytes = + read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t))) { + + value = (coverage_data_t *)gum_malloc0(sizeof(coverage_data_t)); + memcpy(value, &data, sizeof(coverage_data_t)); + g_hash_table_insert(coverage_hash, GSIZE_TO_POINTER(data.start), value); + + } + + if (bytes != 0) { FATAL("Coverage data truncated"); } + + if (errno != ENOENT) { FATAL("Coverage I/O error"); } + + OKF("Coverage - Preparing"); + + coverage_get_ranges(); + + guint size = g_hash_table_size(coverage_hash); + OKF("Coverage - Total Entries: %u", size); + + g_hash_table_foreach(coverage_hash, instrument_coverage_mark, NULL); + OKF("Coverage - Marked Entries: %u", coverage_marked_entries); + + coverage_mark_modules(); + OKF("Coverage - Marked Modules: %u", coverage_marked_modules); + + coverage_write_header(); + + OKF("Coverage - Completed"); + +} + +void instrument_coverage_config(void) { + + instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE"); + +} + +void instrument_coverage_init(void) { + + OKF("Coverage - enabled [%c]", + instrument_coverage_filename == NULL ? ' ' : 'X'); + + if (instrument_coverage_filename == NULL) { return; } + + OKF("Coverage - file [%s]", instrument_coverage_filename); + + char *path = g_canonicalize_filename(instrument_coverage_filename, + g_get_current_dir()); + + OKF("Coverage - path [%s]", path); + + coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (coverage_fd < 0) { FATAL("Failed to open coverage file '%s'", path); } + + g_free(path); + + if (pipe2(coverage_pipes, O_DIRECT) != 0) { FATAL("Failed to create pipes"); } + + coverage_hash = g_hash_table_new(g_direct_hash, g_direct_equal); + if (coverage_hash == NULL) { + + FATAL("Failed to g_hash_table_new, errno: %d", errno); + + } + + pid_t pid = fork(); + if (pid == -1) { FATAL("Failed to start coverage process"); } + + if (pid == 0) { + + instrument_coverage_run(); + exit(0); + + } + + if (close(coverage_pipes[STDIN_FILENO]) != 0) { + + FATAL("Failed to close parent read pipe"); + + } + +} + +void instrument_coverage_start(uint64_t address) { + + coverage_last_start = address; + +} + +void instrument_coverage_end(uint64_t address) { + + coverage_data_t data = { + + .start = coverage_last_start, .end = address, .module = NULL}; + + if (write(coverage_pipes[STDOUT_FILENO], &data, sizeof(coverage_data_t)) != + sizeof(coverage_data_t)) { + + FATAL("Coverage I/O error"); + + } + +} + diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index b8f2d39a..f0cf7311 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -85,6 +85,14 @@ class Afl { static setInMemoryFuzzing() { Afl.jsApiAflSharedMemFuzzing.writeInt(1); } + /** + * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` + * as an argument. + */ + static setInstrumentCoverageFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentCoverageFile(buf); + } /** * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as * an argument. @@ -233,6 +241,7 @@ Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []); Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]); Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []); Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]); +Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]); Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]); Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []); Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 930a6dc0..e51f852a 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -107,6 +107,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_libraries() { } +__attribute__((visibility("default"))) void js_api_set_instrument_coverage_file( + char *path) { + + instrument_coverage_filename = g_strdup(path); + +} + __attribute__((visibility("default"))) void js_api_set_instrument_debug_file( char *path) { diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 6326c099..c1ed123e 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -103,6 +103,15 @@ class Afl { Afl.jsApiAflSharedMemFuzzing.writeInt(1); } + /** + * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` + * as an argument. + */ + public static setInstrumentCoverageFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentCoverageFile(buf); + } + /** * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as * an argument. @@ -282,6 +291,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction( + "js_api_set_instrument_coverage_file", + "void", + ["pointer"]); + private static readonly jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction( "js_api_set_instrument_debug_file", "void", diff --git a/include/envs.h b/include/envs.h index 49605330..722fe1a5 100644 --- a/include/envs.h +++ b/include/envs.h @@ -55,6 +55,7 @@ static char *afl_environment_variables[] = { "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_EXCLUDE_RANGES", + "AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_OPTIMIZE", -- cgit 1.4.1 From c3641fbd976f5ef4df05f06241a4f1dc99ed80a3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 17 Aug 2021 18:34:46 +0100 Subject: Changes to build many-linux build from working copy instead of a fixed branch --- frida_mode/GNUmakefile | 2 +- frida_mode/many-linux/Dockerfile | 10 ---------- frida_mode/many-linux/GNUmakefile | 8 ++++---- frida_mode/many-linux/README.md | 3 ++- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 6b17982d..58a53823 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -166,7 +166,7 @@ $(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR cp -v $< $@ else $(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) - wget -O $@ $(GUM_DEVKIT_URL) + wget -O $@ $(GUM_DEVKIT_URL) || curl -L -o $@ $(GUM_DEVKIT_URL) endif $(GUM_DEVIT_LIBRARY): $(GUM_DEVKIT_TARBALL) diff --git a/frida_mode/many-linux/Dockerfile b/frida_mode/many-linux/Dockerfile index 2cd56bc8..170f0757 100644 --- a/frida_mode/many-linux/Dockerfile +++ b/frida_mode/many-linux/Dockerfile @@ -6,19 +6,9 @@ RUN chmod +x /bin/realpath RUN yum -y install xz RUN yum -y install vim-common -WORKDIR / -RUN git clone https://github.com/AFLplusplus/AFLplusplus.git - -WORKDIR /AFLplusplus -RUN mkdir -p /AFLplusplus/frida_mode/build/frida/ -RUN curl -L -o /AFLplusplus/frida_mode/build/frida/frida-gumjs-devkit-15.0.0-linux-x86_64.tar.xz "https://github.com/frida/frida/releases/download/15.0.0/frida-gumjs-devkit-15.0.0-linux-x86_64.tar.xz" - WORKDIR /AFLplusplus -RUN git checkout dev -WORKDIR /AFLplusplus/frida_mode ENV CFLAGS="\ -DADDR_NO_RANDOMIZE=0x0040000 \ -Wno-implicit-function-declaration \ " ENV CXX=$CC -RUN make diff --git a/frida_mode/many-linux/GNUmakefile b/frida_mode/many-linux/GNUmakefile index 2860f20c..03b619f6 100644 --- a/frida_mode/many-linux/GNUmakefile +++ b/frida_mode/many-linux/GNUmakefile @@ -1,20 +1,20 @@ PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../ BUILD_DIR:=$(PWD)build/ .PHONY: all clean shell -all: | $(BUILD_DIR) +all: docker build --tag many-afl-frida . docker run --rm \ - -v $(PWD)build/:/export \ + -v $(ROOT):/AFLplusplus \ many-afl-frida \ - cp /AFLplusplus/afl-frida-trace.so /export + make -C /AFLplusplus/frida_mode clean all $(BUILD_DIR): mkdir -p $@ clean: - rm -rf $(BUILD_DIR) docker images --filter 'dangling=true' -q --no-trunc | xargs -L1 docker rmi --force shell: diff --git a/frida_mode/many-linux/README.md b/frida_mode/many-linux/README.md index 2c7b6823..4bd7a6c1 100644 --- a/frida_mode/many-linux/README.md +++ b/frida_mode/many-linux/README.md @@ -5,4 +5,5 @@ This folder contains a Docker image to allow the building of based on CentOS Linux 5. By building `afl-frida-trace.so` for such an old version of Linux, given the strong backward compatibility of Linux, this should work on the majority of Linux environments. This may be useful for targetting -Linux distributions other than your development environment. \ No newline at end of file +Linux distributions other than your development environment. `many-local` builds +`AFLplusplus` from the local working copy in the `many-linux` environment. -- cgit 1.4.1 From 10c98c2a4c6ef73e25d460933eeda60e320c9bbf Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 17 Aug 2021 18:42:44 +0100 Subject: Fix coverage data --- frida_mode/src/instrument/instrument.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index c0f1b2c9..e37c1d29 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -217,7 +217,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, instrument_flush(output); instrument_debug_end(output); - instrument_coverage_end(instr->address); + instrument_coverage_end(instr->address + instr->size); } -- cgit 1.4.1 From 69b7f2cae4fbb1ad34fd6a01aa0056126d7609d0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 18 Aug 2021 10:06:33 +0200 Subject: switch back to -j4 for building llvm --- GNUmakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 2161e68d..376f6e9a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -310,7 +310,7 @@ all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_bu .PHONY: llvm llvm: - -$(MAKE) -j -f GNUmakefile.llvm + -$(MAKE) -j4 -f GNUmakefile.llvm @test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; } .PHONY: gcc_plugin @@ -598,7 +598,7 @@ endif .PHONY: distrib distrib: all - -$(MAKE) -j -f GNUmakefile.llvm + -$(MAKE) -j4 -f GNUmakefile.llvm ifneq "$(SYS)" "Darwin" -$(MAKE) -f GNUmakefile.gcc_plugin endif @@ -630,7 +630,7 @@ endif .PHONY: source-only source-only: all - -$(MAKE) -j -f GNUmakefile.llvm + -$(MAKE) -j4 -f GNUmakefile.llvm ifneq "$(SYS)" "Darwin" -$(MAKE) -f GNUmakefile.gcc_plugin endif -- cgit 1.4.1 From 17681405bcdc292cd5238c3199682d1e2f6a505c Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 18 Aug 2021 10:47:07 +0100 Subject: Force exit of coverage process --- frida_mode/src/instrument/instrument_coverage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 68284e71..9d1701d1 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -340,7 +340,7 @@ void instrument_coverage_init(void) { if (pid == 0) { instrument_coverage_run(); - exit(0); + _exit(0); } -- cgit 1.4.1 From 1959812e83becb0895b924d0398d634055cd0c10 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 18 Aug 2021 15:46:01 +0200 Subject: more partial linking --- src/afl-cc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/afl-cc.c b/src/afl-cc.c index 244b46d1..a61635a2 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -794,6 +794,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strcmp(cur, "-E")) preprocessor_only = 1; if (!strcmp(cur, "-shared")) shared_linking = 1; if (!strcmp(cur, "-Wl,-r")) partial_linking = 1; + if (!strcmp(cur, "-Wl,-i")) partial_linking = 1; if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1; if (!strcmp(cur, "-r")) partial_linking = 1; if (!strcmp(cur, "--relocatable")) partial_linking = 1; -- cgit 1.4.1 From 591d6c59c758d1043f8690e4e9dda22dbbefbc1c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 19 Aug 2021 17:02:17 +0200 Subject: fix shared linking on macos --- docs/Changelog.md | 8 +++++--- instrumentation/afl-compiler-rt.o.c | 7 ++++++- src/afl-cc.c | 13 +++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 3a2658f0..7ccae7c2 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,9 +10,11 @@ sending a mail to . ### Version ++3.15a (dev) - afl-fuzz: - added AFL_IGNORE_PROBLEMS plus checks to identify and abort on - incorrect LTO usage setups and enhanced the READMEs for better - information on how to deal with instrumenting libraries + - added AFL_IGNORE_PROBLEMS plus checks to identify and abort on + incorrect LTO usage setups and enhanced the READMEs for better + information on how to deal with instrumenting libraries + - afl-cc: + - fix for shared linking on MacOS - added the very good grammar mutator "GramaTron" to the custom_mutators - added optimin, a faster and better corpus minimizer by diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 18b0a55b..9acab4e7 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1273,7 +1273,12 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { if (__afl_already_initialized_second) return; __afl_already_initialized_second = 1; - if (getenv("AFL_DEBUG")) { __afl_debug = 1; } + if (getenv("AFL_DEBUG")) { + + __afl_debug = 1; + fprintf(stderr, "DEBUG: debug enabled\n"); + + } if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; diff --git a/src/afl-cc.c b/src/afl-cc.c index a61635a2..e49addc4 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -793,6 +793,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strcmp(cur, "-x")) x_set = 1; if (!strcmp(cur, "-E")) preprocessor_only = 1; if (!strcmp(cur, "-shared")) shared_linking = 1; + if (!strcmp(cur, "-dynamiclib")) shared_linking = 1; if (!strcmp(cur, "-Wl,-r")) partial_linking = 1; if (!strcmp(cur, "-Wl,-i")) partial_linking = 1; if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1; @@ -1085,6 +1086,18 @@ static void edit_params(u32 argc, char **argv, char **envp) { alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); #endif + #if defined(__APPLE__) + if (shared_linking || partial_linking) { + + cc_params[cc_par_cnt++] = "-Wl,-U"; + cc_params[cc_par_cnt++] = "-Wl,___afl_area_ptr"; + cc_params[cc_par_cnt++] = "-Wl,-U"; + cc_params[cc_par_cnt++] = "-Wl,___sanitizer_cov_trace_pc_guard_init"; + + } + + #endif + } #if defined(USEMMAP) && !defined(__HAIKU__) -- cgit 1.4.1 From 3513ba2e51222151945e8ae87236bb9d2f07f37a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 19 Aug 2021 17:26:41 +0200 Subject: update unicornafl --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 5db24eec..da9641d5 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -0d82727f2b477de82fa355edef9bc158bd25d374 +9064bca9ba diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 019b8715..9064bca9 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad +Subproject commit 9064bca9ba875d868742cdb9251edfaa2d7d294b -- cgit 1.4.1 From 56e2c55914f4291043b68595e93b3329fb107d1b Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 12:18:13 +0200 Subject: typos --- frida_mode/DEBUGGING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frida_mode/DEBUGGING.md b/frida_mode/DEBUGGING.md index f8d91f2f..f6dd0546 100644 --- a/frida_mode/DEBUGGING.md +++ b/frida_mode/DEBUGGING.md @@ -113,8 +113,8 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, ``` ## ASAN -It is also possible to enalbe ASAN (if that is the configuration you are having -issues with) without having to use `afl-fuzz` this can be done as follows (note +It is also possible to enable ASAN (if that is the configuration you are having +issues with) without having to use `afl-fuzz`. This can be done as follows (note that the name of the asan DSO may need to be changed depending on your platform). Note that the asan DSO must appear first in the `LD_PRELOAD` environment variable: -- cgit 1.4.1 From c2e02df9a5e1bd8d5339ee2da8c3e834282986c6 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 12:21:00 +0200 Subject: wording --- frida_mode/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frida_mode/README.md b/frida_mode/README.md index af79de07..e60340b4 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -308,7 +308,7 @@ library and call a target function within it. The dependent library can either be loaded in using `dlopen` and `dlsym` in a function marked `__attribute__((constructor()))` or the test harness can simply be linked against it. It is important that the target library is loaded before execution -of `main`, since this is the point that FRIDA mode is initialized. Otherwise, it +of `main`, since this is the point where FRIDA mode is initialized. Otherwise, it will not be possible to configure coverage for the test library using `AFL_FRIDA_INST_RANGES` or similar. -- cgit 1.4.1 From 41a4c99d01ddce1ef3db51077477a51411911705 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 12:37:47 +0200 Subject: typos / wording --- instrumentation/README.lto.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md index 38252308..3e9d7585 100644 --- a/instrumentation/README.lto.md +++ b/instrumentation/README.lto.md @@ -146,22 +146,22 @@ afl-clang-lto instead of shared libraries! To make instrumented shared libraries work with afl-clang-lto you have to do quite some extra steps. -Every shared library you want to instrument has to be individually compiled- +Every shared library you want to instrument has to be individually compiled. The environment variable `AFL_LLVM_LTO_DONTWRITEID=1` has to be set during compilation. Additionally the environment variable `AFL_LLVM_LTO_STARTID` has to be set to -the combined edge values of all previous compiled instrumented shared +the added edge count values of all previous compiled instrumented shared libraries for that target. E.g. for the first shared library this would be `AFL_LLVM_LTO_STARTID=0` and afl-clang-lto will then report how many edges have been instrumented (let's say it reported 1000 instrumented edges). The second shared library then has to be set to that value -(`AFL_LLVM_LTO_STARTID=1000` in our example), the third to all previous -combined, etc. +(`AFL_LLVM_LTO_STARTID=1000` in our example), for the third to all previous +counts added, etc. The final program compilation step then may *not* have `AFL_LLVM_LTO_DONTWRITEID` -set, and `AFL_LLVM_LTO_STARTID` must be set to all combined edges of all shared -libaries it will be linked to. +set, and `AFL_LLVM_LTO_STARTID` must be set to all edge counts added of all shared +libraries it will be linked to. This is quite some hands-on work, so better stay away from instrumenting shared libraries :-) -- cgit 1.4.1 From f189668dd6b223317e6f9f4d98b9d8929e695fa5 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 13:00:51 +0200 Subject: fix typo fix --- src/afl-fuzz-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 1d32d966..eb1fe2d9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1339,7 +1339,7 @@ void show_init_stats(afl_state_t *afl) { } - ACTF("No -t option specified, so I'll use exec an timeout of %u ms.", + ACTF("No -t option specified, so I'll use an exec timeout of %u ms.", afl->fsrv.exec_tmout); afl->timeout_given = 1; -- cgit 1.4.1 From 23c240a94a0bd930e601e2dd575aa3608983b6ff Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 13:13:23 +0200 Subject: add newline at end --- utils/plot_ui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/plot_ui/Makefile b/utils/plot_ui/Makefile index 7ade8a40..b2013248 100644 --- a/utils/plot_ui/Makefile +++ b/utils/plot_ui/Makefile @@ -7,4 +7,4 @@ afl-plot-ui: afl-plot-ui.c $(CC) $(CFLAGS) -o afl-plot-ui afl-plot-ui.c $(LDFLAGS) clean: - rm -f afl-plot-ui \ No newline at end of file + rm -f afl-plot-ui -- cgit 1.4.1 From 87794121711f376fc1905e0451b744f9334e8075 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 13:18:14 +0200 Subject: wording --- utils/qbdi_mode/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index a68da616..8b768906 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -1,8 +1,8 @@ # qbdi-based binary-only instrumentation for afl-fuzz NOTE: this code is outdated and first would need to be adapted to the current -AFL++ versions first. -Try frida_mode/ or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. +AFL++ versions. +Try frida_mode or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. ## 1) Introduction -- cgit 1.4.1 From 5ba3601697769fd51e26a3504c165bb7be71bc69 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 20 Aug 2021 13:51:59 +0200 Subject: revise paragraph --- instrumentation/README.persistent_mode.md | 17 +++++++++-------- unicorn_mode/unicornafl | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md index 0517886b..c6ba2103 100644 --- a/instrumentation/README.persistent_mode.md +++ b/instrumentation/README.persistent_mode.md @@ -2,17 +2,18 @@ ## 1) Introduction -In persistent mode, AFL++ fuzzes a target multiple times -in a single process, instead of forking a new process for each fuzz execution. -This is the most effective way to fuzz, as the speed can easily -be x10 or x20 times faster without any disadvanges. +In persistent mode, AFL++ fuzzes a target multiple times in a single forked +process, instead of forking a new process for each fuzz execution. +This is the most effective way to fuzz, as the speed can easily be x10 or x20 +times faster without any disadvanges. *All professional fuzzing uses this mode.* - Persistent mode requires that the target can be called in one or more functions, -and that its state can be reset so that multiple calls can be performed -without resource leaks and earlier runs will have no impact on future runs -(this can be seen by the `stability` indicator in the `afl-fuzz` UI). +and that it's state can be completely reset so that multiple calls can be +performed without resource leaks, and that earlier runs will have no impact on +future runs (an indicator for this is the `stability` value in the `afl-fuzz` +UI, if this decreases to lower values in persistent mode compared to +non-persistent mode, that the fuzz target keeps state). Examples can be found in [utils/persistent_mode](../utils/persistent_mode). diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 9064bca9..019b8715 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 9064bca9ba875d868742cdb9251edfaa2d7d294b +Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad -- cgit 1.4.1 From d8c221fade27b75a387587dc7b5e20ab82ec8012 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 16:12:25 +0200 Subject: typo --- frida_mode/DEBUGGING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frida_mode/DEBUGGING.md b/frida_mode/DEBUGGING.md index f6dd0546..69663510 100644 --- a/frida_mode/DEBUGGING.md +++ b/frida_mode/DEBUGGING.md @@ -10,7 +10,7 @@ you are very familiar with the implementation of Stalker, the instrumented code generated by FRIDA is likely to be very difficult to follow. For this reason, the following debugging strategies are outlined below. -Byte convention below all files should be provided with their path (they are +By convention below all files should be provided with their path (they are omitted for readability) and all items in `` are placeholders and should be replaced accordingly. -- cgit 1.4.1 From 028f8ced8f772d82a7efc522ec629bf4a5fff32d Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Aug 2021 17:28:40 +0100 Subject: Fixed coverage on OSX (dependency on pipe2) Removed use of 'realpath' in makefiles to fix OSX incompatibility Fixed handling of when prefetching should be enabled Snap the main binary during initialization to avoid stability issues with lazy loading Add support for configurable inline cache entries for FRIDA on x86/x64 Support for prefetching FRIDA backpatches on x86/x64 Improved stats support on x86/x64/aarch64 --- frida_mode/GNUmakefile | 11 +- frida_mode/README.md | 125 +++---- frida_mode/Scripting.md | 8 - frida_mode/frida.map | 2 +- frida_mode/include/entry.h | 3 +- frida_mode/include/prefetch.h | 1 + frida_mode/include/ranges.h | 2 +- frida_mode/include/stalker.h | 4 + frida_mode/include/stats.h | 56 +++- frida_mode/src/entry.c | 10 +- frida_mode/src/instrument/instrument.c | 8 +- frida_mode/src/instrument/instrument_coverage.c | 5 +- frida_mode/src/js/api.js | 21 +- frida_mode/src/js/js_api.c | 22 +- frida_mode/src/persistent/persistent.c | 2 +- frida_mode/src/prefetch.c | 98 +++++- frida_mode/src/ranges.c | 8 +- frida_mode/src/stalker.c | 80 +++++ frida_mode/src/stats/stats.c | 423 +++++++++++++++++------- frida_mode/src/stats/stats_arm32.c | 13 +- frida_mode/src/stats/stats_arm64.c | 307 ++++++++++++++++- frida_mode/src/stats/stats_x64.c | 325 ------------------ frida_mode/src/stats/stats_x86.c | 36 -- frida_mode/src/stats/stats_x86_64.c | 420 +++++++++++++++++++++++ frida_mode/test/cmplog/GNUmakefile | 2 +- frida_mode/test/deferred/GNUmakefile | 2 +- frida_mode/test/entry_point/GNUmakefile | 2 +- frida_mode/test/exe/GNUmakefile | 2 +- frida_mode/test/fasan/GNUmakefile | 2 +- frida_mode/test/jpeg/GNUmakefile | 2 +- frida_mode/test/js/GNUmakefile | 2 +- frida_mode/test/libpcap/GNUmakefile | 4 +- frida_mode/test/osx-lib/GNUmakefile | 2 +- frida_mode/test/output/GNUmakefile | 2 +- frida_mode/test/persistent_ret/GNUmakefile | 2 +- frida_mode/test/png/GNUmakefile | 2 +- frida_mode/test/png/persistent/GNUmakefile | 6 +- frida_mode/test/png/persistent/hook/GNUmakefile | 19 +- frida_mode/test/proj4/GNUmakefile | 2 +- frida_mode/test/re2/GNUmakefile | 4 +- frida_mode/test/sqlite/GNUmakefile | 20 +- frida_mode/test/testinstr/GNUmakefile | 2 +- frida_mode/test/unstable/GNUmakefile | 2 +- frida_mode/ts/lib/afl.ts | 36 +- include/envs.h | 2 +- 45 files changed, 1453 insertions(+), 656 deletions(-) delete mode 100644 frida_mode/src/stats/stats_x64.c delete mode 100644 frida_mode/src/stats/stats_x86.c create mode 100644 frida_mode/src/stats/stats_x86_64.c diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 58a53823..3e35e2f6 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -83,16 +83,7 @@ ifndef OS $(error "Operating system unsupported") endif -ifeq "$(ARCH)" "arm64" -# 15.0.0 Not released for aarch64 yet -GUM_DEVKIT_VERSION=14.2.18 -else -ifeq "$(ARCH)" "armhf" -GUM_DEVKIT_VERSION=14.2.18 -else -GUM_DEVKIT_VERSION=15.0.0 -endif -endif +GUM_DEVKIT_VERSION=15.0.16 GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" diff --git a/frida_mode/README.md b/frida_mode/README.md index af79de07..5e944daa 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -162,7 +162,12 @@ 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. +them and they be inherited by the next child on fork, implies +`AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. +* `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH` - Disable prefetching of stalker +backpatching information. By default the child will report applied backpatches +to the parent so that they can be applied and then be inherited by the next +child on fork. * `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to generate block (and hence edge) IDs. Setting this to a constant value may be useful for debugging purposes, e.g. investigating unstable edges. @@ -189,6 +194,9 @@ gdb \ --args [my arguments] ``` +* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries +stored along-side branch instructions which provide a cache to avoid having to +call back into FRIDA to find the next block. Default is 32. * `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being instrumented to the given file name. The statistics are written only for the child process when new block is instrumented (when the @@ -198,67 +206,70 @@ the existing blocks instrumented have been executed in a different order. ``` stats ----- -Index: 2 -Pid: 1815944 -Time: 2021-05-28 15:26:41 -Blocks: 1985 -Instructions: 9192 -Avg Instructions / Block: 4 - -Call Immediates: 391 (4.25%) -Call Immediates Excluded: 65 (0.71%) -Call Register: 0 (0.00%) -Call Memory: 0 (0.00%) - -Jump Immediates: 202 (2.20%) -Jump Register: 10 (0.11%) -Jump Memory: 12 (0.13%) - -Conditional Jump Immediates: 1210 (13.16%) -Conditional Jump CX Immediate: 0 (0.00%) -Conditional Jump Register: 0 (0.00%) -Conditional Jump Memory: 0 (0.00%) - -Returns: 159 (0.00%) - -Rip Relative: 247 (0.00%) - +Time 2021-07-21 11:45:49 +Elapsed 1 seconds + + +Transitions cumulative delta +----------- ---------- ----- +total 753619 17645 +call_imm 9193 ( 1.22%) 344 ( 1.95%) [ 344/s] +call_reg 0 ( 0.00%) 0 ( 0.00%) [ 0/s] +call_mem 0 ( 0.00%) 0 ( 0.00%) [ 0/s] +ret_slow_path 67974 ( 9.02%) 2988 (16.93%) [ 2988/s] +post_call_invoke 7996 ( 1.06%) 299 ( 1.69%) [ 299/s] +excluded_call_imm 3804 ( 0.50%) 200 ( 1.13%) [ 200/s] +jmp_imm 5445 ( 0.72%) 255 ( 1.45%) [ 255/s] +jmp_reg 42081 ( 5.58%) 1021 ( 5.79%) [ 1021/s] +jmp_mem 578092 (76.71%) 10956 (62.09%) [ 10956/s] +jmp_cond_imm 38951 ( 5.17%) 1579 ( 8.95%) [ 1579/s] +jmp_cond_mem 0 ( 0.00%) 0 ( 0.00%) [ 0/s] +jmp_cond_reg 0 ( 0.00%) 0 ( 0.00%) [ 0/s] +jmp_cond_jcxz 0 ( 0.00%) 0 ( 0.00%) [ 0/s] +jmp_continuation 84 ( 0.01%) 3 ( 0.02%) [ 3/s] + + +Instrumentation +--------------- +Instructions 7907 +Blocks 1764 +Avg Instructions / Block 4 + + +EOB Instructions +---------------- +Total 1763 (22.30%) +Call Immediates 358 ( 4.53%) +Call Immediates Excluded 74 ( 0.94%) +Call Register 0 ( 0.00%) +Call Memory 0 ( 0.00%) +Jump Immediates 176 ( 2.23%) +Jump Register 8 ( 0.10%) +Jump Memory 10 ( 0.13%) +Conditional Jump Immediates 1051 (13.29%) +Conditional Jump CX Immediate 0 ( 0.00%) +Conditional Jump Register 0 ( 0.00%) +Conditional Jump Memory 0 ( 0.00%) +Returns 160 ( 2.02%) + + +Relocated Instructions +---------------------- +Total 232 ( 2.93%) +addsd 2 ( 0.86%) +cmp 46 (19.83%) +comisd 2 ( 0.86%) +divsd 2 ( 0.86%) +divss 2 ( 0.86%) +lea 142 (61.21%) +mov 32 (13.79%) +movsd 2 ( 0.86%) +ucomisd 2 ( 0.86%) ``` * `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics information. Stats will be written whenever they are updated if the given interval has elapsed since last time they were written. -* `AFL_FRIDA_STATS_TRANSITIONS` - Also dump the internal stalker counters to -stderr when the regular stats are written. Note that these stats are reset in -the child each time a new fork occurs since they are not stored in shared -memory. Unfortunately, these stats are internal to stalker, so this is the best -we can do for now. -``` -stats ------ -Index: 2 -Pid: 1816794 -Time: 2021-05-28 15:26:41 - - -total_transitions: 786 - call_imms: 97 - call_regs: 0 - call_mems: 0 - post_call_invokes: 86 - excluded_call_imms: 29 - ret_slow_paths: 23 - jmp_imms: 58 - jmp_mems: 7 - jmp_regs: 26 - - jmp_cond_imms: 460 - jmp_cond_mems: 0 - jmp_cond_regs: 0 - jmp_cond_jcxzs: 0 - - jmp_continuations: 0 -``` ## FASAN - Frida Address Sanitizer Mode Frida mode also supports FASAN. The design of this is actually quite simple and very similar to that used when instrumenting applications compiled from source. diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md index 5467db99..f6017fad 100644 --- a/frida_mode/Scripting.md +++ b/frida_mode/Scripting.md @@ -80,7 +80,6 @@ Afl.setInstrumentEnableTracing(); Afl.setInstrumentTracingUnique(); Afl.setStatsFile("/tmp/stats.txt"); Afl.setStatsInterval(1); -Afl.setStatsTransitions(); /* *ALWAYS* call this when you have finished all your configuration */ Afl.done(); @@ -833,13 +832,6 @@ class Afl { Afl.jsApiSetStatsInterval(interval); } - /** - * See `AFL_FRIDA_STATS_TRANSITIONS` - */ - public static setStatsTransitions(): void { - Afl.jsApiSetStatsTransitions(); - } - /** * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as * an argument. diff --git a/frida_mode/frida.map b/frida_mode/frida.map index cf304885..7ad5e682 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -23,11 +23,11 @@ js_api_set_persistent_debug; js_api_set_persistent_hook; js_api_set_persistent_return; + js_api_set_prefetch_backpatch_disable; js_api_set_prefetch_disable; js_api_set_stalker_callback; js_api_set_stats_file; js_api_set_stats_interval; - js_api_set_stats_transitions; js_api_set_stderr; js_api_set_stdout; diff --git a/frida_mode/include/entry.h b/frida_mode/include/entry.h index cbc5c8c7..3f0a4ecc 100644 --- a/frida_mode/include/entry.h +++ b/frida_mode/include/entry.h @@ -4,7 +4,8 @@ #include "frida-gumjs.h" extern guint64 entry_point; -extern gboolean entry_reached; +extern gboolean entry_compiled; +extern gboolean entry_run; void entry_config(void); diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h index 835d5e8a..d1ea5a31 100644 --- a/frida_mode/include/prefetch.h +++ b/frida_mode/include/prefetch.h @@ -4,6 +4,7 @@ #include "frida-gumjs.h" extern gboolean prefetch_enable; +extern gboolean prefetch_backpatch; void prefetch_config(void); void prefetch_init(void); diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index 2eb9b355..0220a59d 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -10,7 +10,7 @@ extern gboolean ranges_inst_jit; void ranges_config(void); void ranges_init(void); -gboolean range_is_excluded(gpointer address); +gboolean range_is_excluded(GumAddress address); void ranges_exclude(); diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h index b5e05d5a..955f3913 100644 --- a/frida_mode/include/stalker.h +++ b/frida_mode/include/stalker.h @@ -3,11 +3,15 @@ #include "frida-gumjs.h" +extern guint stalker_ic_entries; + void stalker_config(void); void stalker_init(void); GumStalker *stalker_get(void); void stalker_start(void); void stalker_trust(void); +GumStalkerObserver *stalker_get_observer(void); + #endif diff --git a/frida_mode/include/stats.h b/frida_mode/include/stats.h index cd2350ea..0ad227c3 100644 --- a/frida_mode/include/stats.h +++ b/frida_mode/include/stats.h @@ -5,30 +5,56 @@ typedef struct { - guint64 num_blocks; - guint64 num_instructions; - guint64 stats_last_time; - guint64 stats_idx; - guint64 transitions_idx; + guint64 stats_time; + guint64 total; + guint64 call_imm; + guint64 call_reg; + guint64 call_mem; + guint64 excluded_call_reg; + guint64 ret_slow_path; + guint64 ret; + guint64 post_call_invoke; + guint64 excluded_call_imm; + guint64 jmp_imm; + guint64 jmp_reg; + guint64 jmp_mem; + guint64 jmp_cond_imm; + guint64 jmp_cond_mem; + guint64 jmp_cond_reg; + guint64 jmp_cond_jcxz; + guint64 jmp_cond_cc; + guint64 jmp_cond_cbz; + guint64 jmp_cond_cbnz; + guint64 jmp_cond_tbz; + guint64 jmp_cond_tbnz; + guint64 jmp_continuation; + +} stats_t; -} stats_data_header_t; +typedef struct { + + /* transitions */ + stats_t curr; + stats_t prev; + +} stats_data_t; -extern stats_data_header_t *stats_data; +#define GUM_TYPE_AFL_STALKER_STATS (gum_afl_stalker_stats_get_type()) +G_DECLARE_FINAL_TYPE(GumAflStalkerStats, gum_afl_stalker_stats, GUM, + AFL_STALKER_STATS, GObject) -extern char * stats_filename; -extern guint64 stats_interval; -extern gboolean stats_transitions; +extern char * stats_filename; +extern guint64 stats_interval; void stats_config(void); void stats_init(void); void stats_collect(const cs_insn *instr, gboolean begin); void stats_print(char *format, ...); -gboolean stats_is_supported_arch(void); -size_t stats_data_size_arch(void); -void stats_collect_arch(const cs_insn *instr); -void stats_write_arch(void); -void stats_on_fork(void); +void starts_arch_init(void); +void stats_collect_arch(const cs_insn *instr, gboolean begin); +void stats_write_arch(stats_data_t *data); +void stats_on_fork(void); #endif diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index 0b5f61ec..3ec8f5be 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -1,3 +1,5 @@ +#include + #include "frida-gumjs.h" #include "debug.h" @@ -13,7 +15,8 @@ extern void __afl_manual_init(); guint64 entry_point = 0; -gboolean entry_reached = FALSE; +gboolean entry_compiled = FALSE; +gboolean entry_run = FALSE; static void entry_launch(void) { @@ -21,7 +24,7 @@ static void entry_launch(void) { __afl_manual_init(); /* Child here */ - entry_reached = TRUE; + entry_run = TRUE; instrument_on_fork(); stats_on_fork(); @@ -37,6 +40,8 @@ void entry_init(void) { OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_point); + if (dlopen(NULL, RTLD_NOW) == NULL) { FATAL("Failed to dlopen: %d", errno); } + } void entry_start(void) { @@ -49,6 +54,7 @@ static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) { UNUSED_PARAMETER(cpu_context); UNUSED_PARAMETER(user_data); + entry_compiled = TRUE; entry_launch(); } diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index e37c1d29..9e4dd191 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -164,7 +164,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, * our AFL_ENTRYPOINT, since it is not until then that we start the * fork-server and thus start executing in the child. */ - excluded = range_is_excluded(GSIZE_TO_POINTER(instr->address)); + excluded = range_is_excluded(GUM_ADDRESS(instr->address)); stats_collect(instr, begin); @@ -173,11 +173,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, instrument_debug_start(instr->address, output); instrument_coverage_start(instr->address); - if (likely(entry_reached)) { - - prefetch_write(GSIZE_TO_POINTER(instr->address)); - - } + prefetch_write(GSIZE_TO_POINTER(instr->address)); if (likely(!excluded)) { diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 9d1701d1..4c0d1a14 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -277,8 +278,6 @@ static void instrument_coverage_run() { if (bytes != 0) { FATAL("Coverage data truncated"); } - if (errno != ENOENT) { FATAL("Coverage I/O error"); } - OKF("Coverage - Preparing"); coverage_get_ranges(); @@ -325,7 +324,7 @@ void instrument_coverage_init(void) { g_free(path); - if (pipe2(coverage_pipes, O_DIRECT) != 0) { FATAL("Failed to create pipes"); } + if (pipe(coverage_pipes) != 0) { FATAL("Failed to create pipes"); } coverage_hash = g_hash_table_new(g_direct_hash, g_direct_equal); if (coverage_hash == NULL) { diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index f0cf7311..71b5e4a4 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -171,6 +171,12 @@ class Afl { static setPersistentReturn(address) { Afl.jsApiSetPersistentReturn(address); } + /** + * See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. + */ + static setPrefetchBackpatchDisable() { + Afl.jsApiSetPrefetchBackpatchDisable(); + } /** * See `AFL_FRIDA_INST_NO_PREFETCH`. */ @@ -184,6 +190,12 @@ class Afl { static setStalkerCallback(callback) { Afl.jsApiSetStalkerCallback(callback); } + /** + * See `AFL_FRIDA_STALKER_IC_ENTRIES`. + */ + static setStalkerIcEntries(val) { + Afl.jsApiSetStalkerIcEntries(val); + } /** * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as * an argument. @@ -199,12 +211,6 @@ class Afl { static setStatsInterval(interval) { Afl.jsApiSetStatsInterval(interval); } - /** - * See `AFL_FRIDA_STATS_TRANSITIONS` - */ - static setStatsTransitions() { - Afl.jsApiSetStatsTransitions(); - } /** * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as * an argument. @@ -254,11 +260,12 @@ Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count" Afl.jsApiSetPersistentDebug = Afl.jsApiGetFunction("js_api_set_persistent_debug", "void", []); Afl.jsApiSetPersistentHook = Afl.jsApiGetFunction("js_api_set_persistent_hook", "void", ["pointer"]); Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_return", "void", ["pointer"]); +Afl.jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_backpatch_disable", "void", []); Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []); Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]); +Afl.jsApiSetStalkerIcEntries = Afl.jsApiGetFunction("js_api_set_stalker_ic_entries", "void", ["uint32"]); Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]); Afl.jsApiSetStatsInterval = Afl.jsApiGetFunction("js_api_set_stats_interval", "void", ["uint64"]); -Afl.jsApiSetStatsTransitions = Afl.jsApiGetFunction("js_api_set_stats_transitions", "void", []); Afl.jsApiSetStdErr = Afl.jsApiGetFunction("js_api_set_stderr", "void", ["pointer"]); Afl.jsApiSetStdOut = Afl.jsApiGetFunction("js_api_set_stdout", "void", ["pointer"]); Afl.jsApiWrite = new NativeFunction( diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index e51f852a..c2746d13 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -7,8 +7,10 @@ #include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "stalker.h" #include "stats.h" #include "util.h" + __attribute__((visibility("default"))) void js_api_done() { js_done = TRUE; @@ -127,6 +129,13 @@ __attribute__((visibility("default"))) void js_api_set_prefetch_disable(void) { } +__attribute__((visibility("default"))) void +js_api_set_prefetch_backpatch_disable(void) { + + prefetch_backpatch = FALSE; + +} + __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( void) { @@ -180,12 +189,6 @@ __attribute__((visibility("default"))) void js_api_set_stats_interval( } -__attribute__((visibility("default"))) void js_api_set_stats_transitions() { - - stats_transitions = TRUE; - -} - __attribute__((visibility("default"))) void js_api_set_persistent_hook( void *address) { @@ -206,3 +209,10 @@ __attribute__((visibility("default"))) void js_api_set_stalker_callback( } +__attribute__((visibility("default"))) void js_api_set_stalker_ic_entries( + guint val) { + + stalker_ic_entries = val; + +} + diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index 639a694e..b2915a2f 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -89,7 +89,7 @@ void persistent_init(void) { void persistent_prologue(GumStalkerOutput *output) { OKF("AFL_FRIDA_PERSISTENT_ADDR reached"); - entry_reached = TRUE; + entry_compiled = TRUE; ranges_exclude(); stalker_trust(); persistent_prologue_arch(output); diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 50d10c9e..0efbc9bf 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -6,32 +6,66 @@ #include "debug.h" +#include "entry.h" #include "intercept.h" #include "prefetch.h" #include "stalker.h" +#include "util.h" #define TRUST 0 #define PREFETCH_SIZE 65536 #define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) +#define BP_SIZE 524288 + typedef struct { size_t count; void * entry[PREFETCH_ENTRIES]; + guint8 backpatch_data[BP_SIZE]; + gsize backpatch_size; + } prefetch_data_t; gboolean prefetch_enable = TRUE; +gboolean prefetch_backpatch = TRUE; static prefetch_data_t *prefetch_data = NULL; static int prefetch_shm_id = -1; +static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self, + const GumBackpatch *backpatch, + gsize size) { + + UNUSED_PARAMETER(self); + if (!entry_run) { return; } + gsize remaining = + sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size; + if (sizeof(gsize) + size > remaining) { return; } + + *(gsize *)(&prefetch_data->backpatch_data[prefetch_data->backpatch_size]) = + size; + prefetch_data->backpatch_size += sizeof(gsize); + + memcpy(&prefetch_data->backpatch_data[prefetch_data->backpatch_size], + backpatch, size); + prefetch_data->backpatch_size += size; + +} + /* * 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) { +#if defined(__aarch64__) + if (!entry_compiled) { return; } +#else + if (!entry_run) { return; } +#endif + /* Bail if we aren't initialized */ if (prefetch_data == NULL) return; @@ -51,10 +85,7 @@ void prefetch_write(void *addr) { } -/* - * Read the IPC region one block at the time and prefetch it - */ -void prefetch_read(void) { +static void prefetch_read_blocks(void) { GumStalker *stalker = stalker_get(); if (prefetch_data == NULL) return; @@ -74,10 +105,60 @@ void prefetch_read(void) { } +static void prefetch_read_patches(void) { + + gsize offset = 0; + GumStalker * stalker = stalker_get(); + GumBackpatch *backpatch = NULL; + + for (gsize remaining = prefetch_data->backpatch_size - offset; + remaining > sizeof(gsize); + remaining = prefetch_data->backpatch_size - offset) { + + gsize size = *(gsize *)(&prefetch_data->backpatch_data[offset]); + offset += sizeof(gsize); + + if (prefetch_data->backpatch_size - offset < size) { + + FATAL("Incomplete backpatch entry"); + + } + + backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset]; + gum_stalker_prefetch_backpatch(stalker, backpatch); + offset += size; + + } + + prefetch_data->backpatch_size = 0; + +} + +/* + * Read the IPC region one block at the time and prefetch it + */ +void prefetch_read(void) { + + prefetch_read_blocks(); + prefetch_read_patches(); + +} + void prefetch_config(void) { prefetch_enable = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); + if (prefetch_enable) { + + prefetch_backpatch = + (getenv("AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH") == NULL); + + } else { + + prefetch_backpatch = FALSE; + + } + } static int prefetch_on_fork(void) { @@ -97,8 +178,9 @@ static void prefetch_hook_fork(void) { void prefetch_init(void) { - g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); OKF("Instrumentation - prefetch [%c]", prefetch_enable ? 'X' : ' '); + OKF("Instrumentation - prefetch_backpatch [%c]", + prefetch_backpatch ? 'X' : ' '); if (!prefetch_enable) { return; } /* @@ -131,5 +213,11 @@ void prefetch_init(void) { prefetch_hook_fork(); + if (!prefetch_backpatch) { return; } + + GumStalkerObserver * observer = stalker_get_observer(); + GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer); + iface->notify_backpatch = gum_afl_stalker_backpatcher_notify; + } diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 6fdd65a7..5b6eb462 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -635,9 +635,7 @@ void ranges_init(void) { } -gboolean range_is_excluded(gpointer address) { - - GumAddress test = GUM_ADDRESS(address); +gboolean range_is_excluded(GumAddress address) { if (ranges == NULL) { return false; } @@ -646,9 +644,9 @@ gboolean range_is_excluded(gpointer address) { GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); GumAddress curr_limit = curr->base_address + curr->size; - if (test < curr->base_address) { return false; } + if (address < curr->base_address) { return false; } - if (test < curr_limit) { return true; } + if (address < curr_limit) { return true; } } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index 5df0386f..814aaeb3 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -1,15 +1,67 @@ #include "debug.h" #include "instrument.h" +#include "prefetch.h" #include "stalker.h" +#include "stats.h" #include "util.h" +guint stalker_ic_entries = 0; + static GumStalker *stalker = NULL; +struct _GumAflStalkerObserver { + + GObject parent; + +}; + +#define GUM_TYPE_AFL_STALKER_OBSERVER (gum_afl_stalker_observer_get_type()) +G_DECLARE_FINAL_TYPE(GumAflStalkerObserver, gum_afl_stalker_observer, GUM, + AFL_STALKER_OBSERVER, GObject) + +static void gum_afl_stalker_observer_iface_init(gpointer g_iface, + gpointer iface_data); +static void gum_afl_stalker_observer_class_init( + GumAflStalkerObserverClass *klass); +static void gum_afl_stalker_observer_init(GumAflStalkerObserver *self); + +G_DEFINE_TYPE_EXTENDED( + GumAflStalkerObserver, gum_afl_stalker_observer, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE(GUM_TYPE_STALKER_OBSERVER, + gum_afl_stalker_observer_iface_init)) + +static GumAflStalkerObserver *observer = NULL; + +static void gum_afl_stalker_observer_iface_init(gpointer g_iface, + gpointer iface_data) { + + UNUSED_PARAMETER(g_iface); + UNUSED_PARAMETER(iface_data); + +} + +static void gum_afl_stalker_observer_class_init( + GumAflStalkerObserverClass *klass) { + + UNUSED_PARAMETER(klass); + +} + +static void gum_afl_stalker_observer_init(GumAflStalkerObserver *self) { + + UNUSED_PARAMETER(self); + +} + void stalker_config(void) { if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); } + stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES"); + + observer = g_object_new(GUM_TYPE_AFL_STALKER_OBSERVER, NULL); + } static gboolean stalker_exclude_self(const GumRangeDetails *details, @@ -35,7 +87,26 @@ static gboolean stalker_exclude_self(const GumRangeDetails *details, void stalker_init(void) { + OKF("Stalker - ic_entries [%u]", stalker_ic_entries); + +#if !(defined(__x86_64__) || defined(__i386__)) + if (stalker_ic_entries != 0) { + + FATAL("AFL_FRIDA_STALKER_IC_ENTRIES not supported"); + + } + +#endif + + if (stalker_ic_entries == 0) { stalker_ic_entries = 32; } + +#if defined(__x86_64__) || defined(__i386__) + stalker = + g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, NULL); +#else stalker = gum_stalker_new(); +#endif + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } gum_stalker_set_trust_threshold(stalker, -1); @@ -57,6 +128,8 @@ void stalker_start(void) { GumStalkerTransformer *transformer = instrument_get_transformer(); gum_stalker_follow_me(stalker, transformer, NULL); + gum_stalker_set_observer(stalker, GUM_STALKER_OBSERVER(observer)); + } void stalker_trust(void) { @@ -65,3 +138,10 @@ void stalker_trust(void) { } +GumStalkerObserver *stalker_get_observer(void) { + + if (observer == NULL) { FATAL("Stalker not yet initialized"); } + return GUM_STALKER_OBSERVER(observer); + +} + diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 91a58741..7972b881 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -11,204 +11,405 @@ #include "debug.h" #include "util.h" +#include "entry.h" +#include "stalker.h" #include "stats.h" #define MICRO_TO_SEC 1000000 -stats_data_header_t *stats_data = NULL; +char * stats_filename = NULL; +guint64 stats_interval = 0; +static guint64 stats_interval_us = 0; +static int stats_fd = -1; +static stats_data_t *stats_data = MAP_FAILED; -static int stats_parent_pid = -1; -static int stats_fd = -1; +void stats_write(void) { -char * stats_filename = NULL; -guint64 stats_interval = 0; -gboolean stats_transitions = FALSE; + if (stats_filename == NULL) { return; } -void stats_config(void) { + if (stats_interval == 0) { return; } - stats_filename = getenv("AFL_FRIDA_STATS_FILE"); - stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); - if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) { + guint64 current_time = g_get_monotonic_time(); + if ((current_time - stats_data->prev.stats_time) < stats_interval_us) { - stats_transitions = TRUE; + return; } + IGNORED_RETURN(ftruncate(stats_fd, 0)); + IGNORED_RETURN(lseek(stats_fd, 0, SEEK_SET)); + + stats_data->curr.stats_time = current_time; + + GDateTime *date_time = g_date_time_new_now_local(); + char * date_string = g_date_time_format(date_time, "%Y-%m-%d"); + char * time_string = g_date_time_format(date_time, "%H:%M:%S"); + guint elapsed = (stats_data->curr.stats_time - stats_data->prev.stats_time) / + MICRO_TO_SEC; + + stats_print("stats\n"); + stats_print("-----\n"); + + stats_print("%-21s %s %s\n", "Time", date_string, time_string); + stats_print("%-30s %10u seconds \n", "Elapsed", elapsed); + + stats_print("\n"); + stats_print("\n"); + + g_free(time_string); + g_free(date_string); + g_date_time_unref(date_time); + + stats_write_arch(stats_data); + + memcpy(&stats_data->prev, &stats_data->curr, sizeof(stats_t)); + } -void stats_init(void) { +static void gum_afl_stalker_stats_increment_total( + GumStalkerObserver *observer) { - stats_parent_pid = getpid(); + UNUSED_PARAMETER(observer); - OKF("Stats - file [%s]", stats_filename); - OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + if (!entry_compiled) { return; } + stats_data->curr.total++; - if (stats_interval != 0 && stats_filename == NULL) { +} - FATAL( - "AFL_FRIDA_STATS_FILE must be specified if " - "AFL_FRIDA_STATS_INTERVAL is"); +static void gum_afl_stalker_stats_increment_call_imm( + GumStalkerObserver *observer) { - } + UNUSED_PARAMETER(observer); - if (stats_interval == 0) { stats_interval = 10; } + if (!entry_compiled) { return; } + stats_data->curr.call_imm++; - if (stats_filename == NULL) { return; } +} - if (!stats_is_supported_arch()) { +static void gum_afl_stalker_stats_increment_call_reg( + GumStalkerObserver *observer) { - FATAL("Stats is not supported on this architecture"); + UNUSED_PARAMETER(observer); - } + if (!entry_compiled) { return; } + stats_data->curr.call_reg++; - char *path = NULL; +} - if (stats_filename == NULL) { return; } +static void gum_afl_stalker_stats_increment_call_mem( + GumStalkerObserver *observer) { - if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); } + UNUSED_PARAMETER(observer); - path = g_canonicalize_filename(stats_filename, g_get_current_dir()); + if (!entry_compiled) { return; } + stats_data->curr.call_mem++; - OKF("Stats - path [%s]", path); +} - stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +static void gum_afl_stalker_stats_increment_excluded_call_reg( + GumStalkerObserver *observer) { - if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + UNUSED_PARAMETER(observer); - g_free(path); + if (!entry_compiled) { return; } + stats_data->curr.excluded_call_reg++; - size_t data_size = stats_data_size_arch(); +} - int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } +static void gum_afl_stalker_stats_increment_ret_slow_path( + GumStalkerObserver *observer) { - stats_data = shmat(shm_id, NULL, 0); - g_assert(stats_data != MAP_FAILED); + UNUSED_PARAMETER(observer); - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + if (!entry_compiled) { return; } + stats_data->curr.ret_slow_path++; - FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); +} - } +static void gum_afl_stalker_stats_increment_ret(GumStalkerObserver *observer) { - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(stats_data, '\0', data_size); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.ret++; } -void stats_vprint(int fd, char *format, va_list ap) { +static void gum_afl_stalker_stats_increment_post_call_invoke( + GumStalkerObserver *observer) { - char buffer[4096] = {0}; - int len; + UNUSED_PARAMETER(observer); - if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + if (!entry_compiled) { return; } + stats_data->curr.post_call_invoke++; - len = strnlen(buffer, sizeof(buffer)); - IGNORED_RETURN(write(fd, buffer, len)); +} + +static void gum_afl_stalker_stats_increment_excluded_call_imm( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.excluded_call_imm++; } -void stats_print_fd(int fd, char *format, ...) { +static void gum_afl_stalker_stats_increment_jmp_imm( + GumStalkerObserver *observer) { - va_list ap; - va_start(ap, format); - stats_vprint(fd, format, ap); - va_end(ap); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_imm++; } -void stats_print(char *format, ...) { +static void gum_afl_stalker_stats_increment_jmp_reg( + GumStalkerObserver *observer) { - va_list ap; - va_start(ap, format); - stats_vprint(stats_fd, format, ap); - va_end(ap); + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_reg++; } -void stats_write(void) { +static void gum_afl_stalker_stats_increment_jmp_mem( + GumStalkerObserver *observer) { - if (stats_parent_pid == getpid()) { return; } + UNUSED_PARAMETER(observer); - GDateTime *date_time = g_date_time_new_now_local(); - char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + if (!entry_compiled) { return; } + stats_data->curr.jmp_mem++; - stats_print("stats\n"); - stats_print("-----\n"); +} - stats_print("Index: %" G_GINT64_MODIFIER "u\n", - stats_data->stats_idx++); - stats_print("Pid: %d\n", getpid()); - stats_print("Time: %s\n", date_time_string); - stats_print("Blocks: %" G_GINT64_MODIFIER "u\n", - stats_data->num_blocks); - stats_print("Instructions: %" G_GINT64_MODIFIER "u\n", - stats_data->num_instructions); - stats_print("Avg Instructions / Block: %" G_GINT64_MODIFIER "u\n", - stats_data->num_instructions / stats_data->num_blocks); +static void gum_afl_stalker_stats_increment_jmp_cond_imm( + GumStalkerObserver *observer) { - stats_print("\n"); + UNUSED_PARAMETER(observer); - g_free(date_time_string); - g_date_time_unref(date_time); + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_imm++; - stats_write_arch(); +} - if (stats_transitions) { +static void gum_afl_stalker_stats_increment_jmp_cond_mem( + GumStalkerObserver *observer) { - GDateTime *date_time = g_date_time_new_now_local(); - char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + UNUSED_PARAMETER(observer); - stats_print_fd(STDERR_FILENO, "stats\n"); - stats_print_fd(STDERR_FILENO, "-----\n"); - stats_print_fd(STDERR_FILENO, "Index: %" G_GINT64_MODIFIER "u\n", - stats_data->transitions_idx++); - stats_print_fd(STDERR_FILENO, "Pid: %d\n", getpid()); - stats_print_fd(STDERR_FILENO, "Time: %s\n", date_time_string); + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_mem++; - g_free(date_time_string); - g_date_time_unref(date_time); - gum_stalker_dump_counters(); +} - } +static void gum_afl_stalker_stats_increment_jmp_cond_reg( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_reg++; } -void stats_on_fork(void) { +static void gum_afl_stalker_stats_increment_jmp_cond_jcxz( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_jcxz++; + +} + +static void gum_afl_stalker_stats_increment_jmp_cond_cc( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_cc++; + +} + +static void gum_afl_stalker_stats_increment_jmp_cond_cbz( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_cbz++; + +} + +static void gum_afl_stalker_stats_increment_jmp_cond_cbnz( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_cbnz++; + +} + +static void gum_afl_stalker_stats_increment_jmp_cond_tbz( + GumStalkerObserver *observer) { - guint64 current_time; + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_tbz++; + +} + +static void gum_afl_stalker_stats_increment_jmp_cond_tbnz( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_cond_tbnz++; + +} + +static void gum_afl_stalker_stats_increment_jmp_continuation( + GumStalkerObserver *observer) { + + UNUSED_PARAMETER(observer); + + if (!entry_compiled) { return; } + stats_data->curr.jmp_continuation++; + +} + +static void stats_observer_init(GumStalkerObserver *observer) { + + GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer); + iface->increment_total = gum_afl_stalker_stats_increment_total; + iface->increment_call_imm = gum_afl_stalker_stats_increment_call_imm; + iface->increment_call_reg = gum_afl_stalker_stats_increment_call_reg; + iface->increment_call_mem = gum_afl_stalker_stats_increment_call_mem; + iface->increment_excluded_call_reg = + gum_afl_stalker_stats_increment_excluded_call_reg; + iface->increment_ret_slow_path = + gum_afl_stalker_stats_increment_ret_slow_path; + iface->increment_ret = gum_afl_stalker_stats_increment_ret; + iface->increment_post_call_invoke = + gum_afl_stalker_stats_increment_post_call_invoke; + iface->increment_excluded_call_imm = + gum_afl_stalker_stats_increment_excluded_call_imm; + iface->increment_jmp_imm = gum_afl_stalker_stats_increment_jmp_imm; + iface->increment_jmp_reg = gum_afl_stalker_stats_increment_jmp_reg; + iface->increment_jmp_mem = gum_afl_stalker_stats_increment_jmp_mem; + iface->increment_jmp_cond_imm = gum_afl_stalker_stats_increment_jmp_cond_imm; + iface->increment_jmp_cond_mem = gum_afl_stalker_stats_increment_jmp_cond_mem; + iface->increment_jmp_cond_reg = gum_afl_stalker_stats_increment_jmp_cond_reg; + iface->increment_jmp_cond_jcxz = + gum_afl_stalker_stats_increment_jmp_cond_jcxz; + iface->increment_jmp_cond_cc = gum_afl_stalker_stats_increment_jmp_cond_cc; + iface->increment_jmp_cond_cbz = gum_afl_stalker_stats_increment_jmp_cond_cbz; + iface->increment_jmp_cond_cbnz = + gum_afl_stalker_stats_increment_jmp_cond_cbnz; + iface->increment_jmp_cond_tbz = gum_afl_stalker_stats_increment_jmp_cond_tbz; + iface->increment_jmp_cond_tbnz = + gum_afl_stalker_stats_increment_jmp_cond_tbnz; + iface->increment_jmp_continuation = + gum_afl_stalker_stats_increment_jmp_continuation; + +} + +void stats_config(void) { + + stats_filename = getenv("AFL_FRIDA_STATS_FILE"); + stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); + +} + +void stats_init(void) { + + OKF("Stats - file [%s]", stats_filename); + OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + + if (stats_interval != 0 && stats_filename == NULL) { + + FATAL( + "AFL_FRIDA_STATS_FILE must be specified if " + "AFL_FRIDA_STATS_INTERVAL is"); + + } + + if (stats_interval == 0) { stats_interval = 10; } + stats_interval_us = stats_interval * MICRO_TO_SEC; if (stats_filename == NULL) { return; } - if (stats_interval == 0) { return; } + char *path = g_canonicalize_filename(stats_filename, g_get_current_dir()); + + OKF("Stats - path [%s]", path); - current_time = g_get_monotonic_time(); + stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } - if ((current_time - stats_data->stats_last_time) > - (stats_interval * MICRO_TO_SEC)) { + g_free(path); - stats_write(); - stats_data->stats_last_time = current_time; + int shm_id = + shmget(IPC_PRIVATE, sizeof(stats_data_t), IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + stats_data = shmat(shm_id, NULL, 0); + g_assert(stats_data != MAP_FAILED); + + GumStalkerObserver *observer = stalker_get_observer(); + stats_observer_init(observer); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(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(stats_data, '\0', sizeof(stats_data_t)); + + starts_arch_init(); + } -void stats_collect(const cs_insn *instr, gboolean begin) { +void stats_print(char *format, ...) { - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(begin); + char buffer[4096] = {0}; + int len; - if (stats_fd < 0) { return; } + va_list ap; + va_start(ap, format); - if (begin) { stats_data->num_blocks++; } - stats_data->num_instructions++; + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } - stats_collect_arch(instr); + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(stats_fd, buffer, len)); + va_end(ap); + +} + +void stats_on_fork(void) { + + stats_write(); + +} + +void stats_collect(const cs_insn *instr, gboolean begin) { + + if (!entry_compiled) { return; } + if (stats_filename == NULL) { return; } + stats_collect_arch(instr, begin); } diff --git a/frida_mode/src/stats/stats_arm32.c b/frida_mode/src/stats/stats_arm32.c index 71953af3..5860d33b 100644 --- a/frida_mode/src/stats/stats_arm32.c +++ b/frida_mode/src/stats/stats_arm32.c @@ -7,27 +7,22 @@ #if defined(__arm__) -gboolean stats_is_supported_arch(void) { - - return FALSE; - -} - -size_t stats_data_size_arch(void) { +void starts_arch_init(void) { FATAL("Stats not supported on this architecture"); } -void stats_write_arch(void) { +void stats_write_arch(stats_data_t *data) { FATAL("Stats not supported on this architecture"); } -void stats_collect_arch(const cs_insn *instr) { +void stats_collect_arch(const cs_insn *instr, gboolean begin) { UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(begin); FATAL("Stats not supported on this architecture"); } diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c index d9d374a4..54b3faf1 100644 --- a/frida_mode/src/stats/stats_arm64.c +++ b/frida_mode/src/stats/stats_arm64.c @@ -1,34 +1,323 @@ +#include +#include + #include "frida-gumjs.h" #include "debug.h" +#include "ranges.h" #include "stats.h" #include "util.h" +#define MICRO_TO_SEC 1000000 + #if defined(__aarch64__) -gboolean stats_is_supported_arch(void) { +typedef struct { + + guint64 num_blocks; + guint64 num_instructions; + + guint64 num_eob; + guint64 num_reloc; + + guint64 num_adr; + guint64 num_adrp; + + guint64 num_b; + guint64 num_bcc; + guint64 num_bl; + guint64 num_br; + + guint64 num_cbz; + guint64 num_cbnz; + + guint64 num_ldr; + guint64 num_ldrsw; + + guint64 num_ret; + + guint64 num_tbz; + guint64 num_tbnz; + +} stats_data_arch_t; + +static stats_data_arch_t *stats_data_arch = NULL; + +void starts_arch_init(void) { + + int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t), + IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + stats_data_arch = shmat(shm_id, NULL, 0); + g_assert(stats_data_arch != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + + FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - return FALSE; + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(stats_data_arch, '\0', sizeof(stats_data_arch_t)); } -size_t stats_data_size_arch(void) { +static void stats_write_arch_stat(char *label, guint64 value, guint64 total) { + + stats_print("%-30s ", label); + stats_print("%10" G_GINT64_MODIFIER "u ", value); + if (total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)value * 100) / total); - FATAL("Stats not supported on this architecture"); + } + + stats_print("\n"); } -void stats_write_arch(void) { +static void stats_write_arch_stat_delta(char *label, guint64 prev_value, + guint64 curr_value, guint elapsed, + guint64 prev_total, + guint64 curr_total) { + + guint64 delta = curr_value - prev_value; + guint64 delta_total = curr_total - prev_total; + guint64 per_sec = delta / elapsed; + + stats_print("%-30s ", label); + + stats_print("%10" G_GINT64_MODIFIER "u ", curr_value); + if (curr_total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)curr_value * 100) / curr_total); + + } + + stats_print("%10" G_GINT64_MODIFIER "u ", delta); + if (delta_total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)delta * 100) / delta_total); - FATAL("Stats not supported on this architecture"); + } + + stats_print("[%10" G_GINT64_MODIFIER "u/s]", per_sec); + stats_print("\n"); } -void stats_collect_arch(const cs_insn *instr) { +void stats_write_arch(stats_data_t *data) { + + guint elapsed = + (data->curr.stats_time - data->prev.stats_time) / MICRO_TO_SEC; + stats_print("%-30s %10s %19s\n", "Transitions", "cumulative", "delta"); + stats_print("%-30s %10s %19s\n", "-----------", "----------", "-----"); + stats_print( + "%-30s %10" G_GINT64_MODIFIER "u %-8s %10" G_GINT64_MODIFIER "u\n", + "total", data->curr.total, "", data->curr.total - data->prev.total); + stats_write_arch_stat_delta("call_imm", data->prev.call_imm, + data->curr.call_imm, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("call_reg", data->prev.call_reg, + data->curr.call_reg, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("excluded_call_reg", data->prev.excluded_call_reg, + data->curr.excluded_call_reg, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("ret", data->prev.ret, data->curr.ret, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("post_call_invoke", data->prev.post_call_invoke, + data->curr.post_call_invoke, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("excluded_call_imm", data->prev.excluded_call_imm, + data->curr.excluded_call_imm, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_imm", data->prev.jmp_imm, data->curr.jmp_imm, + elapsed, data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_reg", data->prev.jmp_reg, data->curr.jmp_reg, + elapsed, data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_cc", data->prev.jmp_cond_cc, + data->curr.jmp_cond_cc, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("jmp_cond_cbz", data->prev.jmp_cond_cbz, + data->curr.jmp_cond_cbz, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_cbnz", data->prev.jmp_cond_cbnz, + data->curr.jmp_cond_cbnz, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_tbz", data->prev.jmp_cond_tbz, + data->curr.jmp_cond_tbz, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_tbnz", data->prev.jmp_cond_tbnz, + data->curr.jmp_cond_tbnz, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_continuation", data->prev.jmp_continuation, + data->curr.jmp_continuation, elapsed, + data->prev.total, data->curr.total); + stats_print("\n"); + stats_print("\n"); + + stats_print("Instrumentation\n"); + stats_print("---------------\n"); + stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Instructions", + stats_data_arch->num_instructions); + stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Blocks", + stats_data_arch->num_blocks); + + if (stats_data_arch->num_blocks != 0) { + + stats_print( + "%-30s %10" G_GINT64_MODIFIER "u\n", "Avg Instructions / Block ", + stats_data_arch->num_instructions / stats_data_arch->num_blocks); + + } + + stats_print("\n"); + stats_print("\n"); + + guint64 num_instructions = stats_data_arch->num_instructions; + + stats_print("EOB Instructions\n"); + stats_print("----------------\n"); + stats_write_arch_stat("Total", stats_data_arch->num_eob, num_instructions); + stats_write_arch_stat("B", stats_data_arch->num_b, num_instructions); + stats_write_arch_stat("Bcc", stats_data_arch->num_bcc, num_instructions); + stats_write_arch_stat("BL", stats_data_arch->num_bl, num_instructions); + stats_write_arch_stat("BR", stats_data_arch->num_br, num_instructions); + stats_write_arch_stat("CBZ", stats_data_arch->num_cbz, num_instructions); + stats_write_arch_stat("CBNZ", stats_data_arch->num_cbnz, num_instructions); + stats_write_arch_stat("RET", stats_data_arch->num_ret, num_instructions); + stats_write_arch_stat("TBZ", stats_data_arch->num_tbz, num_instructions); + stats_write_arch_stat("TBNZ", stats_data_arch->num_tbnz, num_instructions); + stats_print("\n"); + stats_print("\n"); + + stats_print("Relocated Instructions\n"); + stats_print("----------------------\n"); + stats_write_arch_stat("Total", stats_data_arch->num_reloc, num_instructions); + + stats_write_arch_stat("ADR", stats_data_arch->num_adr, num_instructions); + stats_write_arch_stat("ADRP", stats_data_arch->num_adrp, num_instructions); + stats_write_arch_stat("LDR", stats_data_arch->num_ldr, num_instructions); + stats_write_arch_stat("LDRSW", stats_data_arch->num_ldrsw, num_instructions); + + stats_print("\n"); + stats_print("\n"); + +} + +void stats_collect_arch(const cs_insn *instr, gboolean begin) { + + if (stats_data_arch == NULL) { return; } + if (begin) { stats_data_arch->num_blocks++; } + stats_data_arch->num_instructions++; + + switch (instr->id) { + + case ARM64_INS_ADR: + stats_data_arch->num_adr++; + stats_data_arch->num_reloc++; + break; + + case ARM64_INS_ADRP: + stats_data_arch->num_adrp++; + stats_data_arch->num_reloc++; + break; + + case ARM64_INS_B: + switch (instr->detail->arm64.cc) { + + case ARM64_CC_INVALID: + case ARM64_CC_AL: + case ARM64_CC_NV: + stats_data_arch->num_b++; + break; + default: + stats_data_arch->num_bcc++; + break; + + } + + stats_data_arch->num_eob++; + break; + + case ARM64_INS_BR: + case ARM64_INS_BRAA: + case ARM64_INS_BRAAZ: + case ARM64_INS_BRAB: + case ARM64_INS_BRABZ: + stats_data_arch->num_br++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_BL: + case ARM64_INS_BLR: + case ARM64_INS_BLRAA: + case ARM64_INS_BLRAAZ: + case ARM64_INS_BLRAB: + case ARM64_INS_BLRABZ: + stats_data_arch->num_bl++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_CBZ: + stats_data_arch->num_cbz++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_CBNZ: + stats_data_arch->num_cbnz++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_LDR: + stats_data_arch->num_ldr++; + stats_data_arch->num_reloc++; + break; + + case ARM64_INS_LDRSW: + stats_data_arch->num_ldrsw++; + stats_data_arch->num_reloc++; + break; + + case ARM64_INS_RET: + case ARM64_INS_RETAA: + case ARM64_INS_RETAB: + stats_data_arch->num_ret++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_TBZ: + stats_data_arch->num_tbz++; + stats_data_arch->num_eob++; + break; + + case ARM64_INS_TBNZ: + stats_data_arch->num_tbnz++; + stats_data_arch->num_eob++; + break; + + default: + break; - UNUSED_PARAMETER(instr); - FATAL("Stats not supported on this architecture"); + } } diff --git a/frida_mode/src/stats/stats_x64.c b/frida_mode/src/stats/stats_x64.c deleted file mode 100644 index 11464a2a..00000000 --- a/frida_mode/src/stats/stats_x64.c +++ /dev/null @@ -1,325 +0,0 @@ -#include "frida-gumjs.h" - -#include "debug.h" - -#include "ranges.h" -#include "stats.h" -#include "util.h" - -#if defined(__x86_64__) - -typedef struct { - - stats_data_header_t header; - - guint64 num_call_imm; - guint64 num_call_imm_excluded; - guint64 num_call_reg; - guint64 num_call_mem; - - guint64 num_jmp_imm; - guint64 num_jmp_reg; - guint64 num_jmp_mem; - - guint64 num_jmp_cond_imm; - guint64 num_jmp_cond_reg; - guint64 num_jmp_cond_mem; - - guint64 num_jmp_cond_jcxz; - - guint64 num_ret; - - guint64 num_rip_relative; - - guint64 num_rip_relative_type[X86_INS_ENDING]; - char name_rip_relative_type[X86_INS_ENDING][CS_MNEMONIC_SIZE]; - -} stats_data_arch_t; - -gboolean stats_is_supported_arch(void) { - - return TRUE; - -} - -size_t stats_data_size_arch(void) { - - return sizeof(stats_data_arch_t); - -} - -void stats_write_arch(void) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - guint64 num_instructions = stats_data_arch->header.num_instructions; - - stats_print( - "Call Immediates: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_call_imm, - ((float)(stats_data_arch->num_call_imm * 100) / num_instructions)); - stats_print("Call Immediates Excluded: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_call_imm_excluded, - ((float)(stats_data_arch->num_call_imm_excluded * 100) / - num_instructions)); - stats_print( - "Call Register: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_call_reg, - ((float)(stats_data_arch->num_call_reg * 100) / num_instructions)); - stats_print( - "Call Memory: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_call_mem, - ((float)(stats_data_arch->num_call_mem * 100) / num_instructions)); - - stats_print("\n"); - - stats_print("Jump Immediates: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_imm, - ((float)(stats_data_arch->num_jmp_imm * 100) / num_instructions)); - stats_print("Jump Register: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_reg, - ((float)(stats_data_arch->num_jmp_reg * 100) / num_instructions)); - stats_print("Jump Memory: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_mem, - ((float)(stats_data_arch->num_jmp_mem * 100) / num_instructions)); - - stats_print("\n"); - - stats_print( - "Conditional Jump Immediates: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_cond_imm, - ((float)(stats_data_arch->num_jmp_cond_imm * 100) / num_instructions)); - stats_print( - "Conditional Jump CX Immediate: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_cond_jcxz, - ((float)(stats_data_arch->num_jmp_cond_jcxz * 100) / num_instructions)); - stats_print( - "Conditional Jump Register: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_cond_reg, - ((float)(stats_data_arch->num_jmp_cond_reg * 100) / num_instructions)); - stats_print( - "Conditional Jump Memory: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_jmp_cond_mem, - ((float)(stats_data_arch->num_jmp_cond_mem * 100) / num_instructions)); - - stats_print("\n"); - - stats_print("Returns: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_ret, - (stats_data_arch->num_ret * 100 / num_instructions)); - - stats_print("\n"); - - stats_print("Rip Relative: %" G_GINT64_MODIFIER - "u " - "(%3.2f%%)\n", - stats_data_arch->num_rip_relative, - (stats_data_arch->num_rip_relative * 100 / num_instructions)); - - for (size_t i = 0; i < X86_INS_ENDING; i++) { - - if (stats_data_arch->num_rip_relative_type[i] != 0) { - - stats_print(" %10d %s\n", - stats_data_arch->num_rip_relative_type[i], - stats_data_arch->name_rip_relative_type[i]); - - } - - } - - stats_print("\n"); - stats_print("\n"); - -} - -static x86_op_type stats_get_operand_type(const cs_insn *instr) { - - cs_x86 * x86 = &instr->detail->x86; - cs_x86_op *operand; - - if (x86->op_count != 1) { - - FATAL("Unexpected operand count (%d): %s %s\n", x86->op_count, - instr->mnemonic, instr->op_str); - - } - - operand = &x86->operands[0]; - - return operand->type; - -} - -static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - cs_x86 * x86 = &instr->detail->x86; - cs_x86_op * operand = &x86->operands[0]; - - if (range_is_excluded((gpointer)operand->imm)) { - - stats_data_arch->num_call_imm_excluded++; - - } - -} - -static void stats_collect_call_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - x86_op_type type = stats_get_operand_type(instr); - switch (type) { - - case X86_OP_IMM: - stats_data_arch->num_call_imm++; - stats_collect_call_imm_excluded_arch(instr); - break; - case X86_OP_REG: - stats_data_arch->num_call_reg++; - break; - case X86_OP_MEM: - stats_data_arch->num_call_mem++; - break; - default: - FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); - - } - -} - -static void stats_collect_jump_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - x86_op_type type = stats_get_operand_type(instr); - switch (type) { - - case X86_OP_IMM: - stats_data_arch->num_jmp_imm++; - break; - case X86_OP_REG: - stats_data_arch->num_jmp_reg++; - break; - case X86_OP_MEM: - stats_data_arch->num_jmp_mem++; - break; - default: - FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); - - } - -} - -static void stats_collect_jump_cond_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - x86_op_type type = stats_get_operand_type(instr); - switch (type) { - - case X86_OP_IMM: - stats_data_arch->num_jmp_cond_imm++; - break; - case X86_OP_REG: - stats_data_arch->num_jmp_cond_reg++; - break; - case X86_OP_MEM: - stats_data_arch->num_jmp_cond_mem++; - break; - default: - FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); - - } - -} - -static void stats_collect_rip_relative_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - cs_x86 * x86 = &instr->detail->x86; - guint mod; - guint rm; - - if (x86->encoding.modrm_offset == 0) { return; } - - mod = (x86->modrm & 0xc0) >> 6; - if (mod != 0) { return; } - - rm = (x86->modrm & 0x07) >> 0; - if (rm != 5) { return; } - - stats_data_arch->num_rip_relative++; - stats_data_arch->num_rip_relative_type[instr->id]++; - memcpy(stats_data_arch->name_rip_relative_type[instr->id], instr->mnemonic, - CS_MNEMONIC_SIZE); - -} - -void stats_collect_arch(const cs_insn *instr) { - - stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; - switch (instr->id) { - - case X86_INS_CALL: - stats_collect_call_arch(instr); - break; - case X86_INS_JMP: - stats_collect_jump_arch(instr); - break; - case X86_INS_JA: - case X86_INS_JAE: - case X86_INS_JB: - case X86_INS_JBE: - case X86_INS_JE: - case X86_INS_JG: - case X86_INS_JGE: - case X86_INS_JL: - case X86_INS_JLE: - case X86_INS_JNE: - case X86_INS_JNO: - case X86_INS_JNP: - case X86_INS_JNS: - case X86_INS_JO: - case X86_INS_JP: - case X86_INS_JS: - stats_collect_jump_cond_arch(instr); - break; - case X86_INS_JECXZ: - case X86_INS_JRCXZ: - stats_data_arch->num_jmp_cond_jcxz++; - break; - case X86_INS_RET: - stats_data_arch->num_ret++; - break; - default: - stats_collect_rip_relative_arch(instr); - break; - - } - -} - -#endif - diff --git a/frida_mode/src/stats/stats_x86.c b/frida_mode/src/stats/stats_x86.c deleted file mode 100644 index d9c4f652..00000000 --- a/frida_mode/src/stats/stats_x86.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "frida-gumjs.h" - -#include "debug.h" - -#include "stats.h" -#include "util.h" - -#if defined(__i386__) - -gboolean stats_is_supported_arch(void) { - - return FALSE; - -} - -size_t stats_data_size_arch(void) { - - FATAL("Stats not supported on this architecture"); - -} - -void stats_write_arch(void) { - - FATAL("Stats not supported on this architecture"); - -} - -void stats_collect_arch(const cs_insn *instr) { - - UNUSED_PARAMETER(instr); - FATAL("Stats not supported on this architecture"); - -} - -#endif - diff --git a/frida_mode/src/stats/stats_x86_64.c b/frida_mode/src/stats/stats_x86_64.c new file mode 100644 index 00000000..ab914951 --- /dev/null +++ b/frida_mode/src/stats/stats_x86_64.c @@ -0,0 +1,420 @@ +#include +#include + +#include "frida-gumjs.h" + +#include "debug.h" + +#include "ranges.h" +#include "stats.h" +#include "util.h" + +#define MICRO_TO_SEC 1000000 + +#if defined(__x86_64__) || defined(__i386__) + +typedef struct { + + guint64 num_blocks; + guint64 num_instructions; + + guint64 num_eob; + + guint64 num_call_imm; + guint64 num_call_imm_excluded; + guint64 num_call_reg; + guint64 num_call_mem; + + guint64 num_jmp_imm; + guint64 num_jmp_reg; + guint64 num_jmp_mem; + + guint64 num_jmp_cond_imm; + guint64 num_jmp_cond_reg; + guint64 num_jmp_cond_mem; + + guint64 num_jmp_cond_jcxz; + + guint64 num_ret; + + guint64 num_rip_relative; + + guint64 num_rip_relative_type[X86_INS_ENDING]; + char name_rip_relative_type[X86_INS_ENDING][CS_MNEMONIC_SIZE]; + +} stats_data_arch_t; + +static stats_data_arch_t *stats_data_arch = NULL; + +void starts_arch_init(void) { + + int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t), + IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + stats_data_arch = shmat(shm_id, NULL, 0); + g_assert(stats_data_arch != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(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(stats_data_arch, '\0', sizeof(stats_data_arch_t)); + +} + +static void stats_write_arch_stat(char *label, guint64 value, guint64 total) { + + stats_print("%-30s ", label); + stats_print("%10" G_GINT64_MODIFIER "u ", value); + if (total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)value * 100) / total); + + } + + stats_print("\n"); + +} + +static void stats_write_arch_stat_delta(char *label, guint64 prev_value, + guint64 curr_value, guint elapsed, + guint64 prev_total, + guint64 curr_total) { + + guint64 delta = curr_value - prev_value; + guint64 delta_total = curr_total - prev_total; + guint64 per_sec = delta / elapsed; + + stats_print("%-30s ", label); + + stats_print("%10" G_GINT64_MODIFIER "u ", curr_value); + if (curr_total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)curr_value * 100) / curr_total); + + } + + stats_print("%10" G_GINT64_MODIFIER "u ", delta); + if (delta_total == 0) { + + stats_print("(--.--%%), "); + + } else { + + stats_print("(%5.2f%%) ", ((float)delta * 100) / delta_total); + + } + + stats_print("[%10" G_GINT64_MODIFIER "u/s]", per_sec); + stats_print("\n"); + +} + +void stats_write_arch(stats_data_t *data) { + + guint elapsed = + (data->curr.stats_time - data->prev.stats_time) / MICRO_TO_SEC; + stats_print("%-30s %10s %19s\n", "Transitions", "cumulative", "delta"); + stats_print("%-30s %10s %19s\n", "-----------", "----------", "-----"); + stats_print( + "%-30s %10" G_GINT64_MODIFIER "u %-8s %10" G_GINT64_MODIFIER "u\n", + "total", data->curr.total, "", data->curr.total - data->prev.total); + stats_write_arch_stat_delta("call_imm", data->prev.call_imm, + data->curr.call_imm, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("call_reg", data->prev.call_reg, + data->curr.call_reg, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("call_mem", data->prev.call_mem, + data->curr.call_mem, elapsed, data->prev.total, + data->curr.total); + stats_write_arch_stat_delta("ret_slow_path", data->prev.ret_slow_path, + data->curr.ret_slow_path, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("post_call_invoke", data->prev.post_call_invoke, + data->curr.post_call_invoke, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("excluded_call_imm", data->prev.excluded_call_imm, + data->curr.excluded_call_imm, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_imm", data->prev.jmp_imm, data->curr.jmp_imm, + elapsed, data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_reg", data->prev.jmp_reg, data->curr.jmp_reg, + elapsed, data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_mem", data->prev.jmp_mem, data->curr.jmp_mem, + elapsed, data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_imm", data->prev.jmp_cond_imm, + data->curr.jmp_cond_imm, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_mem", data->prev.jmp_cond_mem, + data->curr.jmp_cond_mem, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_reg", data->prev.jmp_cond_reg, + data->curr.jmp_cond_reg, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_cond_jcxz", data->prev.jmp_cond_jcxz, + data->curr.jmp_cond_jcxz, elapsed, + data->prev.total, data->curr.total); + stats_write_arch_stat_delta("jmp_continuation", data->prev.jmp_continuation, + data->curr.jmp_continuation, elapsed, + data->prev.total, data->curr.total); + stats_print("\n"); + stats_print("\n"); + + stats_print("Instrumentation\n"); + stats_print("---------------\n"); + stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Instructions", + stats_data_arch->num_instructions); + stats_print("%-30s %10" G_GINT64_MODIFIER "u\n", "Blocks", + stats_data_arch->num_blocks); + + if (stats_data_arch->num_blocks != 0) { + + stats_print( + "%-30s %10" G_GINT64_MODIFIER "u\n", "Avg Instructions / Block ", + stats_data_arch->num_instructions / stats_data_arch->num_blocks); + + } + + stats_print("\n"); + stats_print("\n"); + + guint64 num_instructions = stats_data_arch->num_instructions; + + stats_print("EOB Instructions\n"); + stats_print("----------------\n"); + stats_write_arch_stat("Total", stats_data_arch->num_eob, num_instructions); + stats_write_arch_stat("Call Immediates", stats_data_arch->num_call_imm, + num_instructions); + stats_write_arch_stat("Call Immediates Excluded", + stats_data_arch->num_call_imm_excluded, + num_instructions); + stats_write_arch_stat("Call Register", stats_data_arch->num_call_reg, + num_instructions); + stats_write_arch_stat("Call Memory", stats_data_arch->num_call_mem, + num_instructions); + stats_write_arch_stat("Jump Immediates", stats_data_arch->num_jmp_imm, + num_instructions); + stats_write_arch_stat("Jump Register", stats_data_arch->num_jmp_reg, + num_instructions); + stats_write_arch_stat("Jump Memory", stats_data_arch->num_jmp_mem, + num_instructions); + stats_write_arch_stat("Conditional Jump Immediates", + stats_data_arch->num_jmp_cond_imm, num_instructions); + stats_write_arch_stat("Conditional Jump CX Immediate", + stats_data_arch->num_jmp_cond_jcxz, num_instructions); + stats_write_arch_stat("Conditional Jump Register", + stats_data_arch->num_jmp_cond_reg, num_instructions); + stats_write_arch_stat("Conditional Jump Memory", + stats_data_arch->num_jmp_cond_mem, num_instructions); + stats_write_arch_stat("Returns", stats_data_arch->num_ret, num_instructions); + stats_print("\n"); + stats_print("\n"); + + stats_print("Relocated Instructions\n"); + stats_print("----------------------\n"); + stats_write_arch_stat("Total", stats_data_arch->num_rip_relative, + num_instructions); + + for (size_t i = 0; i < X86_INS_ENDING; i++) { + + if (stats_data_arch->num_rip_relative_type[i] != 0) { + + stats_write_arch_stat(stats_data_arch->name_rip_relative_type[i], + stats_data_arch->num_rip_relative_type[i], + stats_data_arch->num_rip_relative); + + } + + } + + stats_print("\n"); + stats_print("\n"); + +} + +static x86_op_type stats_get_operand_type(const cs_insn *instr) { + + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op *operand; + + if (x86->op_count != 1) { + + FATAL("Unexpected operand count (%d): %s %s\n", x86->op_count, + instr->mnemonic, instr->op_str); + + } + + operand = &x86->operands[0]; + + return operand->type; + +} + +static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) { + + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op *operand = &x86->operands[0]; + + if (range_is_excluded(GUM_ADDRESS(operand->imm))) { + + stats_data_arch->num_call_imm_excluded++; + + } + +} + +static void stats_collect_call_arch(const cs_insn *instr) { + + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_call_imm++; + stats_collect_call_imm_excluded_arch(instr); + break; + case X86_OP_REG: + stats_data_arch->num_call_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_call_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_arch(const cs_insn *instr) { + + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_cond_arch(const cs_insn *instr) { + + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_cond_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_cond_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_cond_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_rip_relative_arch(const cs_insn *instr) { + + cs_x86 *x86 = &instr->detail->x86; + guint mod; + guint rm; + + if (x86->encoding.modrm_offset == 0) { return; } + + mod = (x86->modrm & 0xc0) >> 6; + if (mod != 0) { return; } + + rm = (x86->modrm & 0x07) >> 0; + if (rm != 5) { return; } + + stats_data_arch->num_rip_relative++; + stats_data_arch->num_rip_relative_type[instr->id]++; + memcpy(stats_data_arch->name_rip_relative_type[instr->id], instr->mnemonic, + CS_MNEMONIC_SIZE); + +} + +void stats_collect_arch(const cs_insn *instr, gboolean begin) { + + if (stats_data_arch == NULL) { return; } + if (begin) { stats_data_arch->num_blocks++; } + stats_data_arch->num_instructions++; + + switch (instr->id) { + + case X86_INS_CALL: + stats_collect_call_arch(instr); + stats_data_arch->num_eob++; + break; + case X86_INS_JMP: + stats_collect_jump_arch(instr); + stats_data_arch->num_eob++; + break; + case X86_INS_JA: + case X86_INS_JAE: + case X86_INS_JB: + case X86_INS_JBE: + case X86_INS_JE: + case X86_INS_JG: + case X86_INS_JGE: + case X86_INS_JL: + case X86_INS_JLE: + case X86_INS_JNE: + case X86_INS_JNO: + case X86_INS_JNP: + case X86_INS_JNS: + case X86_INS_JO: + case X86_INS_JP: + case X86_INS_JS: + stats_collect_jump_cond_arch(instr); + stats_data_arch->num_eob++; + break; + case X86_INS_JECXZ: + case X86_INS_JRCXZ: + stats_data_arch->num_jmp_cond_jcxz++; + stats_data_arch->num_eob++; + break; + case X86_INS_RET: + stats_data_arch->num_ret++; + stats_data_arch->num_eob++; + break; + default: + stats_collect_rip_relative_arch(instr); + break; + + } + +} + +#endif + diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile index 4c71bb33..bcaff42d 100644 --- a/frida_mode/test/cmplog/GNUmakefile +++ b/frida_mode/test/cmplog/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../../)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TEST_CMPLOG_SRC=$(PWD)cmplog.c diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile index f7520051..22aeb2bf 100644 --- a/frida_mode/test/deferred/GNUmakefile +++ b/frida_mode/test/deferred/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile index 5453c1ad..08c660f7 100644 --- a/frida_mode/test/entry_point/GNUmakefile +++ b/frida_mode/test/entry_point/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/exe/GNUmakefile b/frida_mode/test/exe/GNUmakefile index 86e5a461..c86ae894 100644 --- a/frida_mode/test/exe/GNUmakefile +++ b/frida_mode/test/exe/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile index c971c724..e150a6db 100644 --- a/frida_mode/test/fasan/GNUmakefile +++ b/frida_mode/test/fasan/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TEST_DATA_DIR:=$(BUILD_DIR)in/ diff --git a/frida_mode/test/jpeg/GNUmakefile b/frida_mode/test/jpeg/GNUmakefile index 1c124743..ca5101cb 100644 --- a/frida_mode/test/jpeg/GNUmakefile +++ b/frida_mode/test/jpeg/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so diff --git a/frida_mode/test/js/GNUmakefile b/frida_mode/test/js/GNUmakefile index ee8d4ebc..aad81d08 100644 --- a/frida_mode/test/js/GNUmakefile +++ b/frida_mode/test/js/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TEST_DATA_DIR:=$(BUILD_DIR)in/ TEST_DATA_FILE:=$(TEST_DATA_DIR)in diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile index 1263ce60..6f2b58af 100644 --- a/frida_mode/test/libpcap/GNUmakefile +++ b/frida_mode/test/libpcap/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so @@ -142,7 +142,7 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) ########## DUMMY ####### $(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ ###### TEST DATA ####### diff --git a/frida_mode/test/osx-lib/GNUmakefile b/frida_mode/test/osx-lib/GNUmakefile index de0af27b..96dbb5ad 100644 --- a/frida_mode/test/osx-lib/GNUmakefile +++ b/frida_mode/test/osx-lib/GNUmakefile @@ -52,7 +52,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "$$FA$$" > $@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ $(HARNESS_BIN): $(HARNESS_SRC) | $(BUILD_DIR) $(CC) $(CFLAGS) $(LDFLAGS) $(HARNESS_LDFLAGS) -o $@ $< diff --git a/frida_mode/test/output/GNUmakefile b/frida_mode/test/output/GNUmakefile index eaa1c4dc..201c23b7 100644 --- a/frida_mode/test/output/GNUmakefile +++ b/frida_mode/test/output/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index adcacf5a..71f6c693 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile index a1a7f1a5..0f591508 100644 --- a/frida_mode/test/png/GNUmakefile +++ b/frida_mode/test/png/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/ diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile index f6ccfcb5..c6526fee 100644 --- a/frida_mode/test/png/persistent/GNUmakefile +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -1,9 +1,9 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../../..)/ +ROOT:=$(PWD)../../../../ BUILD_DIR:=$(PWD)build/ TEST_BIN:=$(PWD)../build/test -TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ +TEST_DATA_DIR:=$(PWD)../build/libpng/libpng-1.2.56/contrib/pngsuite/ AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in QEMU_OUT:=$(BUILD_DIR)qemu-out @@ -49,7 +49,7 @@ $(BUILD_DIR): mkdir -p $@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ qemu: | $(BUILD_DIR) AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile index 049861dd..5010662b 100644 --- a/frida_mode/test/png/persistent/hook/GNUmakefile +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../../../..)/ +ROOT:=$(PWD)../../../../../ BUILD_DIR:=$(PWD)build/ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so @@ -72,7 +72,7 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) mkdir -p $@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) | $(BUILD_DIR) AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_QEMU_DRIVER_HOOK_OBJ) \ @@ -127,6 +127,21 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUIL -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) +frida_entry_slow: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_STALKER_IC_ENTRIES=2 \ + AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) | $(BUILD_DIR) AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=load.js \ diff --git a/frida_mode/test/proj4/GNUmakefile b/frida_mode/test/proj4/GNUmakefile index 8555ebad..7dffab2e 100644 --- a/frida_mode/test/proj4/GNUmakefile +++ b/frida_mode/test/proj4/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile index 8e1f3682..67b37a89 100644 --- a/frida_mode/test/re2/GNUmakefile +++ b/frida_mode/test/re2/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so @@ -124,7 +124,7 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) mkdir -p $@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ ###### TEST DATA ####### diff --git a/frida_mode/test/sqlite/GNUmakefile b/frida_mode/test/sqlite/GNUmakefile index 1c856d1e..85f213a9 100644 --- a/frida_mode/test/sqlite/GNUmakefile +++ b/frida_mode/test/sqlite/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ SQLITE_BUILD_DIR:=$(BUILD_DIR)sqlite/ @@ -120,7 +120,7 @@ sqlite: $(SQLITE_TEST_DIR) $(TEST_BIN) ########## DUMMY ####### $(AFLPP_DRIVER_DUMMY_INPUT): | $(SQLITE_TEST_DIR) - dd if=/dev/zero bs=1M count=1 of=$@ + dd if=/dev/zero bs=1048576 count=1 of=$@ ###### TEST DATA ####### @@ -156,6 +156,22 @@ frida: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) +frida_slow: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(SQLITE_TEST_DIR) + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_STALKER_IC_ENTRIES=2 \ + AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(SQLITE_TEST_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + debug: gdb \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile index 3701ddc8..79eee213 100644 --- a/frida_mode/test/testinstr/GNUmakefile +++ b/frida_mode/test/testinstr/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in diff --git a/frida_mode/test/unstable/GNUmakefile b/frida_mode/test/unstable/GNUmakefile index 938d7c17..c5fe1b88 100644 --- a/frida_mode/test/unstable/GNUmakefile +++ b/frida_mode/test/unstable/GNUmakefile @@ -1,5 +1,5 @@ PWD:=$(shell pwd)/ -ROOT:=$(shell realpath $(PWD)../../..)/ +ROOT:=$(PWD)../../../ BUILD_DIR:=$(PWD)build/ UNSTABLE_DATA_DIR:=$(BUILD_DIR)in/ UNSTABLE_DATA_FILE:=$(UNSTABLE_DATA_DIR)in diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index c1ed123e..d7f8b7bc 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -202,6 +202,13 @@ class Afl { Afl.jsApiSetPersistentReturn(address); } + /** + * See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. + */ + public static setPrefetchBackpatchDisable(): void { + Afl.jsApiSetPrefetchBackpatchDisable(); + } + /** * See `AFL_FRIDA_INST_NO_PREFETCH`. */ @@ -217,6 +224,13 @@ class Afl { Afl.jsApiSetStalkerCallback(callback); } + /** + * See `AFL_FRIDA_STALKER_IC_ENTRIES`. + */ + public static setStalkerIcEntries(val: number): void { + Afl.jsApiSetStalkerIcEntries(val); + } + /** * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as * an argument. @@ -234,13 +248,6 @@ class Afl { Afl.jsApiSetStatsInterval(interval); } - /** - * See `AFL_FRIDA_STATS_TRANSITIONS` - */ - public static setStatsTransitions(): void { - Afl.jsApiSetStatsTransitions(); - } - /** * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as * an argument. @@ -356,6 +363,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction( + "js_api_set_prefetch_backpatch_disable", + "void", + []); + private static readonly jsApiSetPrefetchDisable = Afl.jsApiGetFunction( "js_api_set_prefetch_disable", "void", @@ -366,6 +378,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetStalkerIcEntries = Afl.jsApiGetFunction( + "js_api_set_stalker_ic_entries", + "void", + ["uint32"]); + private static readonly jsApiSetStatsFile = Afl.jsApiGetFunction( "js_api_set_stats_file", "void", @@ -376,11 +393,6 @@ class Afl { "void", ["uint64"]); - private static readonly jsApiSetStatsTransitions = Afl.jsApiGetFunction( - "js_api_set_stats_transitions", - "void", - []); - private static readonly jsApiSetStdErr = Afl.jsApiGetFunction( "js_api_set_stderr", "void", diff --git a/include/envs.h b/include/envs.h index 722fe1a5..dd84748e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -60,6 +60,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", + "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH", "AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_SEED", "AFL_FRIDA_INST_TRACE", @@ -74,7 +75,6 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_PERSISTENT_RET", "AFL_FRIDA_STATS_FILE", "AFL_FRIDA_STATS_INTERVAL", - "AFL_FRIDA_STATS_TRANSITIONS", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", -- cgit 1.4.1 From 9e2a94532b7fd5191de905a8464176114ee7d258 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 23 Aug 2021 15:35:22 +0200 Subject: silenced warning in unicornafl rust bindings --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index da9641d5..253e4c8c 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -9064bca9ba +eef004c4 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 019b8715..eef004c4 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad +Subproject commit eef004c41f7eb53fd1f378ff9780f97a5fc45edc -- cgit 1.4.1 From e25f7cefdc796e2e52f53388492d476c52d3e251 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 25 Aug 2021 12:29:35 +0200 Subject: announce llvm 13 support --- GNUmakefile.llvm | 4 ++-- README.md | 2 +- docs/Changelog.md | 1 + instrumentation/README.llvm.md | 2 +- instrumentation/README.lto.md | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index a6f646f3..b802ef16 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 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") + $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 13) -> e.g. "pkg_add llvm-7.0.1p9") endif else LLVM_CONFIG ?= llvm-config @@ -46,7 +46,7 @@ LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's 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 '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 ) -LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 ) +LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[4-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 ) LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 ) diff --git a/README.md b/README.md index 19d3a866..1f1fd3b2 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ behaviours and defaults: ## Important features of AFL++ - AFL++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with QEMU 5.1 + AFL++ supports llvm from 3.8 up to version 13, 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. diff --git a/docs/Changelog.md b/docs/Changelog.md index 7ccae7c2..7d72b2df 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . information on how to deal with instrumenting libraries - afl-cc: - fix for shared linking on MacOS + - llvm and LTO mode verified to work with new llvm 14-dev - added the very good grammar mutator "GramaTron" to the custom_mutators - added optimin, a faster and better corpus minimizer by diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 2d428e6d..6e210a7c 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -6,7 +6,7 @@ ## 1) Introduction -! llvm_mode works with llvm versions 3.8 up to 12 ! +! llvm_mode works with llvm versions 3.8 up to 13 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md index 3e9d7585..6174cdc0 100644 --- a/instrumentation/README.lto.md +++ b/instrumentation/README.lto.md @@ -60,12 +60,12 @@ AUTODICTIONARY: 11 strings found ## Getting llvm 11+ -### Installing llvm version 11 +### Installing llvm version 11 or 12 -llvm 11 should be available in all current Linux repositories. +llvm 11 or even 12 should be available in all current Linux repositories. If you use an outdated Linux distribution read the next section. -### Installing llvm from the llvm repository (version 12) +### Installing llvm from the llvm repository (version 12+) Installing the llvm snapshot builds is easy and mostly painless: @@ -85,7 +85,7 @@ apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \ libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools ``` -### Building llvm yourself (version 12) +### Building llvm yourself (version 12+) Building llvm from github takes quite some long time and is not painless: ```sh -- cgit 1.4.1 From edda239131164945068d967acae813156a352898 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 25 Aug 2021 18:34:39 +0100 Subject: Fix issues with cmplog caused by coverage writing to STDIN --- frida_mode/src/instrument/instrument_coverage.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 4c0d1a14..b3323e1d 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -13,7 +13,7 @@ char *instrument_coverage_filename = NULL; static int coverage_fd = -1; -static int coverage_pipes[2] = {0}; +static int coverage_pipes[2] = {-1, -1}; static uint64_t coverage_last_start = 0; static GHashTable *coverage_hash = NULL; static GArray * coverage_modules = NULL; @@ -353,12 +353,16 @@ void instrument_coverage_init(void) { void instrument_coverage_start(uint64_t address) { + if (instrument_coverage_filename == NULL) { return; } + coverage_last_start = address; } void instrument_coverage_end(uint64_t address) { + if (instrument_coverage_filename == NULL) { return; } + coverage_data_t data = { .start = coverage_last_start, .end = address, .module = NULL}; -- cgit 1.4.1 From 4cdf4d2eaf9f81c37e99fd589858abf98d8be173 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 25 Aug 2021 18:34:39 +0100 Subject: Changes to fix coverage output --- frida_mode/frida.map | 1 + frida_mode/src/instrument/instrument_coverage.c | 69 +++++++++++++++++-------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 7ad5e682..288633ab 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -26,6 +26,7 @@ js_api_set_prefetch_backpatch_disable; js_api_set_prefetch_disable; js_api_set_stalker_callback; + js_api_set_stalker_ic_entries; js_api_set_stats_file; js_api_set_stats_interval; js_api_set_stderr; diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index b3323e1d..b4ba523c 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -27,7 +27,7 @@ typedef struct { gsize size; char name[PATH_MAX + 1]; char path[PATH_MAX + 1]; - bool referenced; + guint count; guint16 id; } coverage_module_t; @@ -62,7 +62,7 @@ static gboolean coverage_module(const GumModuleDetails *details, if (details->path != NULL) strncpy(coverage.path, details->path, PATH_MAX); - coverage.referenced = false; + coverage.count = 0; coverage.id = 0; g_array_append_val(coverage_modules, coverage); @@ -83,9 +83,25 @@ static gint coverage_sort(gconstpointer a, gconstpointer b) { } +void instrument_coverage_print(char *format, ...) { + + char buffer[4096] = {0}; + int len; + + va_list ap; + va_start(ap, format); + + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(STDOUT_FILENO, buffer, len)); + va_end(ap); + +} + static void coverage_get_ranges(void) { - OKF("Coverage - Collecting ranges"); + instrument_coverage_print("Coverage - Collecting ranges\n"); coverage_modules = g_array_sized_new(false, false, sizeof(coverage_module_t), 100); @@ -96,9 +112,10 @@ static void coverage_get_ranges(void) { coverage_module_t *module = &g_array_index(coverage_modules, coverage_module_t, i); - OKF("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER - "X - 0x%016" G_GINT64_MODIFIER "X", - i, module->base_address, module->limit); + instrument_coverage_print("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", + i, module->base_address, module->limit, + module->path); } @@ -121,13 +138,14 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { val->module = module; coverage_marked_entries++; - module->referenced = true; + module->count++; return; } - OKF("Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER - "X - 0x%016" G_GINT64_MODIFIER "X %u %u", + instrument_coverage_print( + "Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X %u %u\n", val->start, val->end, i, coverage_modules->len); } @@ -178,7 +196,7 @@ static void coverage_write_modules() { coverage_module_t *module = &g_array_index(coverage_modules, coverage_module_t, i); - if (!module->referenced) continue; + if (module->count == 0) continue; coverage_format("%3u, ", emitted); coverage_format("%016" G_GINT64_MODIFIER "X, ", module->base_address); @@ -201,6 +219,9 @@ static void coverage_write_events(void *key, void *value, void *user_data) { UNUSED_PARAMETER(key); UNUSED_PARAMETER(user_data); coverage_data_t *val = (coverage_data_t *)value; + + if (val->module == NULL) { return; } + coverage_event_t evt = { .offset = val->start - val->module->base_address, @@ -237,12 +258,13 @@ static void coverage_mark_modules() { coverage_module_t *module = &g_array_index(coverage_modules, coverage_module_t, i); - OKF("Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER - "X - 0x%016" G_GINT64_MODIFIER "X (%u:%s)", - i, module->referenced ? 'X' : ' ', module->base_address, module->limit, - module->id, module->path); + instrument_coverage_print( + "Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X [%u] (%u:%s)\n", + i, module->count == 0 ? ' ' : 'X', module->base_address, module->limit, + module->count, module->id, module->path); - if (!module->referenced) { continue; } + if (module->count == 0) { continue; } module->id = coverage_marked_modules; coverage_marked_modules++; @@ -256,7 +278,7 @@ static void instrument_coverage_run() { int bytes; coverage_data_t data; coverage_data_t *value; - OKF("Coverage - Running"); + instrument_coverage_print("Coverage - Running\n"); if (close(coverage_pipes[STDOUT_FILENO]) != 0) { @@ -278,22 +300,24 @@ static void instrument_coverage_run() { if (bytes != 0) { FATAL("Coverage data truncated"); } - OKF("Coverage - Preparing"); + instrument_coverage_print("Coverage - Preparing\n"); coverage_get_ranges(); guint size = g_hash_table_size(coverage_hash); - OKF("Coverage - Total Entries: %u", size); + instrument_coverage_print("Coverage - Total Entries: %u\n", size); g_hash_table_foreach(coverage_hash, instrument_coverage_mark, NULL); - OKF("Coverage - Marked Entries: %u", coverage_marked_entries); + instrument_coverage_print("Coverage - Marked Entries: %u\n", + coverage_marked_entries); coverage_mark_modules(); - OKF("Coverage - Marked Modules: %u", coverage_marked_modules); + instrument_coverage_print("Coverage - Marked Modules: %u\n", + coverage_marked_modules); coverage_write_header(); - OKF("Coverage - Completed"); + instrument_coverage_print("Coverage - Completed\n"); } @@ -339,10 +363,13 @@ void instrument_coverage_init(void) { if (pid == 0) { instrument_coverage_run(); + kill(getpid(), SIGKILL); _exit(0); } + if (close(coverage_fd) < 0) { FATAL("Failed to close coverage output file"); } + if (close(coverage_pipes[STDIN_FILENO]) != 0) { FATAL("Failed to close parent read pipe"); -- cgit 1.4.1 From 1a8819c9ad1b37b633a9fb9d558e3cf34cd0ecca Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 25 Aug 2021 18:34:39 +0100 Subject: Changes to how modules are identified for coverage --- frida_mode/src/instrument/instrument_coverage.c | 122 ++++++++++++++++++------ 1 file changed, 94 insertions(+), 28 deletions(-) diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index b4ba523c..495791c7 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -17,6 +17,7 @@ static int coverage_pipes[2] = {-1, -1}; static uint64_t coverage_last_start = 0; static GHashTable *coverage_hash = NULL; static GArray * coverage_modules = NULL; +static GArray * coverage_ranges = NULL; static guint coverage_marked_modules = 0; static guint coverage_marked_entries = 0; @@ -25,18 +26,19 @@ typedef struct { GumAddress base_address; GumAddress limit; gsize size; - char name[PATH_MAX + 1]; char path[PATH_MAX + 1]; + guint64 offset; + gboolean is_executable; guint count; guint16 id; -} coverage_module_t; +} coverage_range_t; typedef struct { - uint64_t start; - uint64_t end; - coverage_module_t *module; + uint64_t start; + uint64_t end; + coverage_range_t *module; } coverage_data_t; @@ -48,32 +50,44 @@ typedef struct { } coverage_event_t; -static gboolean coverage_module(const GumModuleDetails *details, - gpointer user_data) { +static gboolean coverage_range(const GumRangeDetails *details, + gpointer user_data) { UNUSED_PARAMETER(user_data); - coverage_module_t coverage = {0}; + coverage_range_t coverage = {0}; + + if (details->file == NULL) { return TRUE; } + if (details->protection == GUM_PAGE_NO_ACCESS) { return TRUE; } coverage.base_address = details->range->base_address; coverage.size = details->range->size; coverage.limit = coverage.base_address + coverage.size; - if (details->name != NULL) strncpy(coverage.name, details->name, PATH_MAX); + strncpy(coverage.path, details->file->path, PATH_MAX); + coverage.offset = details->file->offset; + + if ((details->protection & GUM_PAGE_EXECUTE) == 0) { + + coverage.is_executable = false; - if (details->path != NULL) strncpy(coverage.path, details->path, PATH_MAX); + } else { + + coverage.is_executable = true; + + } coverage.count = 0; coverage.id = 0; - g_array_append_val(coverage_modules, coverage); + g_array_append_val(coverage_ranges, coverage); return TRUE; } static gint coverage_sort(gconstpointer a, gconstpointer b) { - coverage_module_t *ma = (coverage_module_t *)a; - coverage_module_t *mb = (coverage_module_t *)b; + coverage_range_t *ma = (coverage_range_t *)a; + coverage_range_t *mb = (coverage_range_t *)b; if (ma->base_address < mb->base_address) return -1; @@ -99,19 +113,48 @@ void instrument_coverage_print(char *format, ...) { } -static void coverage_get_ranges(void) { +static void coverage_get_modules(void) { - instrument_coverage_print("Coverage - Collecting ranges\n"); + instrument_coverage_print("Coverage - Collecting modules\n"); coverage_modules = - g_array_sized_new(false, false, sizeof(coverage_module_t), 100); - gum_process_enumerate_modules(coverage_module, NULL); - g_array_sort(coverage_modules, coverage_sort); + g_array_sized_new(false, false, sizeof(coverage_range_t), 100); + + coverage_range_t current = {0}; + + for (guint i = 0; i < coverage_ranges->len; i++) { + + coverage_range_t *range = + &g_array_index(coverage_ranges, coverage_range_t, i); + + if (range->offset == 0 || + (strncmp(range->path, current.path, PATH_MAX) != 0)) { + + if (current.is_executable) { + + g_array_append_val(coverage_modules, current); + memset(¤t, '\0', sizeof(coverage_range_t)); + + } + + memcpy(¤t, range, sizeof(coverage_range_t)); + + } else { + + current.limit = range->limit; + current.size = current.limit - current.base_address; + if (range->is_executable) { current.is_executable = true; } + + } + + } + + if (current.is_executable) { g_array_append_val(coverage_modules, current); } for (guint i = 0; i < coverage_modules->len; i++) { - coverage_module_t *module = - &g_array_index(coverage_modules, coverage_module_t, i); + coverage_range_t *module = + &g_array_index(coverage_modules, coverage_range_t, i); instrument_coverage_print("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", i, module->base_address, module->limit, @@ -121,6 +164,28 @@ static void coverage_get_ranges(void) { } +static void coverage_get_ranges(void) { + + instrument_coverage_print("Coverage - Collecting ranges\n"); + + coverage_ranges = + g_array_sized_new(false, false, sizeof(coverage_range_t), 100); + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, coverage_range, NULL); + g_array_sort(coverage_ranges, coverage_sort); + + for (guint i = 0; i < coverage_ranges->len; i++) { + + coverage_range_t *range = + &g_array_index(coverage_ranges, coverage_range_t, i); + instrument_coverage_print("Coverage Range - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", + i, range->base_address, range->limit, + range->path); + + } + +} + static void instrument_coverage_mark(void *key, void *value, void *user_data) { UNUSED_PARAMETER(key); @@ -130,8 +195,8 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { for (i = 0; i < coverage_modules->len; i++) { - coverage_module_t *module = - &g_array_index(coverage_modules, coverage_module_t, i); + coverage_range_t *module = + &g_array_index(coverage_modules, coverage_range_t, i); if (val->start > module->limit) continue; if (val->end >= module->limit) break; @@ -145,8 +210,8 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { instrument_coverage_print( "Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER - "X - 0x%016" G_GINT64_MODIFIER "X %u %u\n", - val->start, val->end, i, coverage_modules->len); + "X - 0x%016" G_GINT64_MODIFIER "X\n", + val->start, val->end); } @@ -194,8 +259,8 @@ static void coverage_write_modules() { guint emitted = 0; for (guint i = 0; i < coverage_modules->len; i++) { - coverage_module_t *module = - &g_array_index(coverage_modules, coverage_module_t, i); + coverage_range_t *module = + &g_array_index(coverage_modules, coverage_range_t, i); if (module->count == 0) continue; coverage_format("%3u, ", emitted); @@ -255,8 +320,8 @@ static void coverage_mark_modules() { guint i; for (i = 0; i < coverage_modules->len; i++) { - coverage_module_t *module = - &g_array_index(coverage_modules, coverage_module_t, i); + coverage_range_t *module = + &g_array_index(coverage_modules, coverage_range_t, i); instrument_coverage_print( "Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER @@ -303,6 +368,7 @@ static void instrument_coverage_run() { instrument_coverage_print("Coverage - Preparing\n"); coverage_get_ranges(); + coverage_get_modules(); guint size = g_hash_table_size(coverage_hash); instrument_coverage_print("Coverage - Total Entries: %u\n", size); -- cgit 1.4.1 From e5f5d5886af5d3fad07c2e64945236258b3aca23 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 26 Aug 2021 18:06:41 +0100 Subject: Add unstable coverage support --- frida_mode/README.md | 3 + frida_mode/frida.map | 1 + frida_mode/include/instrument.h | 5 + frida_mode/src/instrument/instrument.c | 47 +- frida_mode/src/instrument/instrument_coverage.c | 588 ++++++++++++++++++++---- frida_mode/src/js/api.js | 9 + frida_mode/src/js/js_api.c | 7 + frida_mode/test/unstable/GNUmakefile | 15 + frida_mode/ts/lib/afl.ts | 14 + include/envs.h | 1 + 10 files changed, 603 insertions(+), 87 deletions(-) diff --git a/frida_mode/README.md b/frida_mode/README.md index 9f00c294..45d90ceb 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -175,6 +175,9 @@ useful for debugging purposes, e.g. investigating unstable edges. implies `AFL_FRIDA_INST_NO_OPTIMIZE`. * `AFL_FRIDA_INST_TRACE_UNIQUE` - As per `AFL_FRIDA_INST_TRACE`, but each edge is logged only once, requires `AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE` - File to write DynamoRio format +coverage information for unstable edges (e.g. to be loaded within IDA +lighthouse). * `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) * `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 288633ab..e753570f 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -18,6 +18,7 @@ js_api_set_instrument_seed; js_api_set_instrument_trace; js_api_set_instrument_trace_unique; + js_api_set_instrument_unstable_coverage_file; js_api_set_persistent_address; js_api_set_persistent_count; js_api_set_persistent_debug; diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 2e8d6b6d..909b2a2c 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -12,6 +12,7 @@ extern gboolean instrument_optimize; extern gboolean instrument_unique; extern __thread guint64 instrument_previous_pc; extern guint64 instrument_hash_zero; +extern char * instrument_coverage_unstable_filename; extern gboolean instrument_use_fixed_seed; extern guint64 instrument_fixed_seed; @@ -44,6 +45,10 @@ void instrument_coverage_init(void); void instrument_coverage_start(uint64_t address); void instrument_coverage_end(uint64_t address); +void instrument_coverage_unstable(guint64 edge, guint64 previous_rip, + guint64 previous_end, guint64 current_rip, + guint64 current_end); + void instrument_on_fork(); guint64 instrument_get_offset_hash(GumAddress current_rip); diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 9e4dd191..fd0982f8 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -29,14 +29,23 @@ guint64 instrument_hash_seed = 0; gboolean instrument_use_fixed_seed = FALSE; guint64 instrument_fixed_seed = 0; +char * instrument_coverage_unstable_filename = NULL; static GumStalkerTransformer *transformer = NULL; __thread guint64 instrument_previous_pc = 0; static GumAddress previous_rip = 0; +static GumAddress previous_end = 0; static u8 * edges_notified = NULL; +typedef struct { + + GumAddress address; + GumAddress end; + +} block_ctx_t; + static void trace_debug(char *format, ...) { va_list ap; @@ -91,9 +100,11 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, UNUSED_PARAMETER(context); - GumAddress current_rip = GUM_ADDRESS(user_data); - guint64 current_pc = instrument_get_offset_hash(current_rip); - guint64 edge; + block_ctx_t *ctx = (block_ctx_t *)user_data; + GumAddress current_rip = ctx->address; + guint16 current_end = ctx->end; + guint64 current_pc = instrument_get_offset_hash(current_rip); + guint64 edge; edge = current_pc ^ instrument_previous_pc; @@ -112,10 +123,18 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, if (instrument_unique) { edges_notified[edge] = 1; } - previous_rip = current_rip; + } + + if (unlikely(instrument_coverage_unstable_filename != NULL)) { + + instrument_coverage_unstable(edge, previous_rip, previous_end, current_rip, + current_end); } + previous_rip = current_rip; + previous_end = current_end; + instrument_previous_pc = ((current_pc & (MAP_SIZE - 1) >> 1)) | ((current_pc & 0x1) << (MAP_SIZE_POW2 - 1)); @@ -130,6 +149,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, const cs_insn *instr; gboolean begin = TRUE; gboolean excluded; + block_ctx_t * ctx = NULL; while (gum_stalker_iterator_next(iterator, &instr)) { @@ -183,8 +203,9 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } else { - gum_stalker_iterator_put_callout( - iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL); + ctx = gum_malloc0(sizeof(block_ctx_t)); + ctx->address = GUM_ADDRESS(instr->address); + gum_stalker_iterator_put_callout(iterator, on_basic_block, ctx, NULL); } @@ -211,6 +232,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } + if (ctx != NULL) { ctx->end = (instr->address + instr->size); } + instrument_flush(output); instrument_debug_end(output); instrument_coverage_end(instr->address + instr->size); @@ -224,6 +247,8 @@ void instrument_config(void) { instrument_unique = (getenv("AFL_FRIDA_INST_TRACE_UNIQUE") != NULL); instrument_use_fixed_seed = (getenv("AFL_FRIDA_INST_SEED") != NULL); instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED"); + instrument_coverage_unstable_filename = + (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE")); instrument_debug_config(); instrument_coverage_config(); @@ -241,6 +266,9 @@ void instrument_init(void) { OKF("Instrumentation - unique [%c]", instrument_unique ? 'X' : ' '); OKF("Instrumentation - fixed seed [%c] [0x%016" G_GINT64_MODIFIER "x]", instrument_use_fixed_seed ? 'X' : ' ', instrument_fixed_seed); + OKF("Instrumentation - unstable coverage [%c] [%s]", + instrument_coverage_unstable_filename == NULL ? ' ' : 'X', + instrument_coverage_unstable_filename); if (instrument_tracing && instrument_optimize) { @@ -249,6 +277,13 @@ void instrument_init(void) { } + if (instrument_coverage_unstable_filename && instrument_optimize) { + + WARNF("AFL_FRIDA_INST_COVERAGE_FILE implies AFL_FRIDA_INST_NO_OPTIMIZE"); + instrument_optimize = FALSE; + + } + if (instrument_unique && instrument_optimize) { WARNF("AFL_FRIDA_INST_TRACE_UNIQUE implies AFL_FRIDA_INST_NO_OPTIMIZE"); diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 495791c7..46c816bc 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -12,14 +12,14 @@ char *instrument_coverage_filename = NULL; -static int coverage_fd = -1; -static int coverage_pipes[2] = {-1, -1}; -static uint64_t coverage_last_start = 0; -static GHashTable *coverage_hash = NULL; -static GArray * coverage_modules = NULL; -static GArray * coverage_ranges = NULL; -static guint coverage_marked_modules = 0; -static guint coverage_marked_entries = 0; +static int normal_coverage_fd = -1; +static int normal_coverage_pipes[2] = {-1, -1}; + +static int unstable_coverage_fd = -1; +static int unstable_coverage_pipes[2] = {-1, -1}; + +static uint64_t normal_coverage_last_start = 0; +static gchar * unstable_coverage_fuzzer_stats = NULL; typedef struct { @@ -40,7 +40,24 @@ typedef struct { uint64_t end; coverage_range_t *module; -} coverage_data_t; +} normal_coverage_data_t; + +typedef struct { + + guint64 edge; + guint64 from; + guint64 from_end; + guint64 to; + guint64 to_end; + +} unstable_coverage_data_t; + +typedef struct { + + GArray *modules; + guint count; + +} coverage_mark_ctx_t; typedef struct { @@ -53,7 +70,7 @@ typedef struct { static gboolean coverage_range(const GumRangeDetails *details, gpointer user_data) { - UNUSED_PARAMETER(user_data); + GArray * coverage_ranges = (GArray *)user_data; coverage_range_t coverage = {0}; if (details->file == NULL) { return TRUE; } @@ -113,11 +130,36 @@ void instrument_coverage_print(char *format, ...) { } -static void coverage_get_modules(void) { +static GArray *coverage_get_ranges(void) { - instrument_coverage_print("Coverage - Collecting modules\n"); + instrument_coverage_print("Coverage - Collecting ranges\n"); - coverage_modules = + GArray *coverage_ranges = + g_array_sized_new(false, false, sizeof(coverage_range_t), 100); + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, coverage_range, + coverage_ranges); + g_array_sort(coverage_ranges, coverage_sort); + + for (guint i = 0; i < coverage_ranges->len; i++) { + + coverage_range_t *range = + &g_array_index(coverage_ranges, coverage_range_t, i); + instrument_coverage_print("Coverage Range - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", + i, range->base_address, range->limit, + range->path); + + } + + return coverage_ranges; + +} + +static GArray *coverage_get_modules(void) { + + instrument_coverage_print("Coverage - Collecting modules\n"); + GArray *coverage_ranges = coverage_get_ranges(); + GArray *coverage_modules = g_array_sized_new(false, false, sizeof(coverage_range_t), 100); coverage_range_t current = {0}; @@ -150,6 +192,7 @@ static void coverage_get_modules(void) { } if (current.is_executable) { g_array_append_val(coverage_modules, current); } + g_array_free(coverage_ranges, TRUE); for (guint i = 0; i < coverage_modules->len; i++) { @@ -162,36 +205,17 @@ static void coverage_get_modules(void) { } -} - -static void coverage_get_ranges(void) { - - instrument_coverage_print("Coverage - Collecting ranges\n"); - - coverage_ranges = - g_array_sized_new(false, false, sizeof(coverage_range_t), 100); - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, coverage_range, NULL); - g_array_sort(coverage_ranges, coverage_sort); - - for (guint i = 0; i < coverage_ranges->len; i++) { - - coverage_range_t *range = - &g_array_index(coverage_ranges, coverage_range_t, i); - instrument_coverage_print("Coverage Range - %3u: 0x%016" G_GINT64_MODIFIER - "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", - i, range->base_address, range->limit, - range->path); - - } + return coverage_modules; } static void instrument_coverage_mark(void *key, void *value, void *user_data) { UNUSED_PARAMETER(key); - UNUSED_PARAMETER(user_data); - coverage_data_t *val = (coverage_data_t *)value; - guint i; + coverage_mark_ctx_t * ctx = (coverage_mark_ctx_t *)user_data; + GArray * coverage_modules = ctx->modules; + normal_coverage_data_t *val = (normal_coverage_data_t *)value; + guint i; for (i = 0; i < coverage_modules->len; i++) { @@ -202,7 +226,7 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { if (val->end >= module->limit) break; val->module = module; - coverage_marked_entries++; + ctx->count = ctx->count + 1; module->count++; return; @@ -223,7 +247,7 @@ static void coverage_write(void *data, size_t size) { for (char *cursor = (char *)data; remain > 0; remain -= written, cursor += written) { - written = write(coverage_fd, cursor, remain); + written = write(normal_coverage_fd, cursor, remain); if (written < 0) { @@ -254,7 +278,7 @@ static void coverage_format(char *format, ...) { } -static void coverage_write_modules() { +static void coverage_write_modules(GArray *coverage_modules) { guint emitted = 0; for (guint i = 0; i < coverage_modules->len; i++) { @@ -283,7 +307,7 @@ static void coverage_write_events(void *key, void *value, void *user_data) { UNUSED_PARAMETER(key); UNUSED_PARAMETER(user_data); - coverage_data_t *val = (coverage_data_t *)value; + normal_coverage_data_t *val = (normal_coverage_data_t *)value; if (val->module == NULL) { return; } @@ -299,7 +323,7 @@ static void coverage_write_events(void *key, void *value, void *user_data) { } -static void coverage_write_header() { +static void coverage_write_header(guint coverage_marked_modules) { char version[] = "DRCOV VERSION: 2\n"; char flavour[] = "DRCOV FLAVOR: frida\n"; @@ -309,14 +333,12 @@ static void coverage_write_header() { coverage_format("Module Table: version 2, count %u\n", coverage_marked_modules); coverage_write(columns, sizeof(columns) - 1); - coverage_write_modules(); - coverage_format("BB Table: %u bbs\n", coverage_marked_entries); - g_hash_table_foreach(coverage_hash, coverage_write_events, NULL); } -static void coverage_mark_modules() { +static guint coverage_mark_modules(GArray *coverage_modules) { + guint coverage_marked_modules = 0; guint i; for (i = 0; i < coverage_modules->len; i++) { @@ -336,29 +358,40 @@ static void coverage_mark_modules() { } + return coverage_marked_modules; + } -static void instrument_coverage_run() { +static void instrument_coverage_normal_run() { - int bytes; - coverage_data_t data; - coverage_data_t *value; + int bytes; + normal_coverage_data_t data; + normal_coverage_data_t *value; instrument_coverage_print("Coverage - Running\n"); - if (close(coverage_pipes[STDOUT_FILENO]) != 0) { + if (close(normal_coverage_pipes[STDOUT_FILENO]) != 0) { FATAL("Failed to close parent read pipe"); } - for (bytes = - read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t)); - bytes == sizeof(coverage_data_t); - bytes = - read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t))) { + GHashTable *coverage_hash = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); + if (coverage_hash == NULL) { + + FATAL("Failed to g_hash_table_new, errno: %d", errno); + + } + + for (bytes = read(normal_coverage_pipes[STDIN_FILENO], &data, + sizeof(normal_coverage_data_t)); + bytes == sizeof(normal_coverage_data_t); + bytes = read(normal_coverage_pipes[STDIN_FILENO], &data, + sizeof(normal_coverage_data_t))) { - value = (coverage_data_t *)gum_malloc0(sizeof(coverage_data_t)); - memcpy(value, &data, sizeof(coverage_data_t)); + value = + (normal_coverage_data_t *)gum_malloc0(sizeof(normal_coverage_data_t)); + memcpy(value, &data, sizeof(normal_coverage_data_t)); g_hash_table_insert(coverage_hash, GSIZE_TO_POINTER(data.start), value); } @@ -367,21 +400,252 @@ static void instrument_coverage_run() { instrument_coverage_print("Coverage - Preparing\n"); - coverage_get_ranges(); - coverage_get_modules(); + GArray *coverage_modules = coverage_get_modules(); guint size = g_hash_table_size(coverage_hash); instrument_coverage_print("Coverage - Total Entries: %u\n", size); - g_hash_table_foreach(coverage_hash, instrument_coverage_mark, NULL); - instrument_coverage_print("Coverage - Marked Entries: %u\n", - coverage_marked_entries); + coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + + g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx); + instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); - coverage_mark_modules(); + guint coverage_marked_modules = coverage_mark_modules(coverage_modules); instrument_coverage_print("Coverage - Marked Modules: %u\n", coverage_marked_modules); - coverage_write_header(); + coverage_write_header(coverage_marked_modules); + coverage_write_modules(coverage_modules); + coverage_format("BB Table: %u bbs\n", ctx.count); + g_hash_table_foreach(coverage_hash, coverage_write_events, NULL); + + g_hash_table_unref(coverage_hash); + + instrument_coverage_print("Coverage - Completed\n"); + +} + +static GArray *instrument_coverage_unstable_read_unstable_ids(void) { + + gchar * contents = NULL; + gsize length = 0; + GArray *unstable_edge_ids = + g_array_sized_new(false, false, sizeof(gpointer), 100); + + if (!g_file_get_contents(unstable_coverage_fuzzer_stats, &contents, &length, + NULL)) { + + FATAL("Failed to read fuzzer_stats"); + + } + + instrument_coverage_print("\n"); + instrument_coverage_print("Unstable coverage stats:\n"); + instrument_coverage_print("========================\n"); + instrument_coverage_print("%s\n", contents); + instrument_coverage_print("\n"); + + gchar **lines = g_strsplit(contents, "\n", -1); + gchar **values = NULL; + + for (guint i = 0; lines[i] != NULL; i++) { + + gchar **fields = g_strsplit(lines[i], ":", 2); + if (fields[0] == NULL) { + + g_strfreev(fields); + continue; + + } + + g_strstrip(fields[0]); + if (g_strcmp0(fields[0], "var_bytes") != 0) { + + g_strfreev(fields); + continue; + + } + + if (fields[1] == NULL) { + + g_strfreev(fields); + continue; + + } + + g_strstrip(fields[1]); + values = g_strsplit(fields[1], " ", -1); + g_strfreev(fields); + + break; + + } + + if (values == NULL) { + + instrument_coverage_print( + "Failed to find var_bytes, did you set AFL_DEBUG?\n"); + + } + + for (guint i = 0; values[i] != NULL; i++) { + + g_strstrip(values[i]); + gpointer val = GSIZE_TO_POINTER(g_ascii_strtoull(values[i], NULL, 10)); + g_array_append_val(unstable_edge_ids, val); + + } + + g_strfreev(values); + g_strfreev(lines); + g_free(contents); + + for (guint i = 0; i < unstable_edge_ids->len; i++) { + + gpointer *id = &g_array_index(unstable_edge_ids, gpointer, i); + + instrument_coverage_print("Unstable edge (%10u): %" G_GINT64_MODIFIER "u\n", + i, GPOINTER_TO_SIZE(*id)); + + } + + return unstable_edge_ids; + +} + +static GHashTable *instrument_collect_unstable_blocks( + GHashTable *unstable_coverage_hash, GArray *unstable_edge_ids) { + + GHashTable *unstable_blocks = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); + + for (guint i = 0; i < unstable_edge_ids->len; i++) { + + gpointer *id = &g_array_index(unstable_edge_ids, gpointer, i); + + GHashTable *child = + (GHashTable *)g_hash_table_lookup(unstable_coverage_hash, *id); + + if (child == NULL) { FATAL("Failed to find edge ID"); } + + GHashTableIter iter = {0}; + gpointer value; + g_hash_table_iter_init(&iter, child); + while (g_hash_table_iter_next(&iter, NULL, &value)) { + + unstable_coverage_data_t *unstable = (unstable_coverage_data_t *)value; + normal_coverage_data_t * from = + gum_malloc0(sizeof(normal_coverage_data_t)); + normal_coverage_data_t *to = gum_malloc0(sizeof(normal_coverage_data_t)); + from->start = unstable->from; + from->end = unstable->from_end; + from->module = NULL; + + to->start = unstable->to; + to->end = unstable->to_end; + to->module = NULL; + + g_hash_table_insert(unstable_blocks, GSIZE_TO_POINTER(from->start), from); + g_hash_table_insert(unstable_blocks, GSIZE_TO_POINTER(to->start), to); + + } + + } + + return unstable_blocks; + +} + +static void instrument_coverage_unstable_run(void) { + + int bytes; + unstable_coverage_data_t data; + unstable_coverage_data_t *value; + instrument_coverage_print("Unstable coverage - Running\n"); + + if (close(unstable_coverage_pipes[STDOUT_FILENO]) != 0) { + + FATAL("Failed to close parent read pipe"); + + } + + GHashTable *unstable_coverage_hash = g_hash_table_new_full( + g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_unref); + if (unstable_coverage_hash == NULL) { + + FATAL("Failed to g_hash_table_new, errno: %d", errno); + + } + + guint edges = 0; + + for (bytes = read(unstable_coverage_pipes[STDIN_FILENO], &data, + sizeof(unstable_coverage_data_t)); + bytes == sizeof(unstable_coverage_data_t); + bytes = read(unstable_coverage_pipes[STDIN_FILENO], &data, + sizeof(unstable_coverage_data_t))) { + + value = (unstable_coverage_data_t *)gum_malloc0( + sizeof(unstable_coverage_data_t)); + memcpy(value, &data, sizeof(unstable_coverage_data_t)); + + gpointer hash_value = g_hash_table_lookup(unstable_coverage_hash, + GSIZE_TO_POINTER(value->edge)); + if (hash_value == NULL) { + + hash_value = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); + + if (!g_hash_table_insert(unstable_coverage_hash, + GSIZE_TO_POINTER(value->edge), hash_value)) { + + FATAL("Entry already in hashtable"); + + } + + } + + if (g_hash_table_insert(hash_value, GSIZE_TO_POINTER(value->from), value)) { + + edges++; + + } + + } + + if (bytes != 0) { FATAL("Unstable coverage data truncated"); } + + instrument_coverage_print("Coverage - Preparing\n"); + + GArray *coverage_modules = coverage_get_modules(); + + instrument_coverage_print("Found edges: %u\n", edges); + + GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids(); + + GHashTable *unstable_blocks = instrument_collect_unstable_blocks( + unstable_coverage_hash, unstable_edge_ids); + + guint size = g_hash_table_size(unstable_blocks); + instrument_coverage_print("Unstable blocks: %u\n", size); + + coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + + g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx); + instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); + + guint coverage_marked_modules = coverage_mark_modules(coverage_modules); + instrument_coverage_print("Coverage - Marked Modules: %u\n", + coverage_marked_modules); + + coverage_write_header(coverage_marked_modules); + coverage_write_modules(coverage_modules); + coverage_format("BB Table: %u bbs\n", ctx.count); + g_hash_table_foreach(unstable_blocks, coverage_write_events, NULL); + + g_hash_table_unref(unstable_blocks); + g_array_free(unstable_edge_ids, TRUE); + g_hash_table_unref(unstable_coverage_hash); instrument_coverage_print("Coverage - Completed\n"); @@ -393,7 +657,7 @@ void instrument_coverage_config(void) { } -void instrument_coverage_init(void) { +void instrument_coverage_normal_init(void) { OKF("Coverage - enabled [%c]", instrument_coverage_filename == NULL ? ' ' : 'X'); @@ -407,19 +671,147 @@ void instrument_coverage_init(void) { OKF("Coverage - path [%s]", path); - coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + normal_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (normal_coverage_fd < 0) { - if (coverage_fd < 0) { FATAL("Failed to open coverage file '%s'", path); } + FATAL("Failed to open coverage file '%s'", path); + + } g_free(path); - if (pipe(coverage_pipes) != 0) { FATAL("Failed to create pipes"); } + if (pipe(normal_coverage_pipes) != 0) { FATAL("Failed to create pipes"); } - coverage_hash = g_hash_table_new(g_direct_hash, g_direct_equal); - if (coverage_hash == NULL) { + pid_t pid = fork(); + if (pid == -1) { FATAL("Failed to start coverage process"); } - FATAL("Failed to g_hash_table_new, errno: %d", errno); + if (pid == 0) { + + instrument_coverage_normal_run(); + kill(getpid(), SIGKILL); + _exit(0); + + } + + if (close(normal_coverage_fd) < 0) { + + FATAL("Failed to close coverage output file"); + + } + + if (close(normal_coverage_pipes[STDIN_FILENO]) != 0) { + + FATAL("Failed to close parent read pipe"); + + } + +} + +void instrument_coverage_unstable_find_output(void) { + + pid_t parent = getpid(); + gchar *fds_name = g_strdup_printf("/proc/%d/fd/", getppid()); + + gchar *root = g_file_read_link("/proc/self/root", NULL); + if (root == NULL) { FATAL("Failed to read link"); } + + GDir *dir = g_dir_open(fds_name, 0, NULL); + + OKF("Coverage Unstable - fds: %s", fds_name); + + for (const gchar *filename = g_dir_read_name(dir); filename != NULL; + filename = g_dir_read_name(dir)) { + + gchar *fullname = g_build_path("/", fds_name, filename, NULL); + + gchar *link = g_file_read_link(fullname, NULL); + if (link == NULL) { FATAL("Failed to read link: %s", fullname); } + + gchar *basename = g_path_get_basename(link); + if (g_strcmp0(basename, "default") != 0) { + + g_free(basename); + g_free(link); + g_free(fullname); + continue; + + } + + gchar *relative = NULL; + size_t root_len = strnlen(root, PATH_MAX); + if (g_str_has_suffix(link, root)) { + + relative = g_build_path("/", &link[root_len], NULL); + + } else { + + relative = g_build_path("/", link, NULL); + + } + + gchar *cmdline = g_build_path("/", relative, "cmdline", NULL); + if (!g_file_test(cmdline, G_FILE_TEST_EXISTS)) { + + g_free(cmdline); + g_free(basename); + g_free(relative); + g_free(link); + g_free(fullname); + continue; + + } + + unstable_coverage_fuzzer_stats = + g_build_path("/", relative, "fuzzer_stats", NULL); + g_free(cmdline); + g_free(basename); + g_free(relative); + g_free(link); + g_free(fullname); + break; + + } + + g_dir_close(dir); + g_free(fds_name); + + if (unstable_coverage_fuzzer_stats == NULL) { + + FATAL("Failed to find fuzzer stats"); + + } + + OKF("Fuzzer stats: %s", unstable_coverage_fuzzer_stats); + +} + +void instrument_coverage_unstable_init(void) { + + if (instrument_coverage_unstable_filename == NULL) { return; } + + char *path = g_canonicalize_filename(instrument_coverage_unstable_filename, + g_get_current_dir()); + + OKF("Coverage - unstable path [%s]", instrument_coverage_unstable_filename); + + unstable_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (unstable_coverage_fd < 0) { + + FATAL("Failed to open unstable coverage file '%s'", path); + + } + + g_free(path); + + instrument_coverage_unstable_find_output(); + + if (pipe(unstable_coverage_pipes) != 0) { + + FATAL("Failed to create unstable pipes"); } @@ -428,15 +820,19 @@ void instrument_coverage_init(void) { if (pid == 0) { - instrument_coverage_run(); + instrument_coverage_unstable_run(); kill(getpid(), SIGKILL); _exit(0); } - if (close(coverage_fd) < 0) { FATAL("Failed to close coverage output file"); } + if (close(unstable_coverage_fd) < 0) { + + FATAL("Failed to close unstable coverage output file"); - if (close(coverage_pipes[STDIN_FILENO]) != 0) { + } + + if (close(unstable_coverage_pipes[STDIN_FILENO]) != 0) { FATAL("Failed to close parent read pipe"); @@ -444,11 +840,18 @@ void instrument_coverage_init(void) { } +void instrument_coverage_init(void) { + + instrument_coverage_normal_init(); + instrument_coverage_unstable_init(); + +} + void instrument_coverage_start(uint64_t address) { if (instrument_coverage_filename == NULL) { return; } - coverage_last_start = address; + normal_coverage_last_start = address; } @@ -456,12 +859,12 @@ void instrument_coverage_end(uint64_t address) { if (instrument_coverage_filename == NULL) { return; } - coverage_data_t data = { + normal_coverage_data_t data = { - .start = coverage_last_start, .end = address, .module = NULL}; + .start = normal_coverage_last_start, .end = address, .module = NULL}; - if (write(coverage_pipes[STDOUT_FILENO], &data, sizeof(coverage_data_t)) != - sizeof(coverage_data_t)) { + if (write(normal_coverage_pipes[STDOUT_FILENO], &data, + sizeof(normal_coverage_data_t)) != sizeof(normal_coverage_data_t)) { FATAL("Coverage I/O error"); @@ -469,3 +872,26 @@ void instrument_coverage_end(uint64_t address) { } +void instrument_coverage_unstable(guint64 edge, guint64 previous_rip, + guint64 previous_end, guint64 current_rip, + guint64 current_end) { + + if (instrument_coverage_unstable_filename == NULL) { return; } + unstable_coverage_data_t data = { + + .edge = edge, + .from = previous_rip, + .from_end = previous_end, + .to = current_rip, + .to_end = current_end}; + + if (write(unstable_coverage_pipes[STDOUT_FILENO], &data, + sizeof(unstable_coverage_data_t)) != + sizeof(unstable_coverage_data_t)) { + + FATAL("Unstable coverage I/O error"); + + } + +} + diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 71b5e4a4..cf422ba9 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -137,6 +137,14 @@ class Afl { static setInstrumentTracingUnique() { Afl.jsApiSetInstrumentTraceUnique(); } + /** + * See `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE`. This function takes a single + * `string` as an argument. + */ + static setInstrumentUnstableCoverageFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentUnstableCoverageFile(buf); + } /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * `NativePointer` should be provided as it's argument. @@ -255,6 +263,7 @@ Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_n Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]); Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []); Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []); +Afl.jsApiSetInstrumentUnstableCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_unstable_coverage_file", "void", ["pointer"]); Afl.jsApiSetPersistentAddress = Afl.jsApiGetFunction("js_api_set_persistent_address", "void", ["pointer"]); Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count", "void", ["uint64"]); Afl.jsApiSetPersistentDebug = Afl.jsApiGetFunction("js_api_set_persistent_debug", "void", []); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index c2746d13..49ca3baa 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -164,6 +164,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_trace_unique( } +__attribute__((visibility("default"))) void +js_api_set_instrument_unstable_coverage_file(char *path) { + + instrument_coverage_unstable_filename = g_strdup(path); + +} + __attribute__((visibility("default"))) void js_api_set_stdout(char *file) { output_stdout = g_strdup(file); diff --git a/frida_mode/test/unstable/GNUmakefile b/frida_mode/test/unstable/GNUmakefile index c5fe1b88..0ccc5fb1 100644 --- a/frida_mode/test/unstable/GNUmakefile +++ b/frida_mode/test/unstable/GNUmakefile @@ -85,6 +85,21 @@ frida: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) -- \ $(UNSTABLE_BIN) @@ +frida_coverage: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) + AFL_DEBUG=1 \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_OUTPUT_STDOUT=/tmp/stdout.txt \ + AFL_FRIDA_OUTPUT_STDERR=/tmp/stderr.txt \ + AFL_FRIDA_INST_COVERAGE_FILE=/tmp/coverage.dat \ + AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE=/tmp/unstable.dat \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(UNSTABLE_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(UNSTABLE_BIN) @@ + debug: gdb \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index d7f8b7bc..c722f558 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -163,6 +163,15 @@ class Afl { Afl.jsApiSetInstrumentTraceUnique(); } + /** + * See `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE`. This function takes a single + * `string` as an argument. + */ + public static setInstrumentUnstableCoverageFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentUnstableCoverageFile(buf); + } + /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * `NativePointer` should be provided as it's argument. @@ -338,6 +347,11 @@ class Afl { "void", []); + private static readonly jsApiSetInstrumentUnstableCoverageFile = Afl.jsApiGetFunction( + "js_api_set_instrument_unstable_coverage_file", + "void", + ["pointer"]); + private static readonly jsApiSetPersistentAddress = Afl.jsApiGetFunction( "js_api_set_persistent_address", "void", diff --git a/include/envs.h b/include/envs.h index dd84748e..e3957147 100644 --- a/include/envs.h +++ b/include/envs.h @@ -65,6 +65,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_SEED", "AFL_FRIDA_INST_TRACE", "AFL_FRIDA_INST_TRACE_UNIQUE", + "AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE", "AFL_FRIDA_JS_SCRIPT", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR", -- cgit 1.4.1 From 31e34c1634e5b5bf43c6c1a8451557fe48da2771 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 26 Aug 2021 19:40:09 +0200 Subject: updated unicornafl --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 253e4c8c..0db54339 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -eef004c4 +c0e03d2c diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index eef004c4..c0e03d2c 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit eef004c41f7eb53fd1f378ff9780f97a5fc45edc +Subproject commit c0e03d2c6b55a22025324f121746b41b1e756fb8 -- cgit 1.4.1 From ca28ca6c059700d9f858f6effb33390ca16bf477 Mon Sep 17 00:00:00 2001 From: DC Date: Fri, 27 Aug 2021 14:50:44 +0100 Subject: Network client linkage fix for solarisish systems. --- utils/afl_network_proxy/GNUmakefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/afl_network_proxy/GNUmakefile b/utils/afl_network_proxy/GNUmakefile index 0b55dc2c..7c8c22ff 100644 --- a/utils/afl_network_proxy/GNUmakefile +++ b/utils/afl_network_proxy/GNUmakefile @@ -3,6 +3,8 @@ BIN_PATH = $(PREFIX)/bin HELPER_PATH = $(PREFIX)/lib/afl DOC_PATH = $(PREFIX)/share/doc/afl +SYS = $(shell uname -s) + PROGRAMS = afl-network-client afl-network-server HASH=\# @@ -13,6 +15,10 @@ ifdef STATIC CFLAGS += -static endif +ifeq "$(SYS)" "SunOS" + LDFLAGS += -lnsl -lsocket +endif + ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" CFLAGS += -DUSE_DEFLATE=1 LDFLAGS += -ldeflate -- cgit 1.4.1 From 5559dd9c244848a1dbb19981f0295774f4e176d9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 27 Aug 2021 18:38:22 +0100 Subject: Added seccomp support --- frida_mode/README.md | 2 + frida_mode/frida.map | 1 + frida_mode/include/seccomp.h | 359 +++++++++++++++++++++++++++++++ frida_mode/src/entry.c | 2 + frida_mode/src/js/api.js | 9 + frida_mode/src/js/js_api.c | 8 + frida_mode/src/main.c | 3 + frida_mode/src/seccomp/seccomp.c | 157 ++++++++++++++ frida_mode/src/seccomp/seccomp_atomic.c | 28 +++ frida_mode/src/seccomp/seccomp_child.c | 69 ++++++ frida_mode/src/seccomp/seccomp_event.c | 45 ++++ frida_mode/src/seccomp/seccomp_filter.c | 258 ++++++++++++++++++++++ frida_mode/src/seccomp/seccomp_socket.c | 121 +++++++++++ frida_mode/src/seccomp/seccomp_syscall.c | 335 ++++++++++++++++++++++++++++ frida_mode/ts/lib/afl.ts | 14 ++ 15 files changed, 1411 insertions(+) create mode 100644 frida_mode/include/seccomp.h create mode 100644 frida_mode/src/seccomp/seccomp.c create mode 100644 frida_mode/src/seccomp/seccomp_atomic.c create mode 100644 frida_mode/src/seccomp/seccomp_child.c create mode 100644 frida_mode/src/seccomp/seccomp_event.c create mode 100644 frida_mode/src/seccomp/seccomp_filter.c create mode 100644 frida_mode/src/seccomp/seccomp_socket.c create mode 100644 frida_mode/src/seccomp/seccomp_syscall.c diff --git a/frida_mode/README.md b/frida_mode/README.md index 45d90ceb..165f8089 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -197,6 +197,8 @@ gdb \ --args [my arguments] ``` +* `AFL_FRIDA_SECCOMP_FILE` - Write a log of any syscalls made by the target to +the specified file. * `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries stored along-side branch instructions which provide a cache to avoid having to call back into FRIDA to find the next block. Default is 32. diff --git a/frida_mode/frida.map b/frida_mode/frida.map index e753570f..0fc48aa6 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -26,6 +26,7 @@ js_api_set_persistent_return; js_api_set_prefetch_backpatch_disable; js_api_set_prefetch_disable; + js_api_set_seccomp_file; js_api_set_stalker_callback; js_api_set_stalker_ic_entries; js_api_set_stats_file; diff --git a/frida_mode/include/seccomp.h b/frida_mode/include/seccomp.h new file mode 100644 index 00000000..2c037ff7 --- /dev/null +++ b/frida_mode/include/seccomp.h @@ -0,0 +1,359 @@ +#ifndef _SECCOMP_H +#define _SECCOMP_H + +#include + +#include "frida-gumjs.h" + +#define SECCOMP_SOCKET_SEND_FD 0x1D3 +#define SECCOMP_SOCKET_RECV_FD 0x1D4 + +#define SECCOMP_OUTPUT_FILE_FD 0x1D5 +#define SECCOMP_PARENT_EVENT_FD 0x1D6 + +enum { + + SYS_READ = 0, + SYS_WRITE = 1, + SYS_OPEN = 2, + SYS_CLOSE = 3, + SYS_STAT = 4, + SYS_FSTAT = 5, + SYS_LSTAT = 6, + SYS_POLL = 7, + SYS_LSEEK = 8, + SYS_MMAP = 9, + SYS_MPROTECT = 10, + SYS_MUNMAP = 11, + SYS_BRK = 12, + SYS_RT_SIGACTION = 13, + SYS_RT_SIGPROCMASK = 14, + SYS_RT_SIGRETURN = 15, + SYS_IOCTL = 16, + SYS_PREAD64 = 17, + SYS_PWRITE64 = 18, + SYS_READV = 19, + SYS_WRITEV = 20, + SYS_ACCESS = 21, + SYS_PIPE = 22, + SYS_SELECT = 23, + SYS_SCHED_YIELD = 24, + SYS_MREMAP = 25, + SYS_MSYNC = 26, + SYS_MINCORE = 27, + SYS_MADVISE = 28, + SYS_SHMGET = 29, + SYS_SHMAT = 30, + SYS_SHMCTL = 31, + SYS_DUP = 32, + SYS_DUP2 = 33, + SYS_PAUSE = 34, + SYS_NANOSLEEP = 35, + SYS_GETITIMER = 36, + SYS_ALARM = 37, + SYS_SETITIMER = 38, + SYS_GETPID = 39, + SYS_SENDFILE = 40, + SYS_SOCKET = 41, + SYS_CONNECT = 42, + SYS_ACCEPT = 43, + SYS_SENDTO = 44, + SYS_RECVFROM = 45, + SYS_SENDMSG = 46, + SYS_RECVMSG = 47, + SYS_SHUTDOWN = 48, + SYS_BIND = 49, + SYS_LISTEN = 50, + SYS_GETSOCKNAME = 51, + SYS_GETPEERNAME = 52, + SYS_SOCKETPAIR = 53, + SYS_SETSOCKOPT = 54, + SYS_GETSOCKOPT = 55, + SYS_CLONE = 56, + SYS_FORK = 57, + SYS_VFORK = 58, + SYS_EXECVE = 59, + SYS_EXIT = 60, + SYS_WAIT4 = 61, + SYS_KILL = 62, + SYS_UNAME = 63, + SYS_SEMGET = 64, + SYS_SEMOP = 65, + SYS_SEMCTL = 66, + SYS_SHMDT = 67, + SYS_MSGGET = 68, + SYS_MSGSND = 69, + SYS_MSGRCV = 70, + SYS_MSGCTL = 71, + SYS_FCNTL = 72, + SYS_FLOCK = 73, + SYS_FSYNC = 74, + SYS_FDATASYNC = 75, + SYS_TRUNCATE = 76, + SYS_FTRUNCATE = 77, + SYS_GETDENTS = 78, + SYS_GETCWD = 79, + SYS_CHDIR = 80, + SYS_FCHDIR = 81, + SYS_RENAME = 82, + SYS_MKDIR = 83, + SYS_RMDIR = 84, + SYS_CREAT = 85, + SYS_LINK = 86, + SYS_UNLINK = 87, + SYS_SYMLINK = 88, + SYS_READLINK = 89, + SYS_CHMOD = 90, + SYS_FCHMOD = 91, + SYS_CHOWN = 92, + SYS_FCHOWN = 93, + SYS_LCHOWN = 94, + SYS_UMASK = 95, + SYS_GETTIMEOFDAY = 96, + SYS_GETRLIMIT = 97, + SYS_GETRUSAGE = 98, + SYS_SYSINFO = 99, + SYS_TIMES = 100, + SYS_PTRACE = 101, + SYS_GETUID = 102, + SYS_SYSLOG = 103, + SYS_GETGID = 104, + SYS_SETUID = 105, + SYS_SETGID = 106, + SYS_GETEUID = 107, + SYS_GETEGID = 108, + SYS_SETPGID = 109, + SYS_GETPPID = 110, + SYS_GETPGRP = 111, + SYS_SETSID = 112, + SYS_SETREUID = 113, + SYS_SETREGID = 114, + SYS_GETGROUPS = 115, + SYS_SETGROUPS = 116, + SYS_SETRESUID = 117, + SYS_GETRESUID = 118, + SYS_SETRESGID = 119, + SYS_GETRESGID = 120, + SYS_GETPGID = 121, + SYS_SETFSUID = 122, + SYS_SETFSGID = 123, + SYS_GETSID = 124, + SYS_CAPGET = 125, + SYS_CAPSET = 126, + SYS_RT_SIGPENDING = 127, + SYS_RT_SIGTIMEDWAIT = 128, + SYS_RT_SIGQUEUEINFO = 129, + SYS_RT_SIGSUSPEND = 130, + SYS_SIGALTSTACK = 131, + SYS_UTIME = 132, + SYS_MKNOD = 133, + SYS_USELIB = 134, + SYS_PERSONALITY = 135, + SYS_USTAT = 136, + SYS_STATFS = 137, + SYS_FSTATFS = 138, + SYS_SYSFS = 139, + SYS_GETPRIORITY = 140, + SYS_SETPRIORITY = 141, + SYS_SCHED_SETPARAM = 142, + SYS_SCHED_GETPARAM = 143, + SYS_SCHED_SETSCHEDULER = 144, + SYS_SCHED_GETSCHEDULER = 145, + SYS_SCHED_GET_PRIORITY_MAX = 146, + SYS_SCHED_GET_PRIORITY_MIN = 147, + SYS_SCHED_RR_GET_INTERVAL = 148, + SYS_MLOCK = 149, + SYS_MUNLOCK = 150, + SYS_MLOCKALL = 151, + SYS_MUNLOCKALL = 152, + SYS_VHANGUP = 153, + SYS_MODIFY_LDT = 154, + SYS_PIVOT_ROOT = 155, + SYS__SYSCTL = 156, + SYS_PRCTL = 157, + SYS_ARCH_PRCTL = 158, + SYS_ADJTIMEX = 159, + SYS_SETRLIMIT = 160, + SYS_CHROOT = 161, + SYS_SYNC = 162, + SYS_ACCT = 163, + SYS_SETTIMEOFDAY = 164, + SYS_MOUNT = 165, + SYS_UMOUNT2 = 166, + SYS_SWAPON = 167, + SYS_SWAPOFF = 168, + SYS_REBOOT = 169, + SYS_SETHOSTNAME = 170, + SYS_SETDOMAINNAME = 171, + SYS_IOPL = 172, + SYS_IOPERM = 173, + SYS_CREATE_MODULE = 174, + SYS_INIT_MODULE = 175, + SYS_DELETE_MODULE = 176, + SYS_GET_KERNEL_SYMS = 177, + SYS_QUERY_MODULE = 178, + SYS_QUOTACTL = 179, + SYS_NFSSERVCTL = 180, + SYS_GETPMSG = 181, + SYS_PUTPMSG = 182, + SYS_AFS_SYSCALL = 183, + SYS_TUXCALL = 184, + SYS_SECURITY = 185, + SYS_GETTID = 186, + SYS_READAHEAD = 187, + SYS_SETXATTR = 188, + SYS_LSETXATTR = 189, + SYS_FSETXATTR = 190, + SYS_GETXATTR = 191, + SYS_LGETXATTR = 192, + SYS_FGETXATTR = 193, + SYS_LISTXATTR = 194, + SYS_LLISTXATTR = 195, + SYS_FLISTXATTR = 196, + SYS_REMOVEXATTR = 197, + SYS_LREMOVEXATTR = 198, + SYS_FREMOVEXATTR = 199, + SYS_TKILL = 200, + SYS_TIME = 201, + SYS_FUTEX = 202, + SYS_SCHED_SETAFFINITY = 203, + SYS_SCHED_GETAFFINITY = 204, + SYS_SET_THREAD_AREA = 205, + SYS_IO_SETUP = 206, + SYS_IO_DESTROY = 207, + SYS_IO_GETEVENTS = 208, + SYS_IO_SUBMIT = 209, + SYS_IO_CANCEL = 210, + SYS_GET_THREAD_AREA = 211, + SYS_LOOKUP_DCOOKIE = 212, + SYS_EPOLL_CREATE = 213, + SYS_EPOLL_CTL_OLD = 214, + SYS_EPOLL_WAIT_OLD = 215, + SYS_REMAP_FILE_PAGES = 216, + SYS_GETDENTS64 = 217, + SYS_SET_TID_ADDRESS = 218, + SYS_RESTART_SYSCALL = 219, + SYS_SEMTIMEDOP = 220, + SYS_FADVISE64 = 221, + SYS_TIMER_CREATE = 222, + SYS_TIMER_SETTIME = 223, + SYS_TIMER_GETTIME = 224, + SYS_TIMER_GETOVERRUN = 225, + SYS_TIMER_DELETE = 226, + SYS_CLOCK_SETTIME = 227, + SYS_CLOCK_GETTIME = 228, + SYS_CLOCK_GETRES = 229, + SYS_CLOCK_NANOSLEEP = 230, + SYS_EXIT_GROUP = 231, + SYS_EPOLL_WAIT = 232, + SYS_EPOLL_CTL = 233, + SYS_TGKILL = 234, + SYS_UTIMES = 235, + SYS_VSERVER = 236, + SYS_MBIND = 237, + SYS_SET_MEMPOLICY = 238, + SYS_GET_MEMPOLICY = 239, + SYS_MQ_OPEN = 240, + SYS_MQ_UNLINK = 241, + SYS_MQ_TIMEDSEND = 242, + SYS_MQ_TIMEDRECEIVE = 243, + SYS_MQ_NOTIFY = 244, + SYS_MQ_GETSETATTR = 245, + SYS_KEXEC_LOAD = 246, + SYS_WAITID = 247, + SYS_ADD_KEY = 248, + SYS_REQUEST_KEY = 249, + SYS_KEYCTL = 250, + SYS_IOPRIO_SET = 251, + SYS_IOPRIO_GET = 252, + SYS_INOTIFY_INIT = 253, + SYS_INOTIFY_ADD_WATCH = 254, + SYS_INOTIFY_RM_WATCH = 255, + SYS_MIGRATE_PAGES = 256, + SYS_OPENAT = 257, + SYS_MKDIRAT = 258, + SYS_MKNODAT = 259, + SYS_FCHOWNAT = 260, + SYS_FUTIMESAT = 261, + SYS_NEWFSTATAT = 262, + SYS_UNLINKAT = 263, + SYS_RENAMEAT = 264, + SYS_LINKAT = 265, + SYS_SYMLINKAT = 266, + SYS_READLINKAT = 267, + SYS_FCHMODAT = 268, + SYS_FACCESSAT = 269, + SYS_PSELECT6 = 270, + SYS_PPOLL = 271, + SYS_UNSHARE = 272, + SYS_SET_ROBUST_LIST = 273, + SYS_GET_ROBUST_LIST = 274, + SYS_SPLICE = 275, + SYS_TEE = 276, + SYS_SYNC_FILE_RANGE = 277, + SYS_VMSPLICE = 278, + SYS_MOVE_PAGES = 279, + SYS_UTIMENSAT = 280, + SYS_EPOLL_PWAIT = 281, + SYS_SIGNALFD = 282, + SYS_TIMERFD_CREATE = 283, + SYS_EVENTFD = 284, + SYS_FALLOCATE = 285, + SYS_TIMERFD_SETTIME = 286, + SYS_TIMERFD_GETTIME = 287, + SYS_ACCEPT4 = 288, + SYS_SIGNALFD4 = 289, + SYS_EVENTFD2 = 290, + SYS_EPOLL_CREATE1 = 291, + SYS_DUP3 = 292, + SYS_PIPE2 = 293, + SYS_INOTIFY_INIT1 = 294, + SYS_PREADV = 295, + SYS_PWRITEV = 296, + SYS_RT_TGSIGQUEUEINFO = 297, + SYS_PERF_EVENT_OPEN = 298, + SYS_RECVMMSG = 299, + SYS_FANOTIFY_INIT = 300, + SYS_FANOTIFY_MARK = 301, + SYS_PRLIMIT64 = 302 + +}; + +extern char *seccomp_filename; + +typedef void (*seccomp_child_func_t)(int event_fd, void *ctx); + +typedef void (*seccomp_filter_callback_t)(struct seccomp_notif * req, + struct seccomp_notif_resp *resp, + GumReturnAddressArray * frames); + +void seccomp_config(void); +void seccomp_init(void); +void seccomp_on_fork(void); +void seccomp_print(char *format, ...); + +void seccomp_atomic_set(volatile bool *ptr, bool val); +bool seccomp_atomic_try_set(volatile bool *ptr, bool val); +void seccomp_atomic_wait(volatile bool *ptr, bool val); + +void seccomp_child_run(seccomp_child_func_t child_func, void *ctx, pid_t *child, + int *event_fd); +void seccomp_child_wait(int event_fd); + +int seccomp_event_create(void); +void seccomp_event_signal(int fd); +void seccomp_event_wait(int fd); +void seccomp_event_destroy(int fd); + +int seccomp_filter_install(pid_t child); +void seccomp_filter_child_install(void); +void seccomp_filter_run(int fd, seccomp_filter_callback_t callback); + +void seccomp_socket_create(int *sock); +void seccomp_socket_send(int sockfd, int fd); +int seccomp_socket_recv(int sockfd); + +char *seccomp_syscall_lookup(int id); + +#endif + diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index 3ec8f5be..186ddd3a 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -8,6 +8,7 @@ #include "instrument.h" #include "persistent.h" #include "ranges.h" +#include "seccomp.h" #include "stalker.h" #include "stats.h" #include "util.h" @@ -26,6 +27,7 @@ static void entry_launch(void) { /* Child here */ entry_run = TRUE; instrument_on_fork(); + seccomp_on_fork(); stats_on_fork(); } diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index cf422ba9..40bb4a16 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -191,6 +191,14 @@ class Afl { static setPrefetchDisable() { Afl.jsApiSetPrefetchDisable(); } + /** + * See `AFL_FRIDA_SECCOMP_FILE`. This function takes a single `string` as + * an argument. + */ + static setSeccompFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetSeccompFile(buf); + } /* * Set a function to be called for each instruction which is instrumented * by AFL FRIDA mode. @@ -271,6 +279,7 @@ Afl.jsApiSetPersistentHook = Afl.jsApiGetFunction("js_api_set_persistent_hook", Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_return", "void", ["pointer"]); Afl.jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_backpatch_disable", "void", []); Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []); +Afl.jsApiSetSeccompFile = Afl.jsApiGetFunction("js_api_set_seccomp_file", "void", ["pointer"]); Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]); Afl.jsApiSetStalkerIcEntries = Afl.jsApiGetFunction("js_api_set_stalker_ic_entries", "void", ["uint32"]); Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 49ca3baa..9dba79aa 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -7,6 +7,7 @@ #include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "seccomp.h" #include "stalker.h" #include "stats.h" #include "util.h" @@ -171,6 +172,13 @@ js_api_set_instrument_unstable_coverage_file(char *path) { } +__attribute__((visibility("default"))) void js_api_set_seccomp_file( + char *file) { + + seccomp_filename = g_strdup(file); + +} + __attribute__((visibility("default"))) void js_api_set_stdout(char *file) { output_stdout = g_strdup(file); diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 91687046..c0de9c6b 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -25,6 +25,7 @@ #include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "seccomp.h" #include "stalker.h" #include "stats.h" #include "util.h" @@ -177,6 +178,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) { persistent_config(); prefetch_config(); ranges_config(); + seccomp_config(); stalker_config(); stats_config(); @@ -191,6 +193,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) { lib_init(); persistent_init(); prefetch_init(); + seccomp_init(); stalker_init(); ranges_init(); stats_init(); diff --git a/frida_mode/src/seccomp/seccomp.c b/frida_mode/src/seccomp/seccomp.c new file mode 100644 index 00000000..7683cd71 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +#include "frida-gumjs.h" + +#include "debug.h" + +#include "seccomp.h" +#include "util.h" + +char *seccomp_filename = NULL; + +static void seccomp_vprint(int fd, char *format, va_list ap) { + + char buffer[4096] = {0}; + int len; + + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(fd, buffer, len)); + +} + +void seccomp_print(char *format, ...) { + + va_list ap; + va_start(ap, format); + seccomp_vprint(SECCOMP_OUTPUT_FILE_FD, format, ap); + va_end(ap); + +} + +static void seccomp_filter_callback(struct seccomp_notif * req, + struct seccomp_notif_resp *resp, + GumReturnAddressArray * frames) { + + GumDebugSymbolDetails details = {0}; + if (req->data.nr == SYS_OPENAT) { + + seccomp_print("SYS_OPENAT: (%s)\n", (char *)req->data.args[1]); + + } + + seccomp_print( + "\nID (%#llx) for PID %d - %d (%s) [0x%llx 0x%llx 0x%llx 0x%llx 0x%llx " + "0x%llx ]\n", + req->id, req->pid, req->data.nr, seccomp_syscall_lookup(req->data.nr), + req->data.args[0], req->data.args[1], req->data.args[2], + req->data.args[3], req->data.args[4], req->data.args[5]); + + seccomp_print("FRAMES: (%u)\n", frames->len); + char **syms = backtrace_symbols(frames->items, frames->len); + if (syms == NULL) { FATAL("Failed to get symbols"); } + + for (guint i = 0; i < frames->len; i++) { + + if (gum_symbol_details_from_address(frames->items[i], &details)) { + + seccomp_print("\t%3d. %s!%s\n", i, details.module_name, + details.symbol_name); + + } else { + + seccomp_print("\t%3d. %s\n", i, syms[i]); + + } + + } + + free(syms); + + resp->error = 0; + resp->val = 0; + resp->id = req->id; + resp->flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE; + +} + +static void seccomp_child(int signal_parent, void *ctx) { + + int sock_fd = *((int *)ctx); + int fd = seccomp_socket_recv(sock_fd); + + if (close(sock_fd) < 0) { FATAL("child - close"); } + + seccomp_event_signal(signal_parent); + seccomp_filter_child_install(); + seccomp_filter_run(fd, seccomp_filter_callback); + +} + +void seccomp_on_fork(void) { + + int sock[2] = {-1, -1}; + pid_t child = -1; + int child_fd = -1; + + if (seccomp_filename == NULL) { return; } + + seccomp_socket_create(sock); + seccomp_child_run(seccomp_child, sock, &child, &child_fd); + + if (dup2(child_fd, SECCOMP_PARENT_EVENT_FD) < 0) { FATAL("dup2"); } + + if (close(child_fd) < 0) { FATAL("seccomp_on_fork - close (1)"); } + + if (close(sock[STDIN_FILENO]) < 0) { FATAL("grandparent - close (2)"); } + + int fd = seccomp_filter_install(child); + seccomp_socket_send(sock[STDOUT_FILENO], fd); + + if (close(sock[STDOUT_FILENO]) < 0) { FATAL("grandparent - close (3)"); } + + if (close(fd) < 0) { FATAL("grandparent - close (4)"); } + + seccomp_child_wait(SECCOMP_PARENT_EVENT_FD); + +} + +void seccomp_config(void) { + + seccomp_filename = getenv("AFL_FRIDA_SECCOMP_FILE"); + +} + +void seccomp_init(void) { + + char *path = NULL; + int fd; + + OKF("Seccomp - file [%s]", seccomp_filename); + + if (seccomp_filename == NULL) { return; } + + path = g_canonicalize_filename(seccomp_filename, g_get_current_dir()); + + OKF("Seccomp - path [%s]", path); + + fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (dup2(fd, SECCOMP_OUTPUT_FILE_FD) < 0) { + + FATAL("Failed to duplicate seccomp output file"); + + } + + if (close(fd) < 0) { FATAL("Failed to close seccomp output file fd"); } + + g_free(path); + +} + diff --git a/frida_mode/src/seccomp/seccomp_atomic.c b/frida_mode/src/seccomp/seccomp_atomic.c new file mode 100644 index 00000000..1720a726 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_atomic.c @@ -0,0 +1,28 @@ +#include +#include + +#include "debug.h" + +void seccomp_atomic_set(volatile bool *ptr, bool val) { + + if (!__sync_bool_compare_and_swap(ptr, !val, val)) { + + FATAL("Failed to set event"); + + } + +} + +bool seccomp_atomic_try_set(volatile bool *ptr, bool val) { + + return __sync_bool_compare_and_swap(ptr, !val, val); + +} + +void seccomp_atomic_wait(volatile bool *ptr, bool val) { + + while (!__sync_bool_compare_and_swap(ptr, val, !val)) + ; + +} + diff --git a/frida_mode/src/seccomp/seccomp_child.c b/frida_mode/src/seccomp/seccomp_child.c new file mode 100644 index 00000000..4d494137 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_child.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +#include "seccomp.h" + +#define SECCOMP_CHILD_STACK_SIZE (1UL << 20) + +typedef void (*seccomp_child_func_t)(int event_fd, void *ctx); + +typedef struct { + + seccomp_child_func_t func; + int event_fd; + void * ctx; + +} seccomp_child_func_ctx_t; + +static int seccomp_child_func(void *ctx) { + + seccomp_child_func_ctx_t *args = (seccomp_child_func_ctx_t *)ctx; + args->func(args->event_fd, args->ctx); + _exit(0); + return 0; + +} + +void seccomp_child_run(seccomp_child_func_t child_func, void *ctx, pid_t *child, + int *event_fd) { + + int fd = seccomp_event_create(); + + seccomp_child_func_ctx_t *child_ctx = + malloc(sizeof(seccomp_child_func_ctx_t)); + child_ctx->func = child_func; + child_ctx->ctx = ctx; + child_ctx->event_fd = fd; + + int flags = CLONE_VM | CLONE_UNTRACED; + + char *stack = + (char *)mmap(NULL, SECCOMP_CHILD_STACK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (stack == MAP_FAILED) { FATAL("mmap"); } + + pid_t child_pid = clone(seccomp_child_func, &stack[SECCOMP_CHILD_STACK_SIZE], + flags, child_ctx, NULL, NULL, NULL); + if (child_pid < 0) { FATAL("clone"); } + + if (child != NULL) { *child = child_pid; } + if (event_fd != NULL) { *event_fd = fd; } + +} + +void seccomp_child_wait(int event_fd) { + + seccomp_event_wait(event_fd); + seccomp_event_destroy(event_fd); + +} + diff --git a/frida_mode/src/seccomp/seccomp_event.c b/frida_mode/src/seccomp/seccomp_event.c new file mode 100644 index 00000000..ecb9be32 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_event.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "debug.h" + +#include "seccomp.h" + +int seccomp_event_create(void) { + + int fd = eventfd(0, 0); + if (fd < 0) { FATAL("seccomp_event_create"); } + return fd; + +} + +void seccomp_event_signal(int fd) { + + uint64_t val = 1; + if (write(fd, &val, sizeof(uint64_t)) != sizeof(uint64_t)) { + + FATAL("seccomp_event_signal"); + + } + +} + +void seccomp_event_wait(int fd) { + + uint64_t val = 1; + if (read(fd, &val, sizeof(uint64_t)) != sizeof(uint64_t)) { + + FATAL("seccomp_event_wait"); + + } + +} + +void seccomp_event_destroy(int fd) { + + if (close(fd) < 0) { FATAL("seccomp_event_destroy"); } + +} + diff --git a/frida_mode/src/seccomp/seccomp_filter.c b/frida_mode/src/seccomp/seccomp_filter.c new file mode 100644 index 00000000..c16e7ebd --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_filter.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +#include "frida-gumjs.h" + +#include "seccomp.h" +#include "util.h" + +#define SECCOMP_FILTER_NUM_FRAMES 512 + +extern void gum_linux_parse_ucontext(const ucontext_t *uc, GumCpuContext *ctx); + +static struct sock_filter filter[] = { + + /* Allow us sendmsg to SECCOMP_FD */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_sendmsg, 0, 3), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, args[0]))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_SOCKET_SEND_FD, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow close */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_close, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow sigreturn */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_rt_sigreturn, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow sigprocmaksk */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_rt_sigprocmask, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow console output*/ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_lseek, 2, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fstat, 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 4), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, args[0]))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, STDERR_FILENO, 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, STDOUT_FILENO, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow waiting for the child */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_read, 0, 3), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, args[0]))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SECCOMP_PARENT_EVENT_FD, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow us to make anonymous maps */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap, 0, 3), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, args[4]))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, -1, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow msync/mincore used by cmplog */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_msync, 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mincore, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* + * Allow tgkill (SIGKILL, SIGSTOP) used in persistent mode. Also + * allow seccomp to send (SIGUSR1) to the child to collect trace. + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_tgkill, 0, 5), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, args[2]))), + /* Used by seccomp to signal the child to collect a callstack*/ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SIGUSR1, 2, 0), + /* Used when handling faults */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SIGKILL, 1, 0), + /* Used by target app of interest */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SIGSTOP, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow getpid / gettid */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_getpid, 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_gettid, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow exit_group */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit_group, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Allow brk */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_brk, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + + /* Send the rest to user-mode to filter */ + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF)}; + +static volatile bool seccomp_filter_parent_done = false; +static volatile bool seccomp_filter_child_done = false; +static pid_t seccomp_filter_child = -1; +static GumCpuContext seccomp_filter_cpu_context = {0}; +static GumReturnAddressArray seccomp_filter_frames = {.len = 0, .items = {0}}; +static GumBacktracer * seccomp_filter_backtracer = NULL; + +static void seccomp_filter_child_handler(int sig, siginfo_t *info, + void *ucontext) { + + GumCpuContext cpu_context; + if (seccomp_filter_backtracer == NULL) { + + seccomp_filter_backtracer = gum_backtracer_make_fuzzy(); + + } + + gum_backtracer_generate(seccomp_filter_backtracer, + &seccomp_filter_cpu_context, &seccomp_filter_frames); + + seccomp_atomic_set(&seccomp_filter_child_done, true); + +} + +static void seccomp_filter_parent_handler(int sig, siginfo_t *info, + void *ucontext) { + + UNUSED_PARAMETER(sig); + UNUSED_PARAMETER(info); + + ucontext_t *uc = (ucontext_t *)ucontext; + gum_linux_parse_ucontext(uc, &seccomp_filter_cpu_context); + + if (tgkill(seccomp_filter_child, seccomp_filter_child, SIGUSR1) < 0) { + + FATAL("kill"); + + } + + seccomp_atomic_wait(&seccomp_filter_child_done, true); + seccomp_atomic_set(&seccomp_filter_parent_done, true); + +} + +void seccomp_filter_child_install(void) { + + const struct sigaction sa = {.sa_sigaction = seccomp_filter_child_handler, + .sa_flags = SA_SIGINFO | SA_RESTART}; + if (sigaction(SIGUSR1, &sa, NULL) < 0) { FATAL("sigaction"); } + +} + +int seccomp_filter_install(pid_t child) { + + seccomp_filter_child = child; + + const struct sigaction sa = {.sa_sigaction = seccomp_filter_parent_handler, + .sa_flags = SA_SIGINFO | SA_RESTART}; + + struct sock_fprog filter_prog = { + + .len = sizeof(filter) / sizeof(struct sock_filter), .filter = filter}; + + if (sigaction(SIGUSR1, &sa, NULL) < 0) { FATAL("sigaction"); } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + + FATAL("PR_SET_NO_NEW_PRIVS %d", errno); + + } + + int fd = syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, + SECCOMP_FILTER_FLAG_NEW_LISTENER, &filter_prog); + if (fd < 0) { FATAL("SYS_seccomp %d", fd); } + + return fd; + +} + +void seccomp_filter_run(int fd, seccomp_filter_callback_t callback) { + + struct seccomp_notif * req = NULL; + struct seccomp_notif_resp *resp = NULL; + struct seccomp_notif_sizes sizes; + + if (syscall(SYS_seccomp, SECCOMP_GET_NOTIF_SIZES, 0, &sizes) == -1) { + + FATAL("seccomp-SECCOMP_GET_NOTIF_SIZES"); + + } + + if (sizes.seccomp_notif != sizeof(struct seccomp_notif)) { + + FATAL("size - seccomp_notif"); + + } + + if (sizes.seccomp_notif_resp != sizeof(struct seccomp_notif_resp)) { + + FATAL("size - seccomp_notif"); + + } + + req = alloca(sizes.seccomp_notif); + resp = alloca(sizes.seccomp_notif_resp); + + while (true) { + + memset(req, 0, sizes.seccomp_notif); + + if (ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV, req) < 0) { + + if (errno == EINTR) { continue; } + FATAL("SECCOMP_IOCTL_NOTIF_RECV: %d\n", fd); + + } + + if (seccomp_atomic_try_set(&seccomp_filter_parent_done, false)) { + + callback(req, resp, &seccomp_filter_frames); + + } else { + + if (kill(req->pid, SIGUSR1) < 0) { FATAL("kill"); } + + } + + if (ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) { + + if (errno == ENOENT) { continue; } + OKF("SECCOMP_IOCTL_NOTIF_SEND"); + continue; + + } + + } + +} + diff --git a/frida_mode/src/seccomp/seccomp_socket.c b/frida_mode/src/seccomp/seccomp_socket.c new file mode 100644 index 00000000..ca42e158 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_socket.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include "debug.h" + +#include "seccomp.h" + +union cmsg { + + char buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr hdr; + +}; + +void seccomp_socket_create(int *sock) { + + int tmp_sock[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, tmp_sock) < 0) { + + FATAL("socketpair"); + + } + + if (dup2(tmp_sock[STDIN_FILENO], SECCOMP_SOCKET_RECV_FD) < 0) { + + FATAL("seccomp_socket_create - dup2 (1)"); + + } + + if (dup2(tmp_sock[STDOUT_FILENO], SECCOMP_SOCKET_SEND_FD) < 0) { + + FATAL("seccomp_socket_create - dup2 (1)"); + + } + + if (close(tmp_sock[STDIN_FILENO]) < 0) { + + FATAL("seccomp_socket_create - close (1)"); + + } + + if (close(tmp_sock[STDOUT_FILENO]) < 0) { + + FATAL("seccomp_socket_create - close (2)"); + + } + + sock[STDIN_FILENO] = SECCOMP_SOCKET_RECV_FD; + sock[STDOUT_FILENO] = SECCOMP_SOCKET_SEND_FD; + +} + +void seccomp_socket_send(int sockfd, int fd) { + + int data = 12345; + struct iovec iov = {.iov_base = &data, .iov_len = sizeof(data)}; + union cmsg control_msg = {.hdr = { + + .cmsg_len = CMSG_LEN(sizeof(int)), + .cmsg_level = SOL_SOCKET, + .cmsg_type = SCM_RIGHTS, + + }}; + + struct msghdr message = {.msg_control = control_msg.buf, + .msg_controllen = sizeof(control_msg.buf), + .msg_flags = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_name = NULL, + .msg_namelen = 0}; + + memcpy(CMSG_DATA(&control_msg.hdr), &fd, sizeof(int)); + + if (sendmsg(sockfd, &message, 0) == -1) { FATAL("sendmsg"); } + +} + +int seccomp_socket_recv(int sockfd) { + + int data; + struct iovec iov = {.iov_base = &data, .iov_len = sizeof(data)}; + union cmsg control_msg = {0}; + struct msghdr message = {.msg_control = control_msg.buf, + .msg_controllen = sizeof(control_msg.buf), + .msg_flags = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_name = NULL, + .msg_namelen = 0}; + + int fd; + + if (recvmsg(sockfd, &message, 0) < 0) { FATAL("recvmsg"); } + + if (control_msg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { + + FATAL("control_msg.hdr.cmsg_len"); + + } + + if (control_msg.hdr.cmsg_level != SOL_SOCKET) { + + FATAL("control_msg.hdr.cmsg_level"); + + } + + if (control_msg.hdr.cmsg_type != SCM_RIGHTS) { + + FATAL("control_msg.hdr.cmsg_type"); + + } + + memcpy(&fd, CMSG_DATA(&control_msg.hdr), sizeof(int)); + + return fd; + +} + diff --git a/frida_mode/src/seccomp/seccomp_syscall.c b/frida_mode/src/seccomp/seccomp_syscall.c new file mode 100644 index 00000000..b2c084c8 --- /dev/null +++ b/frida_mode/src/seccomp/seccomp_syscall.c @@ -0,0 +1,335 @@ +#include +#include + +#include "debug.h" + +#include "seccomp.h" + +typedef struct { + + int id; + char name[PATH_MAX]; + +} syscall_entry_t; + +static syscall_entry_t seccomp_syscall_table[] = { + + {SYS_READ, "SYS_READ"}, + {SYS_WRITE, "SYS_WRITE"}, + {SYS_OPEN, "SYS_OPEN"}, + {SYS_CLOSE, "SYS_CLOSE"}, + {SYS_STAT, "SYS_STAT"}, + {SYS_FSTAT, "SYS_FSTAT"}, + {SYS_LSTAT, "SYS_LSTAT"}, + {SYS_POLL, "SYS_POLL"}, + {SYS_LSEEK, "SYS_LSEEK"}, + {SYS_MMAP, "SYS_MMAP"}, + {SYS_MPROTECT, "SYS_MPROTECT"}, + {SYS_MUNMAP, "SYS_MUNMAP"}, + {SYS_BRK, "SYS_BRK"}, + {SYS_RT_SIGACTION, "SYS_RT_SIGACTION"}, + {SYS_RT_SIGPROCMASK, "SYS_RT_SIGPROCMASK"}, + {SYS_RT_SIGRETURN, "SYS_RT_SIGRETURN"}, + {SYS_IOCTL, "SYS_IOCTL"}, + {SYS_PREAD64, "SYS_PREAD64"}, + {SYS_PWRITE64, "SYS_PWRITE64"}, + {SYS_READV, "SYS_READV"}, + {SYS_WRITEV, "SYS_WRITEV"}, + {SYS_ACCESS, "SYS_ACCESS"}, + {SYS_PIPE, "SYS_PIPE"}, + {SYS_SELECT, "SYS_SELECT"}, + {SYS_SCHED_YIELD, "SYS_SCHED_YIELD"}, + {SYS_MREMAP, "SYS_MREMAP"}, + {SYS_MSYNC, "SYS_MSYNC"}, + {SYS_MINCORE, "SYS_MINCORE"}, + {SYS_MADVISE, "SYS_MADVISE"}, + {SYS_SHMGET, "SYS_SHMGET"}, + {SYS_SHMAT, "SYS_SHMAT"}, + {SYS_SHMCTL, "SYS_SHMCTL"}, + {SYS_DUP, "SYS_DUP"}, + {SYS_DUP2, "SYS_DUP2"}, + {SYS_PAUSE, "SYS_PAUSE"}, + {SYS_NANOSLEEP, "SYS_NANOSLEEP"}, + {SYS_GETITIMER, "SYS_GETITIMER"}, + {SYS_ALARM, "SYS_ALARM"}, + {SYS_SETITIMER, "SYS_SETITIMER"}, + {SYS_GETPID, "SYS_GETPID"}, + {SYS_SENDFILE, "SYS_SENDFILE"}, + {SYS_SOCKET, "SYS_SOCKET"}, + {SYS_CONNECT, "SYS_CONNECT"}, + {SYS_ACCEPT, "SYS_ACCEPT"}, + {SYS_SENDTO, "SYS_SENDTO"}, + {SYS_RECVFROM, "SYS_RECVFROM"}, + {SYS_SENDMSG, "SYS_SENDMSG"}, + {SYS_RECVMSG, "SYS_RECVMSG"}, + {SYS_SHUTDOWN, "SYS_SHUTDOWN"}, + {SYS_BIND, "SYS_BIND"}, + {SYS_LISTEN, "SYS_LISTEN"}, + {SYS_GETSOCKNAME, "SYS_GETSOCKNAME"}, + {SYS_GETPEERNAME, "SYS_GETPEERNAME"}, + {SYS_SOCKETPAIR, "SYS_SOCKETPAIR"}, + {SYS_SETSOCKOPT, "SYS_SETSOCKOPT"}, + {SYS_GETSOCKOPT, "SYS_GETSOCKOPT"}, + {SYS_CLONE, "SYS_CLONE"}, + {SYS_FORK, "SYS_FORK"}, + {SYS_VFORK, "SYS_VFORK"}, + {SYS_EXECVE, "SYS_EXECVE"}, + {SYS_EXIT, "SYS_EXIT"}, + {SYS_WAIT4, "SYS_WAIT4"}, + {SYS_KILL, "SYS_KILL"}, + {SYS_UNAME, "SYS_UNAME"}, + {SYS_SEMGET, "SYS_SEMGET"}, + {SYS_SEMOP, "SYS_SEMOP"}, + {SYS_SEMCTL, "SYS_SEMCTL"}, + {SYS_SHMDT, "SYS_SHMDT"}, + {SYS_MSGGET, "SYS_MSGGET"}, + {SYS_MSGSND, "SYS_MSGSND"}, + {SYS_MSGRCV, "SYS_MSGRCV"}, + {SYS_MSGCTL, "SYS_MSGCTL"}, + {SYS_FCNTL, "SYS_FCNTL"}, + {SYS_FLOCK, "SYS_FLOCK"}, + {SYS_FSYNC, "SYS_FSYNC"}, + {SYS_FDATASYNC, "SYS_FDATASYNC"}, + {SYS_TRUNCATE, "SYS_TRUNCATE"}, + {SYS_FTRUNCATE, "SYS_FTRUNCATE"}, + {SYS_GETDENTS, "SYS_GETDENTS"}, + {SYS_GETCWD, "SYS_GETCWD"}, + {SYS_CHDIR, "SYS_CHDIR"}, + {SYS_FCHDIR, "SYS_FCHDIR"}, + {SYS_RENAME, "SYS_RENAME"}, + {SYS_MKDIR, "SYS_MKDIR"}, + {SYS_RMDIR, "SYS_RMDIR"}, + {SYS_CREAT, "SYS_CREAT"}, + {SYS_LINK, "SYS_LINK"}, + {SYS_UNLINK, "SYS_UNLINK"}, + {SYS_SYMLINK, "SYS_SYMLINK"}, + {SYS_READLINK, "SYS_READLINK"}, + {SYS_CHMOD, "SYS_CHMOD"}, + {SYS_FCHMOD, "SYS_FCHMOD"}, + {SYS_CHOWN, "SYS_CHOWN"}, + {SYS_FCHOWN, "SYS_FCHOWN"}, + {SYS_LCHOWN, "SYS_LCHOWN"}, + {SYS_UMASK, "SYS_UMASK"}, + {SYS_GETTIMEOFDAY, "SYS_GETTIMEOFDAY"}, + {SYS_GETRLIMIT, "SYS_GETRLIMIT"}, + {SYS_GETRUSAGE, "SYS_GETRUSAGE"}, + {SYS_SYSINFO, "SYS_SYSINFO"}, + {SYS_TIMES, "SYS_TIMES"}, + {SYS_PTRACE, "SYS_PTRACE"}, + {SYS_GETUID, "SYS_GETUID"}, + {SYS_SYSLOG, "SYS_SYSLOG"}, + {SYS_GETGID, "SYS_GETGID"}, + {SYS_SETUID, "SYS_SETUID"}, + {SYS_SETGID, "SYS_SETGID"}, + {SYS_GETEUID, "SYS_GETEUID"}, + {SYS_GETEGID, "SYS_GETEGID"}, + {SYS_SETPGID, "SYS_SETPGID"}, + {SYS_GETPPID, "SYS_GETPPID"}, + {SYS_GETPGRP, "SYS_GETPGRP"}, + {SYS_SETSID, "SYS_SETSID"}, + {SYS_SETREUID, "SYS_SETREUID"}, + {SYS_SETREGID, "SYS_SETREGID"}, + {SYS_GETGROUPS, "SYS_GETGROUPS"}, + {SYS_SETGROUPS, "SYS_SETGROUPS"}, + {SYS_SETRESUID, "SYS_SETRESUID"}, + {SYS_GETRESUID, "SYS_GETRESUID"}, + {SYS_SETRESGID, "SYS_SETRESGID"}, + {SYS_GETRESGID, "SYS_GETRESGID"}, + {SYS_GETPGID, "SYS_GETPGID"}, + {SYS_SETFSUID, "SYS_SETFSUID"}, + {SYS_SETFSGID, "SYS_SETFSGID"}, + {SYS_GETSID, "SYS_GETSID"}, + {SYS_CAPGET, "SYS_CAPGET"}, + {SYS_CAPSET, "SYS_CAPSET"}, + {SYS_RT_SIGPENDING, "SYS_RT_SIGPENDING"}, + {SYS_RT_SIGTIMEDWAIT, "SYS_RT_SIGTIMEDWAIT"}, + {SYS_RT_SIGQUEUEINFO, "SYS_RT_SIGQUEUEINFO"}, + {SYS_RT_SIGSUSPEND, "SYS_RT_SIGSUSPEND"}, + {SYS_SIGALTSTACK, "SYS_SIGALTSTACK"}, + {SYS_UTIME, "SYS_UTIME"}, + {SYS_MKNOD, "SYS_MKNOD"}, + {SYS_USELIB, "SYS_USELIB"}, + {SYS_PERSONALITY, "SYS_PERSONALITY"}, + {SYS_USTAT, "SYS_USTAT"}, + {SYS_STATFS, "SYS_STATFS"}, + {SYS_FSTATFS, "SYS_FSTATFS"}, + {SYS_SYSFS, "SYS_SYSFS"}, + {SYS_GETPRIORITY, "SYS_GETPRIORITY"}, + {SYS_SETPRIORITY, "SYS_SETPRIORITY"}, + {SYS_SCHED_SETPARAM, "SYS_SCHED_SETPARAM"}, + {SYS_SCHED_GETPARAM, "SYS_SCHED_GETPARAM"}, + {SYS_SCHED_SETSCHEDULER, "SYS_SCHED_SETSCHEDULER"}, + {SYS_SCHED_GETSCHEDULER, "SYS_SCHED_GETSCHEDULER"}, + {SYS_SCHED_GET_PRIORITY_MAX, "SYS_SCHED_GET_PRIORITY_MAX"}, + {SYS_SCHED_GET_PRIORITY_MIN, "SYS_SCHED_GET_PRIORITY_MIN"}, + {SYS_SCHED_RR_GET_INTERVAL, "SYS_SCHED_RR_GET_INTERVAL"}, + {SYS_MLOCK, "SYS_MLOCK"}, + {SYS_MUNLOCK, "SYS_MUNLOCK"}, + {SYS_MLOCKALL, "SYS_MLOCKALL"}, + {SYS_MUNLOCKALL, "SYS_MUNLOCKALL"}, + {SYS_VHANGUP, "SYS_VHANGUP"}, + {SYS_MODIFY_LDT, "SYS_MODIFY_LDT"}, + {SYS_PIVOT_ROOT, "SYS_PIVOT_ROOT"}, + {SYS__SYSCTL, "SYS__SYSCTL"}, + {SYS_PRCTL, "SYS_PRCTL"}, + {SYS_ARCH_PRCTL, "SYS_ARCH_PRCTL"}, + {SYS_ADJTIMEX, "SYS_ADJTIMEX"}, + {SYS_SETRLIMIT, "SYS_SETRLIMIT"}, + {SYS_CHROOT, "SYS_CHROOT"}, + {SYS_SYNC, "SYS_SYNC"}, + {SYS_ACCT, "SYS_ACCT"}, + {SYS_SETTIMEOFDAY, "SYS_SETTIMEOFDAY"}, + {SYS_MOUNT, "SYS_MOUNT"}, + {SYS_UMOUNT2, "SYS_UMOUNT2"}, + {SYS_SWAPON, "SYS_SWAPON"}, + {SYS_SWAPOFF, "SYS_SWAPOFF"}, + {SYS_REBOOT, "SYS_REBOOT"}, + {SYS_SETHOSTNAME, "SYS_SETHOSTNAME"}, + {SYS_SETDOMAINNAME, "SYS_SETDOMAINNAME"}, + {SYS_IOPL, "SYS_IOPL"}, + {SYS_IOPERM, "SYS_IOPERM"}, + {SYS_CREATE_MODULE, "SYS_CREATE_MODULE"}, + {SYS_INIT_MODULE, "SYS_INIT_MODULE"}, + {SYS_DELETE_MODULE, "SYS_DELETE_MODULE"}, + {SYS_GET_KERNEL_SYMS, "SYS_GET_KERNEL_SYMS"}, + {SYS_QUERY_MODULE, "SYS_QUERY_MODULE"}, + {SYS_QUOTACTL, "SYS_QUOTACTL"}, + {SYS_NFSSERVCTL, "SYS_NFSSERVCTL"}, + {SYS_GETPMSG, "SYS_GETPMSG"}, + {SYS_PUTPMSG, "SYS_PUTPMSG"}, + {SYS_AFS_SYSCALL, "SYS_AFS_SYSCALL"}, + {SYS_TUXCALL, "SYS_TUXCALL"}, + {SYS_SECURITY, "SYS_SECURITY"}, + {SYS_GETTID, "SYS_GETTID"}, + {SYS_READAHEAD, "SYS_READAHEAD"}, + {SYS_SETXATTR, "SYS_SETXATTR"}, + {SYS_LSETXATTR, "SYS_LSETXATTR"}, + {SYS_FSETXATTR, "SYS_FSETXATTR"}, + {SYS_GETXATTR, "SYS_GETXATTR"}, + {SYS_LGETXATTR, "SYS_LGETXATTR"}, + {SYS_FGETXATTR, "SYS_FGETXATTR"}, + {SYS_LISTXATTR, "SYS_LISTXATTR"}, + {SYS_LLISTXATTR, "SYS_LLISTXATTR"}, + {SYS_FLISTXATTR, "SYS_FLISTXATTR"}, + {SYS_REMOVEXATTR, "SYS_REMOVEXATTR"}, + {SYS_LREMOVEXATTR, "SYS_LREMOVEXATTR"}, + {SYS_FREMOVEXATTR, "SYS_FREMOVEXATTR"}, + {SYS_TKILL, "SYS_TKILL"}, + {SYS_TIME, "SYS_TIME"}, + {SYS_FUTEX, "SYS_FUTEX"}, + {SYS_SCHED_SETAFFINITY, "SYS_SCHED_SETAFFINITY"}, + {SYS_SCHED_GETAFFINITY, "SYS_SCHED_GETAFFINITY"}, + {SYS_SET_THREAD_AREA, "SYS_SET_THREAD_AREA"}, + {SYS_IO_SETUP, "SYS_IO_SETUP"}, + {SYS_IO_DESTROY, "SYS_IO_DESTROY"}, + {SYS_IO_GETEVENTS, "SYS_IO_GETEVENTS"}, + {SYS_IO_SUBMIT, "SYS_IO_SUBMIT"}, + {SYS_IO_CANCEL, "SYS_IO_CANCEL"}, + {SYS_GET_THREAD_AREA, "SYS_GET_THREAD_AREA"}, + {SYS_LOOKUP_DCOOKIE, "SYS_LOOKUP_DCOOKIE"}, + {SYS_EPOLL_CREATE, "SYS_EPOLL_CREATE"}, + {SYS_EPOLL_CTL_OLD, "SYS_EPOLL_CTL_OLD"}, + {SYS_EPOLL_WAIT_OLD, "SYS_EPOLL_WAIT_OLD"}, + {SYS_REMAP_FILE_PAGES, "SYS_REMAP_FILE_PAGES"}, + {SYS_GETDENTS64, "SYS_GETDENTS64"}, + {SYS_SET_TID_ADDRESS, "SYS_SET_TID_ADDRESS"}, + {SYS_RESTART_SYSCALL, "SYS_RESTART_SYSCALL"}, + {SYS_SEMTIMEDOP, "SYS_SEMTIMEDOP"}, + {SYS_FADVISE64, "SYS_FADVISE64"}, + {SYS_TIMER_CREATE, "SYS_TIMER_CREATE"}, + {SYS_TIMER_SETTIME, "SYS_TIMER_SETTIME"}, + {SYS_TIMER_GETTIME, "SYS_TIMER_GETTIME"}, + {SYS_TIMER_GETOVERRUN, "SYS_TIMER_GETOVERRUN"}, + {SYS_TIMER_DELETE, "SYS_TIMER_DELETE"}, + {SYS_CLOCK_SETTIME, "SYS_CLOCK_SETTIME"}, + {SYS_CLOCK_GETTIME, "SYS_CLOCK_GETTIME"}, + {SYS_CLOCK_GETRES, "SYS_CLOCK_GETRES"}, + {SYS_CLOCK_NANOSLEEP, "SYS_CLOCK_NANOSLEEP"}, + {SYS_EXIT_GROUP, "SYS_EXIT_GROUP"}, + {SYS_EPOLL_WAIT, "SYS_EPOLL_WAIT"}, + {SYS_EPOLL_CTL, "SYS_EPOLL_CTL"}, + {SYS_TGKILL, "SYS_TGKILL"}, + {SYS_UTIMES, "SYS_UTIMES"}, + {SYS_VSERVER, "SYS_VSERVER"}, + {SYS_MBIND, "SYS_MBIND"}, + {SYS_SET_MEMPOLICY, "SYS_SET_MEMPOLICY"}, + {SYS_GET_MEMPOLICY, "SYS_GET_MEMPOLICY"}, + {SYS_MQ_OPEN, "SYS_MQ_OPEN"}, + {SYS_MQ_UNLINK, "SYS_MQ_UNLINK"}, + {SYS_MQ_TIMEDSEND, "SYS_MQ_TIMEDSEND"}, + {SYS_MQ_TIMEDRECEIVE, "SYS_MQ_TIMEDRECEIVE"}, + {SYS_MQ_NOTIFY, "SYS_MQ_NOTIFY"}, + {SYS_MQ_GETSETATTR, "SYS_MQ_GETSETATTR"}, + {SYS_KEXEC_LOAD, "SYS_KEXEC_LOAD"}, + {SYS_WAITID, "SYS_WAITID"}, + {SYS_ADD_KEY, "SYS_ADD_KEY"}, + {SYS_REQUEST_KEY, "SYS_REQUEST_KEY"}, + {SYS_KEYCTL, "SYS_KEYCTL"}, + {SYS_IOPRIO_SET, "SYS_IOPRIO_SET"}, + {SYS_IOPRIO_GET, "SYS_IOPRIO_GET"}, + {SYS_INOTIFY_INIT, "SYS_INOTIFY_INIT"}, + {SYS_INOTIFY_ADD_WATCH, "SYS_INOTIFY_ADD_WATCH"}, + {SYS_INOTIFY_RM_WATCH, "SYS_INOTIFY_RM_WATCH"}, + {SYS_MIGRATE_PAGES, "SYS_MIGRATE_PAGES"}, + {SYS_OPENAT, "SYS_OPENAT"}, + {SYS_MKDIRAT, "SYS_MKDIRAT"}, + {SYS_MKNODAT, "SYS_MKNODAT"}, + {SYS_FCHOWNAT, "SYS_FCHOWNAT"}, + {SYS_FUTIMESAT, "SYS_FUTIMESAT"}, + {SYS_NEWFSTATAT, "SYS_NEWFSTATAT"}, + {SYS_UNLINKAT, "SYS_UNLINKAT"}, + {SYS_RENAMEAT, "SYS_RENAMEAT"}, + {SYS_LINKAT, "SYS_LINKAT"}, + {SYS_SYMLINKAT, "SYS_SYMLINKAT"}, + {SYS_READLINKAT, "SYS_READLINKAT"}, + {SYS_FCHMODAT, "SYS_FCHMODAT"}, + {SYS_FACCESSAT, "SYS_FACCESSAT"}, + {SYS_PSELECT6, "SYS_PSELECT6"}, + {SYS_PPOLL, "SYS_PPOLL"}, + {SYS_UNSHARE, "SYS_UNSHARE"}, + {SYS_SET_ROBUST_LIST, "SYS_SET_ROBUST_LIST"}, + {SYS_GET_ROBUST_LIST, "SYS_GET_ROBUST_LIST"}, + {SYS_SPLICE, "SYS_SPLICE"}, + {SYS_TEE, "SYS_TEE"}, + {SYS_SYNC_FILE_RANGE, "SYS_SYNC_FILE_RANGE"}, + {SYS_VMSPLICE, "SYS_VMSPLICE"}, + {SYS_MOVE_PAGES, "SYS_MOVE_PAGES"}, + {SYS_UTIMENSAT, "SYS_UTIMENSAT"}, + {SYS_EPOLL_PWAIT, "SYS_EPOLL_PWAIT"}, + {SYS_SIGNALFD, "SYS_SIGNALFD"}, + {SYS_TIMERFD_CREATE, "SYS_TIMERFD_CREATE"}, + {SYS_EVENTFD, "SYS_EVENTFD"}, + {SYS_FALLOCATE, "SYS_FALLOCATE"}, + {SYS_TIMERFD_SETTIME, "SYS_TIMERFD_SETTIME"}, + {SYS_TIMERFD_GETTIME, "SYS_TIMERFD_GETTIME"}, + {SYS_ACCEPT4, "SYS_ACCEPT4"}, + {SYS_SIGNALFD4, "SYS_SIGNALFD4"}, + {SYS_EVENTFD2, "SYS_EVENTFD2"}, + {SYS_EPOLL_CREATE1, "SYS_EPOLL_CREATE1"}, + {SYS_DUP3, "SYS_DUP3"}, + {SYS_PIPE2, "SYS_PIPE2"}, + {SYS_INOTIFY_INIT1, "SYS_INOTIFY_INIT1"}, + {SYS_PREADV, "SYS_PREADV"}, + {SYS_PWRITEV, "SYS_PWRITEV"}, + {SYS_RT_TGSIGQUEUEINFO, "SYS_RT_TGSIGQUEUEINFO"}, + {SYS_PERF_EVENT_OPEN, "SYS_PERF_EVENT_OPEN"}, + {SYS_RECVMMSG, "SYS_RECVMMSG"}, + {SYS_FANOTIFY_INIT, "SYS_FANOTIFY_INIT"}, + {SYS_FANOTIFY_MARK, "SYS_FANOTIFY_MARK"}, + {SYS_PRLIMIT64, "SYS_PRLIMIT64"}, + +}; + +char *seccomp_syscall_lookup(int id) { + + if (id < 0) { FATAL("Invalid id: %d", id); } + if ((uint32_t)id >= sizeof(seccomp_syscall_table) / sizeof(syscall_entry_t)) { + + FATAL("Invalid id: %d", id); + + } + + return seccomp_syscall_table[id].name; + +} + diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index c722f558..8a1ebf1b 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -225,6 +225,15 @@ class Afl { Afl.jsApiSetPrefetchDisable(); } + /** + * See `AFL_FRIDA_SECCOMP_FILE`. This function takes a single `string` as + * an argument. + */ + public static setSeccompFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetSeccompFile(buf); + } + /* * Set a function to be called for each instruction which is instrumented * by AFL FRIDA mode. @@ -387,6 +396,11 @@ class Afl { "void", []); + private static readonly jsApiSetSeccompFile = Afl.jsApiGetFunction( + "js_api_set_seccomp_file", + "void", + ["pointer"]); + private static readonly jsApiSetStalkerCallback = Afl.jsApiGetFunction( "js_api_set_stalker_callback", "void", -- cgit 1.4.1