diff options
author | van Hauser <vh@thc.org> | 2020-07-14 23:26:11 +0200 |
---|---|---|
committer | van Hauser <vh@thc.org> | 2020-07-14 23:26:11 +0200 |
commit | 383b280531a92a8b81d112a9acb4e44c08987be0 (patch) | |
tree | 1d23c9fb0762e62db06a5a3f856387f255f700b5 /examples | |
parent | 95276f7da6ed9dd72556236f505a8997bee23387 (diff) | |
download | afl++-383b280531a92a8b81d112a9acb4e44c08987be0.tar.gz |
added frida gum extension
Diffstat (limited to 'examples')
-rw-r--r-- | examples/afl_frida/Makefile | 23 | ||||
-rw-r--r-- | examples/afl_frida/README.md | 38 | ||||
-rw-r--r-- | examples/afl_frida/afl-frida.c | 312 | ||||
-rw-r--r-- | examples/afl_frida/afl-frida.h | 53 | ||||
-rw-r--r-- | examples/afl_frida/libtestinstr.c | 35 | ||||
-rw-r--r-- | examples/afl_network_proxy/afl-network-client.c | 2 |
6 files changed, 462 insertions, 1 deletions
diff --git a/examples/afl_frida/Makefile b/examples/afl_frida/Makefile new file mode 100644 index 00000000..5d482e54 --- /dev/null +++ b/examples/afl_frida/Makefile @@ -0,0 +1,23 @@ +ifdef DEBUG + OPT=-O0 -D_DEBUG=\"1\" +else + OPT=-O3 -funroll-loops +endif + +all: afl-frida libtestinstr.so + +libfrida-gum.a: + @echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest + @exit 1 + +afl-frida: afl-frida.c libfrida-gum.a + $(CC) -g $(OPT) -o afl-frida -I. -fpermissive -fPIC afl-frida.c ../../afl-llvm-rt.o libfrida-gum.a -ldl -lresolv -pthread + +libtestinstr.so: libtestinstr.c + $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c + +clean: + rm -f afl-frida *~ core *.o libtestinstr.so + +deepclean: clean + rm -f libfrida-gum.a frida-gum* diff --git a/examples/afl_frida/README.md b/examples/afl_frida/README.md new file mode 100644 index 00000000..93e8f35a --- /dev/null +++ b/examples/afl_frida/README.md @@ -0,0 +1,38 @@ +# afl-frida - faster fuzzing of binary-only libraries + +## Introduction + +afl-frida is an example skeleton file which can easily be used to fuzz +a closed source library. + +It requires less memory and is x5-10 faster than qemu_mode but does not +provide interesting features like compcov or cmplog. + +## How-to + +### Modify afl-frida.c + +Read and modify afl-frida.c then `make`. +To adapt afl-frida.c to your needs, read the header of the file and then +search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. + +### Fuzzing + +Example (after modifying afl-frida.c to your needs and compile it): +``` +afl-fuzz -i in -o out -- ./afl-frida +``` +(or even remote via afl-network-proxy). + +### Testing and debugging + +For testing/debugging you can try: +``` +make DEBUG=1 +AFL_DEBUG=1 gdb ./afl-frida +``` +and then you can easily set breakpoints to "breakpoint" and "fuzz". + +# Background + +This code ist copied for a larger part from https://github.com/meme/hotwax diff --git a/examples/afl_frida/afl-frida.c b/examples/afl_frida/afl-frida.c new file mode 100644 index 00000000..c24e05b7 --- /dev/null +++ b/examples/afl_frida/afl-frida.c @@ -0,0 +1,312 @@ +/* + american fuzzy lop++ - afl-frida skeleton example + ------------------------------------------------- + + Copyright 2020 AFLplusplus Project. All rights reserved. + + Written mostly by meme -> https://github.com/meme/hotwax + + Modificationy by Marc Heuse <mh@mh-sec.de> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + HOW-TO + ====== + + You only need to change the following: + + 1. set the defines and function call parameters. + 2. dl load the library you want to fuzz, lookup the functions you need + and setup the calls to these. + 3. in the while loop you call the functions in the necessary order - + incl the cleanup. the cleanup is important! + + Just look these steps up in the code, look for "// STEP x:" + +*/ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <stdint.h> +#include <stddef.h> +#include <sys/shm.h> +#include <dlfcn.h> + +#ifndef __APPLE__ + #include <sys/wait.h> +#endif + + +// STEP 1: + +// The presets are for the example libtestinstr.so: + +/* What is the name of the library to fuzz */ +#define TARGET_LIBRARY "libtestinstr.so" + +/* What is the name of the function to fuzz */ +#define TARGET_FUNCTION "testinstr" + +/* here you need to specify the parameter for the target function */ +static void *(*o_function)(uint8_t *, int); + +// END STEP 1 + + +#include "frida-gum.h" + +G_BEGIN_DECLS + +#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) +G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, + FAKE_EVENT_SINK, GObject) + +struct _GumFakeEventSink { + + GObject parent; + GumEventType mask; + +}; + +GumEventSink *gum_fake_event_sink_new(void); +void gum_fake_event_sink_reset(GumFakeEventSink *self); + +G_END_DECLS + +static void gum_fake_event_sink_iface_init(gpointer g_iface, + gpointer iface_data); +static void gum_fake_event_sink_finalize(GObject *obj); +static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink); +static void gum_fake_event_sink_process(GumEventSink *sink, const GumEvent *ev); +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); +void afl_setup(void); +void afl_start_forkserver(void); +int __afl_persistent_loop(unsigned int max_cnt); + +static void gum_fake_event_sink_class_init(GumFakeEventSinkClass *klass) { + + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->finalize = gum_fake_event_sink_finalize; + +} + +static void gum_fake_event_sink_iface_init(gpointer g_iface, + gpointer iface_data) { + + GumEventSinkInterface *iface = (GumEventSinkInterface *) g_iface; + iface->query_mask = gum_fake_event_sink_query_mask; + iface->process = gum_fake_event_sink_process; + +} + +G_DEFINE_TYPE_EXTENDED(GumFakeEventSink, gum_fake_event_sink, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE(GUM_TYPE_EVENT_SINK, + gum_fake_event_sink_iface_init)) + +#include "../../config.h" + +// Shared memory fuzzing. +int __afl_sharedmem_fuzzing = 1; +extern unsigned int *__afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +int __afl_persistent_loop(unsigned int); + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +void __afl_manual_init(); + +// Because we do our own logging. +extern uint8_t * __afl_area_ptr; + +// Frida stuff below. +typedef struct { + + GumAddress base_address; + guint64 code_start, code_end; + +} range_t; + +inline static void afl_maybe_log(guint64 current_pc) { + + static __thread guint64 previous_pc; + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + __afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + +static void on_basic_block(GumCpuContext *context, gpointer user_data) { + + afl_maybe_log((guint64)user_data); + +} + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data) { + + range_t *range = (range_t *)user_data; + + const cs_insn *instr; + gboolean begin = TRUE; + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (begin) { + + guint64 current_pc = instr->address - range->base_address; + gum_stalker_iterator_put_callout(iterator, on_basic_block, + (gpointer)current_pc, NULL); + begin = FALSE; + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +static void gum_fake_event_sink_init(GumFakeEventSink *self) { } + +static void gum_fake_event_sink_finalize(GObject *obj) { + + G_OBJECT_CLASS(gum_fake_event_sink_parent_class)->finalize(obj); + +} + +GumEventSink *gum_fake_event_sink_new(void) { + + GumFakeEventSink *sink; + sink = (GumFakeEventSink *) g_object_new(GUM_TYPE_FAKE_EVENT_SINK, NULL); + return GUM_EVENT_SINK(sink); + +} + +void gum_fake_event_sink_reset(GumFakeEventSink *self) { } + +static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink) { + + return 0; + +} + +static void gum_fake_event_sink_process(GumEventSink * sink, + const GumEvent *ev) { } + +/* Because this CAN be called more than once, it will return the LAST range */ +static int enumerate_ranges(const GumRangeDetails *details, + gpointer user_data) { + + GumMemoryRange *code_range = (GumMemoryRange *)user_data; + memcpy(code_range, details->range, sizeof(*code_range)); + return 0; + +} + +int main() { + + // STEP 2: load the library you want to fuzz and lookup the functions, + // inclusive of the cleanup functions. + // If there is just one function, then there is nothing to change + // or add here. + + void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + if (!dl) { + + fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); + exit(-1); + + } + + if (!(o_function = dlsym(dl, TARGET_FUNCTION))) { + + fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); + exit(-1); + + } + + // END STEP 2 + + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + return 1; + + } + + GumStalker *stalker = gum_stalker_new(); + + GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY); + + GumMemoryRange code_range; + gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, + &code_range); + guint64 code_start = code_range.base_address - base_address; + guint64 code_end = (code_range.base_address + code_range.size) - base_address; + + range_t instr_range = {base_address, code_start, code_end}; + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, + &instr_range, NULL); + + GumEventSink *event_sink = gum_fake_event_sink_new(); + + __afl_manual_init(); + + // + // any expensive target library initialization that has to be done just once + // - put that here + // + + gum_stalker_follow_me(stalker, transformer, event_sink); + + while (__afl_persistent_loop(UINT32_MAX) != 0) { + +#ifdef _DEBUG + fprintf(stderr, "CLIENT crc: %016llx len: %u\n", hash64(__afl_fuzz_ptr, *__a + fprintf(stderr, "RECV:"); + for (int i = 0; i < *__afl_fuzz_len; i++) + fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); + fprintf(stderr,"\n"); +#endif + + // STEP 3: ensure the minimum length is present and setup the target + // function to fuzz. + + if (*__afl_fuzz_len > 0) { + + __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate + (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + + // END STEP 3 + + } + + gum_stalker_unfollow_me(stalker); + + while (gum_stalker_garbage_collect(stalker)) + g_usleep(10000); + + g_object_unref(stalker); + g_object_unref(transformer); + g_object_unref(event_sink); + gum_deinit_embedded(); + + return 0; + +} diff --git a/examples/afl_frida/afl-frida.h b/examples/afl_frida/afl-frida.h new file mode 100644 index 00000000..efa3440f --- /dev/null +++ b/examples/afl_frida/afl-frida.h @@ -0,0 +1,53 @@ +extern int is_persistent; + +G_BEGIN_DECLS + +#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) + +G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, + FAKE_EVENT_SINK, GObject) + +struct _GumFakeEventSink { + + GObject parent; + GumEventType mask; + +}; + +GumEventSink *gum_fake_event_sink_new(void); +void gum_fake_event_sink_reset(GumFakeEventSink *self); + +G_END_DECLS + +typedef struct { + + GumAddress base_address; + guint64 code_start, code_end; + +} range_t; + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); +#pragma once + +void afl_setup(void); +void afl_start_forkserver(void); +int __afl_persistent_loop(unsigned int max_cnt); + +inline static inline void afl_maybe_log(guint64 current_pc) { + + extern unsigned int afl_instr_rms; + extern uint8_t * afl_area_ptr; + + static __thread guint64 previous_pc; + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + if (current_pc >= afl_instr_rms) return; + + afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + diff --git a/examples/afl_frida/libtestinstr.c b/examples/afl_frida/libtestinstr.c new file mode 100644 index 00000000..96b1cf21 --- /dev/null +++ b/examples/afl_frida/libtestinstr.c @@ -0,0 +1,35 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index 7c4d8b35..a2451fdc 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -35,7 +35,7 @@ #include <arpa/inet.h> #include <sys/mman.h> #ifndef USEMMAP -#include <sys/shm.h> + #include <sys/shm.h> #endif #include <sys/wait.h> #include <sys/types.h> |