about summary refs log tree commit diff
path: root/frida_mode
diff options
context:
space:
mode:
Diffstat (limited to 'frida_mode')
-rw-r--r--frida_mode/README.md44
-rw-r--r--frida_mode/include/util.h5
-rw-r--r--frida_mode/src/entry.c2
-rw-r--r--frida_mode/src/instrument/instrument.c2
-rw-r--r--frida_mode/src/persistent/persistent.c6
-rw-r--r--frida_mode/src/seccomp/seccomp_event.c10
-rw-r--r--frida_mode/src/seccomp/seccomp_filter.c10
-rw-r--r--frida_mode/src/stalker.c22
-rw-r--r--frida_mode/src/stats/stats.c6
-rw-r--r--frida_mode/src/util.c34
-rw-r--r--frida_mode/test/bloaty/GNUmakefile114
-rw-r--r--frida_mode/test/bloaty/Makefile13
-rwxr-xr-xfrida_mode/test/bloaty/get_symbol_addr.py36
13 files changed, 245 insertions, 59 deletions
diff --git a/frida_mode/README.md b/frida_mode/README.md
index c7d331b8..c19280e1 100644
--- a/frida_mode/README.md
+++ b/frida_mode/README.md
@@ -141,31 +141,33 @@ 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_DRIVER_NO_HOOK` - See `AFL_QEMU_DRIVER_NO_HOOK`. When using the
+  QEMU driver to provide a `main` loop for a user provided
+  `LLVMFuzzerTestOneInput`, this option configures the driver to read input from
+  `stdin` rather than using in-memory test cases.
 * `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.
 
-```
-***
-
-Creating block for 0x7ffff7953313:
-        0x7ffff7953313  mov qword ptr [rax], 0
-        0x7ffff795331a  add rsp, 8
-        0x7ffff795331e  ret
-
-Generated block 0x7ffff75e98e2
-        0x7ffff75e98e2  mov qword ptr [rax], 0
-        0x7ffff75e98e9  add rsp, 8
-        0x7ffff75e98ed  lea rsp, [rsp - 0x80]
-        0x7ffff75e98f5  push rcx
-        0x7ffff75e98f6  movabs rcx, 0x7ffff795331e
-        0x7ffff75e9900  jmp 0x7ffff75e9384
-
-
-***
-```
+  ```
+  ***
+
+  Creating block for 0x7ffff7953313:
+          0x7ffff7953313  mov qword ptr [rax], 0
+          0x7ffff795331a  add rsp, 8
+          0x7ffff795331e  ret
+
+  Generated block 0x7ffff75e98e2
+          0x7ffff75e98e2  mov qword ptr [rax], 0
+          0x7ffff75e98e9  add rsp, 8
+          0x7ffff75e98ed  lea rsp, [rsp - 0x80]
+          0x7ffff75e98f5  push rcx
+          0x7ffff75e98f6  movabs rcx, 0x7ffff795331e
+          0x7ffff75e9900  jmp 0x7ffff75e9384
+
+  ***
+  ```
 
 * `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
   code. Code is considered to be JIT if the executable segment is not backed by
@@ -194,6 +196,8 @@ Generated block 0x7ffff75e98e2
 * `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_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting
