added frida gum extension

This commit is contained in:
van Hauser
2020-07-14 23:26:11 +02:00
parent 95276f7da6
commit 383b280531
9 changed files with 525 additions and 40 deletions

View File

@ -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*

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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>

View File

@ -266,6 +266,8 @@ int main(int argc, char **argv_orig, char **envp) {
gettimeofday(&tv, &tz);
rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
while ((opt = getopt(argc, argv,
"+c:i:I:o:f:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) >
0) {
@ -563,7 +565,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
afl->fsrv.qemu_mode = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
@ -580,7 +581,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
afl->unicorn_mode = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; }
@ -591,7 +591,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
afl->fsrv.qemu_mode = 1;
afl->use_wine = 1;
afl->shmem_testcase_mode = 1;
if (!mem_limit_given) { afl->fsrv.mem_limit = 0; }

View File

@ -1,18 +1,20 @@
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int main(void) {
long double magic;
ssize_t bytes_read = read(STDIN_FILENO, &magic, sizeof(magic));
if (bytes_read < (ssize_t)sizeof(magic)) {
return 1;
}
if (bytes_read < (ssize_t)sizeof(magic)) { return 1; }
if( (-magic == 15.0 + 0.5 + 0.125 + 0.03125 + 0.0078125) ){ /* 15 + 1/2 + 1/8 + 1/32 + 1/128 */
if ((-magic == 15.0 + 0.5 + 0.125 + 0.03125 +
0.0078125)) { /* 15 + 1/2 + 1/8 + 1/32 + 1/128 */
abort();
}
return 0;
}

View File

@ -4,13 +4,14 @@
* or -DFLOAT_TYPE="long double"
*/
#include <assert.h>
int main() {
volatile FLOAT_TYPE a,b;
volatile FLOAT_TYPE a, b;
/* different values */
a = -2.1; b = -2; /* signs equal, exp equal, mantissa > */
a = -2.1;
b = -2; /* signs equal, exp equal, mantissa > */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -18,7 +19,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 1.8; b = 2.1; /* signs equal, exp differ, mantissa > */
a = 1.8;
b = 2.1; /* signs equal, exp differ, mantissa > */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -26,7 +28,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 2; b = 2.1; /* signs equal, exp equal, mantissa < */
a = 2;
b = 2.1; /* signs equal, exp equal, mantissa < */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -34,7 +37,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -2; b = -1.8; /* signs equal, exp differ, mantissa < */
a = -2;
b = -1.8; /* signs equal, exp differ, mantissa < */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -42,7 +46,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -1; b = 1; /* signs differ, exp equal, mantissa equal */
a = -1;
b = 1; /* signs differ, exp equal, mantissa equal */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -50,7 +55,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -1; b = 0; /* signs differ, exp differ, mantissa equal */
a = -1;
b = 0; /* signs differ, exp differ, mantissa equal */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -58,7 +64,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -2; b = 2.8; /* signs differ, exp equal, mantissa < */
a = -2;
b = 2.8; /* signs differ, exp equal, mantissa < */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -66,7 +73,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -2; b = 1.8; /* signs differ, exp differ, mantissa < */
a = -2;
b = 1.8; /* signs differ, exp differ, mantissa < */
assert((a < b));
assert((a <= b));
assert(!(a > b));
@ -74,8 +82,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -2; b = -2.1; /* signs equal, exp equal, mantissa > */
a = -2;
b = -2.1; /* signs equal, exp equal, mantissa > */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -83,7 +91,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 2.1; b = 1.8; /* signs equal, exp differ, mantissa > */
a = 2.1;
b = 1.8; /* signs equal, exp differ, mantissa > */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -91,7 +100,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 2.1; b = 2; /* signs equal, exp equal, mantissa < */
a = 2.1;
b = 2; /* signs equal, exp equal, mantissa < */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -99,7 +109,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = -1.8; b = -2; /* signs equal, exp differ, mantissa < */
a = -1.8;
b = -2; /* signs equal, exp differ, mantissa < */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -107,7 +118,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 1; b = -1; /* signs differ, exp equal, mantissa equal */
a = 1;
b = -1; /* signs differ, exp equal, mantissa equal */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -115,7 +127,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 0; b = -1; /* signs differ, exp differ, mantissa equal */
a = 0;
b = -1; /* signs differ, exp differ, mantissa equal */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -123,7 +136,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 2.8; b = -2; /* signs differ, exp equal, mantissa < */
a = 2.8;
b = -2; /* signs differ, exp equal, mantissa < */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -131,7 +145,8 @@ int main() {
assert((a != b));
assert(!(a == b));
a = 1.8; b = -2; /* signs differ, exp differ, mantissa < */
a = 1.8;
b = -2; /* signs differ, exp differ, mantissa < */
assert((a > b));
assert((a >= b));
assert(!(a < b));
@ -140,7 +155,8 @@ int main() {
assert(!(a == b));
/* equal values */
a = 0; b = 0;
a = 0;
b = 0;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
@ -148,7 +164,8 @@ int main() {
assert(!(a != b));
assert((a == b));
a = -0; b = 0;
a = -0;
b = 0;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
@ -156,7 +173,8 @@ int main() {
assert(!(a != b));
assert((a == b));
a = 1; b = 1;
a = 1;
b = 1;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
@ -164,7 +182,8 @@ int main() {
assert(!(a != b));
assert((a == b));
a = 0.5; b = 0.5;
a = 0.5;
b = 0.5;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
@ -172,7 +191,8 @@ int main() {
assert(!(a != b));
assert((a == b));
a = -1; b = -1;
a = -1;
b = -1;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
@ -180,11 +200,14 @@ int main() {
assert(!(a != b));
assert((a == b));
a = -0.5; b = -0.5;
a = -0.5;
b = -0.5;
assert(!(a < b));
assert((a <= b));
assert(!(a > b));
assert((a >= b));
assert(!(a != b));
assert((a == b));
}