aboutsummaryrefslogtreecommitdiff
path: root/frida_mode/src/instrument
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-05-10 13:57:47 +0200
committerGitHub <noreply@github.com>2021-05-10 13:57:47 +0200
commit8b7a7b29c60f11cdf6226b3e418e87a5c3f5caac (patch)
tree6ce9d90644f161d21d802e9cbe48eb38467684e9 /frida_mode/src/instrument
parentd0225c2c4d465968660a08c93857fed354e539b1 (diff)
downloadafl++-8b7a7b29c60f11cdf6226b3e418e87a5c3f5caac.tar.gz
Push to stable (#895)
* sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name <you@example.com> * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name <you@example.com> * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name <you@example.com> * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name <you@example.com> * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name <you@example.com> * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com> * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name <you@example.com> * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name <you@example.com> * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name <you@example.com> * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name <you@example.com> * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation Co-authored-by: Dominik Maier <domenukk@gmail.com> Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name <you@example.com> Co-authored-by: Dmitry Zheregelya <zheregelya.d@gmail.com> Co-authored-by: hexcoder <hexcoder-@users.noreply.github.com> Co-authored-by: hexcoder- <heiko@hexco.de> Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com> Co-authored-by: David CARLIER <devnexen@gmail.com> Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev <SecNotice@ya.ru>
Diffstat (limited to 'frida_mode/src/instrument')
-rw-r--r--frida_mode/src/instrument/instrument.c155
-rw-r--r--frida_mode/src/instrument/instrument_arm32.c23
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c97
-rw-r--r--frida_mode/src/instrument/instrument_x64.c93
-rw-r--r--frida_mode/src/instrument/instrument_x86.c23
5 files changed, 391 insertions, 0 deletions
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
new file mode 100644
index 00000000..971f80c0
--- /dev/null
+++ b/frida_mode/src/instrument/instrument.c
@@ -0,0 +1,155 @@
+#include <unistd.h>
+
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "entry.h"
+#include "frida_cmplog.h"
+#include "instrument.h"
+#include "persistent.h"
+#include "prefetch.h"
+#include "ranges.h"
+#include "stalker.h"
+#include "util.h"
+
+static gboolean tracing = false;
+static gboolean optimize = false;
+static GumStalkerTransformer *transformer = NULL;
+
+__thread uint64_t previous_pc = 0;
+
+__attribute__((hot)) static void on_basic_block(GumCpuContext *context,
+ gpointer user_data) {
+
+ UNUSED_PARAMETER(context);
+ /*
+ * This function is performance critical as it is called to instrument every
+ * basic block. By moving our print buffer to a global, we avoid it affecting
+ * the critical path with additional stack adjustments if tracing is not
+ * enabled. If tracing is enabled, then we're printing a load of diagnostic
+ * information so this overhead is unlikely to be noticeable.
+ */
+ static char buffer[200];
+ int len;
+ guint64 current_pc = (guint64)user_data;
+ uint8_t * cursor;
+ uint64_t value;
+ if (unlikely(tracing)) {
+
+ /* Avoid any functions which may cause an allocation since the target app
+ * may already be running inside malloc and it isn't designed to be
+ * re-entrant on a single thread */
+ len = snprintf(buffer, sizeof(buffer),
+ "current_pc: 0x%016" G_GINT64_MODIFIER
+ "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n",
+ current_pc, previous_pc);
+
+ IGNORED_RERURN(write(STDOUT_FILENO, buffer, len + 1));
+
+ }
+
+ current_pc = (current_pc >> 4) ^ (current_pc << 8);
+ current_pc &= MAP_SIZE - 1;
+
+ cursor = &__afl_area_ptr[current_pc ^ previous_pc];
+ value = *cursor;
+
+ if (value == 0xff) {
+
+ value = 1;
+
+ } else {
+
+ value++;
+
+ }
+
+ *cursor = value;
+ previous_pc = current_pc >> 1;
+
+}
+
+static void instr_basic_block(GumStalkerIterator *iterator,
+ GumStalkerOutput *output, gpointer user_data) {
+
+ UNUSED_PARAMETER(user_data);
+
+ const cs_insn *instr;
+ gboolean begin = TRUE;
+ while (gum_stalker_iterator_next(iterator, &instr)) {
+
+ if (instr->address == entry_start) { entry_prologue(iterator, output); }
+ if (instr->address == persistent_start) { persistent_prologue(output); }
+
+ if (begin) {
+
+ prefetch_write((void *)instr->address);
+ if (!range_is_excluded((void *)instr->address)) {
+
+ if (optimize) {
+
+ instrument_coverage_optimize(instr, output);
+
+ } else {
+
+ gum_stalker_iterator_put_callout(iterator, on_basic_block,
+ (gpointer)instr->address, NULL);
+
+ }
+
+ }
+
+ begin = FALSE;
+
+ }
+
+ if (!range_is_excluded((void *)instr->address)) {
+
+ cmplog_instrument(instr, iterator);
+
+ }
+
+ gum_stalker_iterator_keep(iterator);
+
+ }
+
+}
+
+void instrument_init(void) {
+
+ optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL);
+ tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL);
+
+ if (!instrument_is_coverage_optimize_supported()) optimize = false;
+
+ OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' ');
+ OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' ');
+
+ if (tracing && optimize) {
+
+ FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible");
+
+ }
+
+ if (__afl_map_size != 0x10000) {
+
+ FATAL("Bad map size: 0x%08x", __afl_map_size);
+
+ }
+
+ transformer =
+ gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL);
+
+ cmplog_init();
+
+}
+
+GumStalkerTransformer *instrument_get_transformer(void) {
+
+ if (transformer == NULL) { FATAL("Instrumentation not initialized"); }
+ return transformer;
+
+}
+
diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c
new file mode 100644
index 00000000..c2d720a7
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_arm32.c
@@ -0,0 +1,23 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "instrument.h"
+
+#if defined(__arm__)
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+ return false;
+
+}
+
+void instrument_coverage_optimize(const cs_insn * instr,
+ GumStalkerOutput *output) {
+
+ FATAL("Optimized coverage not supported on this architecture");
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
new file mode 100644
index 00000000..fa3afb48
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -0,0 +1,97 @@
+#include "frida-gum.h"
+
+#include "config.h"
+#include "debug.h"
+
+#include "instrument.h"
+
+#if defined(__aarch64__)
+
+static GumAddress current_log_impl = GUM_ADDRESS(0);
+
+static const guint8 afl_log_code[] = {
+
+ // __afl_area_ptr[current_pc ^ previous_pc]++;
+ // previous_pc = current_pc >> 1;
+ 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]!
+ 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]!
+
+ // x0 = current_pc
+ 0xe1, 0x01, 0x00, 0x58, // ldr x1, #0x3c, =&__afl_area_ptr
+ 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr)
+
+ 0xe2, 0x01, 0x00, 0x58, // ldr x2, #0x3c, =&previous_pc
+ 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc)
+
+ // __afl_area_ptr[current_pc ^ previous_pc]++;
+ 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0
+ 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2]
+ 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1
+ 0x63, 0x00, 0x1f, 0x9a, // adc x3, x3, xzr
+ 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2]
+
+ // previous_pc = current_pc >> 1;
+ 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1
+ 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc
+ 0x40, 0x00, 0x00, 0xf9, // str x0, [x2]
+
+ 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10
+ 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10
+ 0xC0, 0x03, 0x5F, 0xD6, // ret
+
+ // &afl_area_ptr_ptr
+ // &afl_prev_loc_ptr
+
+};
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+ return true;
+
+}
+
+void instrument_coverage_optimize(const cs_insn * instr,
+ GumStalkerOutput *output) {
+
+ guint64 current_pc = instr->address;
+ guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
+ area_offset &= MAP_SIZE - 1;
+ GumArm64Writer *cw = output->writer.arm64;
+
+ if (current_log_impl == 0 ||
+ !gum_arm64_writer_can_branch_directly_between(cw, cw->pc,
+ current_log_impl) ||
+ !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128,
+ current_log_impl)) {
+
+ gconstpointer after_log_impl = cw->code + 1;
+
+ gum_arm64_writer_put_b_label(cw, after_log_impl);
+
+ current_log_impl = cw->pc;
+ gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
+
+ uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
+ uint64_t *afl_prev_loc_ptr = &previous_pc;
+ gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
+ sizeof(afl_area_ptr_ptr));
+ gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
+ sizeof(afl_prev_loc_ptr));
+
+ gum_arm64_writer_put_label(cw, after_log_impl);
+
+ }
+
+ gum_arm64_writer_put_stp_reg_reg_reg_offset(
+ cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE),
+ GUM_INDEX_PRE_ADJUST);
+ gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset);
+ gum_arm64_writer_put_bl_imm(cw, current_log_impl);
+ gum_arm64_writer_put_ldp_reg_reg_reg_offset(
+ cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE,
+ GUM_INDEX_POST_ADJUST);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
new file mode 100644
index 00000000..901f3bd0
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -0,0 +1,93 @@
+#include "frida-gum.h"
+
+#include "config.h"
+
+#include "instrument.h"
+
+#if defined(__x86_64__)
+
+static GumAddress current_log_impl = GUM_ADDRESS(0);
+
+static const guint8 afl_log_code[] = {
+
+ // 0xcc,
+
+ 0x9c, /* pushfq */
+ 0x51, /* push rcx */
+ 0x52, /* push rdx */
+
+ 0x48, 0x8b, 0x0d, 0x28,
+ 0x00, 0x00, 0x00, /* mov rcx, sym.&previous_pc */
+ 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */
+ 0x48, 0x31, 0xfa, /* xor rdx, rdi */
+
+ 0x48, 0x03, 0x15, 0x13,
+ 0x00, 0x00, 0x00, /* add rdx, sym._afl_area_ptr_ptr */
+
+ 0x80, 0x02, 0x01, /* add byte ptr [rdx], 1 */
+ 0x80, 0x12, 0x00, /* adc byte ptr [rdx], 0 */
+ 0x48, 0xd1, 0xef, /* shr rdi, 1 */
+ 0x48, 0x89, 0x39, /* mov qword [rcx], rdi */
+
+ 0x5a, /* pop rdx */
+ 0x59, /* pop rcx */
+ 0x9d, /* popfq */
+
+ 0xc3, /* ret */
+ 0x90, 0x90, 0x90 /* nop pad */
+
+ /* Read-only data goes here: */
+ /* uint8_t* __afl_area_ptr */
+ /* uint64_t* &previous_pc */
+
+};
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+ return true;
+
+}
+
+void instrument_coverage_optimize(const cs_insn * instr,
+ GumStalkerOutput *output) {
+
+ guint64 current_pc = instr->address;
+ guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8);
+ area_offset &= MAP_SIZE - 1;
+ GumX86Writer *cw = output->writer.x86;
+
+ if (current_log_impl == 0 ||
+ !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) ||
+ !gum_x86_writer_can_branch_directly_between(cw->pc + 128,
+ current_log_impl)) {
+
+ gconstpointer after_log_impl = cw->code + 1;
+
+ gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
+
+ current_log_impl = cw->pc;
+ gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
+
+ uint64_t *afl_prev_loc_ptr = &previous_pc;
+ gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr,
+ sizeof(__afl_area_ptr));
+ gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
+ sizeof(afl_prev_loc_ptr));
+
+ gum_x86_writer_put_label(cw, after_log_impl);
+
+ }
+
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+ -GUM_RED_ZONE_SIZE);
+ gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
+ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset);
+ gum_x86_writer_put_call_address(cw, current_log_impl);
+ gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+ GUM_RED_ZONE_SIZE);
+
+}
+
+#endif
+
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
new file mode 100644
index 00000000..5b8cbbba
--- /dev/null
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -0,0 +1,23 @@
+#include "frida-gum.h"
+
+#include "debug.h"
+
+#include "instrument.h"
+
+#if defined(__i386__)
+
+gboolean instrument_is_coverage_optimize_supported(void) {
+
+ return false;
+
+}
+
+void instrument_coverage_optimize(const cs_insn * instr,
+ GumStalkerOutput *output) {
+
+ FATAL("Optimized coverage not supported on this architecture");
+
+}
+
+#endif
+