+  engine. See [Scipting.md](Scripting.md) for details.
 * `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/include/util.h b/frida_mode/include/util.h
index 77491ea8..4dc05f20 100644
--- a/frida_mode/include/util.h
+++ b/frida_mode/include/util.h
@@ -8,9 +8,8 @@
 #define UNUSED_PARAMETER(x) (void)(x)
 #define IGNORED_RETURN(x) (void)!(x)
 
-guint64 util_read_address(char *key);
-
-guint64  util_read_num(char *key);
+guint64  util_read_address(char *key, guint64 default_value);
+guint64  util_read_num(char *key, guint64 default_value);
 gboolean util_output_enabled(void);
 gsize    util_rotate(gsize val, gsize shift, gsize size);
 gsize    util_log2(gsize val);
diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c
index 562e74eb..de645fdb 100644
--- a/frida_mode/src/entry.c
+++ b/frida_mode/src/entry.c
@@ -62,7 +62,7 @@ void entry_on_fork(void) {
 
 void entry_config(void) {
 
-  entry_point = util_read_address("AFL_ENTRYPOINT");
+  entry_point = util_read_address("AFL_ENTRYPOINT", 0);
   if (getenv("AFL_FRIDA_TRACEABLE") != NULL) { traceable = TRUE; }
 
 }
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index d5823654..414dc84c 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -246,7 +246,7 @@ void instrument_config(void) {
   instrument_tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL);
   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_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0);
   instrument_coverage_unstable_filename =
       (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
 
diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c
index e62f25d0..817d9925 100644
--- a/frida_mode/src/persistent/persistent.c
+++ b/frida_mode/src/persistent/persistent.c
@@ -22,9 +22,9 @@ gboolean               persistent_debug = FALSE;
 void persistent_config(void) {
 
   hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK");
-  persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR");
-  persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT");
-  persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET");
+  persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR", 0);
+  persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT", 0);
+  persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET", 0);
 
   if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; }
 
diff --git a/frida_mode/src/seccomp/seccomp_event.c b/frida_mode/src/seccomp/seccomp_event.c
index 0907eff8..e6585f1d 100644
--- a/frida_mode/src/seccomp/seccomp_event.c
+++ b/frida_mode/src/seccomp/seccomp_event.c
@@ -10,13 +10,13 @@
 
 int seccomp_event_create(void) {
 
-#ifdef SYS_eventfd
+  #ifdef SYS_eventfd
   int fd = syscall(SYS_eventfd, 0, 0);
-#else
-# ifdef SYS_eventfd2
+  #else
+    #ifdef SYS_eventfd2
   int fd = syscall(SYS_eventfd2, 0, 0);
-# endif
-#endif
+    #endif
+  #endif
   if (fd < 0) { FFATAL("seccomp_event_create"); }
   return fd;
 
diff --git a/frida_mode/src/seccomp/seccomp_filter.c b/frida_mode/src/seccomp/seccomp_filter.c
index 5aee398f..1d050303 100644
--- a/frida_mode/src/seccomp/seccomp_filter.c
+++ b/frida_mode/src/seccomp/seccomp_filter.c
@@ -72,13 +72,13 @@ static struct sock_filter filter[] = {
 
     /* Allow us to make anonymous maps */
     BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
-#ifdef __NR_mmap
+  #ifdef __NR_mmap
     BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap, 0, 3),
-#else
-# ifdef __NR_mmap2
+  #else
+    #ifdef __NR_mmap2
     BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap2, 0, 3),
-# endif
-#endif
+    #endif
+  #endif
     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),
diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c
index b4dd5a47..caa16b3f 100644
--- a/frida_mode/src/stalker.c
+++ b/frida_mode/src/stalker.c
@@ -61,9 +61,10 @@ void stalker_config(void) {
 
   backpatch_enable = (getenv("AFL_FRIDA_INST_NO_BACKPATCH") == NULL);
 
-  stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_ADJACENT_BLOCKS");
+  stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES", 32);
 
-  stalker_adjacent_blocks = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES");
+  stalker_adjacent_blocks =
+      util_read_num("AFL_FRIDA_STALKER_ADJACENT_BLOCKS", 32);
 
   observer = g_object_new(GUM_TYPE_AFL_STALKER_OBSERVER, NULL);
 
@@ -98,33 +99,32 @@ void stalker_init(void) {
   FOKF("Stalker - adjacent_blocks [%u]", stalker_adjacent_blocks);
 
 #if !(defined(__x86_64__) || defined(__i386__))
-  if (stalker_ic_entries != 0) {
+  if (getenv("AFL_FRIDA_STALKER_IC_ENTRIES") != NULL) {
 
     FFATAL("AFL_FRIDA_STALKER_IC_ENTRIES not supported");
 
   }
 
-  if (stalker_adjacent_blocks != 0) {
+  if (getenv("AFL_FRIDA_STALKER_ADJACENT_BLOCKS") != NULL) {
 
     FFATAL("AFL_FRIDA_STALKER_ADJACENT_BLOCKS not supported");
 
   }
 
 #endif
-  if (stalker_ic_entries == 0) { stalker_ic_entries = 32; }
 
-  if (instrument_coverage_filename == NULL) {
+  if (instrument_coverage_filename != NULL) {
 
-    if (stalker_adjacent_blocks == 0) { stalker_adjacent_blocks = 32; }
-
-  } else {
-
-    if (stalker_adjacent_blocks != 0) {
+    if (getenv("AFL_FRIDA_STALKER_ADJACENT_BLOCKS") != NULL) {
 
       FFATAL(
           "AFL_FRIDA_STALKER_ADJACENT_BLOCKS and AFL_FRIDA_INST_COVERAGE_FILE "
           "are incompatible");
 
+    } else {
+
+      stalker_adjacent_blocks = 0;
+
     }
 
   }
diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c
index a61834d6..83ecf89a 100644
--- a/frida_mode/src/stats/stats.c
+++ b/frida_mode/src/stats/stats.c
@@ -323,7 +323,7 @@ static void stats_observer_init(GumStalkerObserver *observer) {
 void stats_config(void) {
 
   stats_filename = getenv("AFL_FRIDA_STATS_FILE");
-  stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL");
+  stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL", 10);
 
 }
 
@@ -332,7 +332,8 @@ void stats_init(void) {
   FOKF("Stats - file [%s]", stats_filename);
   FOKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval);
 
-  if (stats_interval != 0 && stats_filename == NULL) {
+  if (getenv("AFL_FRIDA_STATS_INTERVAL") != NULL &&
+      getenv("AFL_FRIDA_STATS_FILE") == NULL) {
 
     FFATAL(
         "AFL_FRIDA_STATS_FILE must be specified if "
@@ -340,7 +341,6 @@ void stats_init(void) {
 
   }
 
-  if (stats_interval == 0) { stats_interval = 10; }
   stats_interval_us = stats_interval * MICRO_TO_SEC;
 
   if (stats_filename == NULL) { return; }
diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c
index d84b7065..6f52b6cb 100644
--- a/frida_mode/src/util.c
+++ b/frida_mode/src/util.c
@@ -1,10 +1,11 @@
 #include "util.h"
 
-guint64 util_read_address(char *key) {
+guint64 util_read_address(char *key, guint64 default_value) {
 
   char *value_str = getenv(key);
+  char *end_ptr;
 
-  if (value_str == NULL) { return 0; }
+  if (value_str == NULL) { return default_value; }
 
   if (!g_str_has_prefix(value_str, "0x")) {
 
@@ -25,8 +26,17 @@ guint64 util_read_address(char *key) {
 
   }
 
-  guint64 value = g_ascii_strtoull(value_str2, NULL, 16);
-  if (value == 0) {
+  errno = 0;
+
+  guint64 value = g_ascii_strtoull(value_str2, &end_ptr, 16);
+
+  if (errno != 0) {
+
+    FATAL("Error (%d) during conversion: %s", errno, value_str);
+
+  }
+
+  if (value == 0 && end_ptr == value_str2) {
 
     FATAL("Invalid address failed hex conversion: %s=%s\n", key, value_str2);
 
@@ -36,11 +46,12 @@ guint64 util_read_address(char *key) {
 
 }
 
-guint64 util_read_num(char *key) {
+guint64 util_read_num(char *key, guint64 default_value) {
 
   char *value_str = getenv(key);
+  char *end_ptr;
 
-  if (value_str == NULL) { return 0; }
+  if (value_str == NULL) { return default_value; }
 
   for (char *c = value_str; *c != '\0'; c++) {
 
@@ -53,8 +64,17 @@ guint64 util_read_num(char *key) {
 
   }
 
+  errno = 0;
+
   guint64 value = g_ascii_strtoull(value_str, NULL, 10);
-  if (value == 0) {
+
+  if (errno != 0) {
+
+    FATAL("Error (%d) during conversion: %s", errno, value_str);
+
+  }
+
+  if (value == 0 && end_ptr == value_str) {
 
     FATAL("Invalid address failed numeric conversion: %s=%s\n", key, value_str);
 
diff --git a/frida_mode/test/bloaty/GNUmakefile b/frida_mode/test/bloaty/GNUmakefile
new file mode 100644
index 00000000..7ef4fe81
--- /dev/null
+++ b/frida_mode/test/bloaty/GNUmakefile
@@ -0,0 +1,114 @@
+PWD:=$(shell pwd)/
+ROOT:=$(PWD)../../../
+BUILD_DIR:=$(PWD)build/
+
+AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
+AFLPP_QEMU_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/qemu_hook.so
+
+# LIBFUZZER_LIB:=/usr/lib/llvm-12/lib/libFuzzer.a
+
+BLOATY_GIT_REPO:=https://github.com/google/bloaty.git
+BLOATY_DIR:=$(BUILD_DIR)bloaty/
+TEST_BIN:=$(BLOATY_DIR)fuzz_target
+
+ifeq "$(shell uname)" "Darwin"
+TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie
+endif
+
+TEST_DATA_DIR:=$(BUILD_DIR)in/
+TEST_DATA_SRC:=$(BLOATY_DIR)tests/testdata/fuzz_corpus/
+DUMMY_DATA_FILE:=$(BUILD_DIR)default_seed
+
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+
+ifndef ARCH
+
+ARCH=$(shell uname -m)
+ifeq "$(ARCH)" "aarch64"
+ ARCH:=arm64
+endif
+
+ifeq "$(ARCH)" "i686"
+ ARCH:=x86
+endif
+endif
+
+GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
+
+AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x4000000000)
+
+ifeq "$(ARCH)" "aarch64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000)
+endif
+
+ifeq "$(ARCH)" "x86_64"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000)
+endif
+
+ifeq "$(ARCH)" "x86"
+ AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000)
+endif
+
+.PHONY: all clean frida hook
+
+all: $(TEST_BIN)
+	make -C $(ROOT)frida_mode/
+
+32:
+	CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+########## BLOATY #######
+
+$(BLOATY_DIR): | $(BUILD_DIR)
+	git clone --depth 1 $(BLOATY_GIT_REPO) $@
+
+$(TEST_BIN): $(BLOATY_DIR)
+	cd $(BLOATY_DIR) && CC=clang CXX=clang++ CCC=clang++ LIB_FUZZING_ENGINE="-fsanitize=fuzzer" cmake -G Ninja -DBUILD_TESTING=false $(BLOATY_DIR)
+	cd $(BLOATY_DIR) && CC=clang CXX=clang++ CCC=clang++ ninja -j $(shell nproc)
+
+########## DUMMY #######
+
+$(TEST_DATA_DIR): | $(BLOATY_DIR) $(BUILD_DIR)
+	cp -av $(TEST_DATA_SRC) $@
+
+$(DUMMY_DATA_FILE): | $(TEST_DATA_DIR)
+	dd if=/dev/zero bs=1048576 count=1 of=$@
+
+###### TEST DATA #######
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+frida: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE)
+	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) \
+	$(ROOT)afl-fuzz \
+		-i $(TEST_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-m none \
+		-d \
+		-O \
+		-V 30 \
+		-- \
+			$(TEST_BIN) $(DUMMY_DATA_FILE)
+
+qemu: $(TEST_BIN) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE)
+	AFL_QEMU_PERSISTENT_CNT=1000000 \
+	AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_QEMU_DRIVER_HOOK_OBJ) \
+	AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-i $(TEST_DATA_DIR) \
+		-o $(QEMU_OUT) \
+		-m none \
+		-d \
+		-Q \
+		-V 30 \
+		-- \
+			$(TEST_BIN) $(DUMMY_DATA_FILE)
diff --git a/frida_mode/test/bloaty/Makefile b/frida_mode/test/bloaty/Makefile
new file mode 100644
index 00000000..07b139e9
--- /dev/null
+++ b/frida_mode/test/bloaty/Makefile
@@ -0,0 +1,13 @@
+all:
+	@echo trying to use GNU make...
+	@gmake all || echo please install GNUmake
+
+32:
+	@echo trying to use GNU make...
+	@gmake 32 || echo please install GNUmake
+
+clean:
+	@gmake clean
+
+frida:
+	@gmake frida
diff --git a/frida_mode/test/bloaty/get_symbol_addr.py b/frida_mode/test/bloaty/get_symbol_addr.py
new file mode 100755
index 00000000..1c46e010
--- /dev/null
+++ b/frida_mode/test/bloaty/get_symbol_addr.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import argparse
+from elftools.elf.elffile import ELFFile
+
+def process_file(file, symbol, base):
+    with open(file, 'rb') as f:
+        elf = ELFFile(f)
+        symtab = elf.get_section_by_name('.symtab')
+        mains = symtab.get_symbol_by_name(symbol)
+        if len(mains) != 1:
+            print ("Failed to find main")
+            return 1
+
+        main_addr = mains[0]['st_value']
+        main = base + main_addr
+        print ("0x%016x" % main)
+        return 0
+
+def hex_value(x):
+    return int(x, 16)
+
+def main():
+    parser = argparse.ArgumentParser(description='Process some integers.')
+    parser.add_argument('-f', '--file', dest='file', type=str,
+                    help='elf file name', required=True)
+    parser.add_argument('-s', '--symbol', dest='symbol', type=str,
+                    help='symbol name', required=True)
+    parser.add_argument('-b', '--base', dest='base', type=hex_value,
+                    help='elf base address', required=True)
+
+    args = parser.parse_args()
+    return process_file (args.file, args.symbol, args.base)
+
+if __name__ == "__main__":
+    ret = main()
+    exit(ret)