Merge pull request #1410 from WorksButNotTested/dynamic

A few updates
This commit is contained in:
van Hauser 2022-05-16 11:15:21 +02:00 committed by GitHub
commit c08eeb95ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 320 additions and 4 deletions

View File

@ -116,7 +116,7 @@ ifndef OS
$(error "Operating system unsupported")
endif
GUM_DEVKIT_VERSION=15.1.15
GUM_DEVKIT_VERSION=15.1.22
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)"

View File

@ -157,11 +157,13 @@ static gboolean instrument_is_deterministic(const cs_insn *from_insn) {
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn * from_insn,
gpointer * target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
gsize fixup_offset;

View File

@ -172,12 +172,13 @@ void instrument_coverage_optimize_init(void) {
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn * from_insn,
gpointer * target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(start_address);
UNUSED_PARAMETER(from_address);
cs_x86 * x86;
cs_x86_op *op;

View File

@ -84,11 +84,13 @@ gboolean instrument_is_coverage_optimize_supported(void) {
}
static void instrument_coverage_switch(GumStalkerObserver *self,
gpointer from_address,
gpointer start_address,
const cs_insn * from_insn,
gpointer * target) {
UNUSED_PARAMETER(self);
UNUSED_PARAMETER(from_address);
UNUSED_PARAMETER(start_address);
cs_x86 * x86;

View File

@ -32,6 +32,8 @@ gboolean prefetch_backpatch = TRUE;
static prefetch_data_t *prefetch_data = NULL;
static int prefetch_shm_id = -1;
static GHashTable *cant_prefetch = NULL;
static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
const GumBackpatch *backpatch,
gsize size) {
@ -40,6 +42,18 @@ static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
if (!entry_run) { return; }
gsize remaining =
sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size;
gpointer from = gum_stalker_backpatch_get_from(backpatch);
gpointer to = gum_stalker_backpatch_get_to(backpatch);
/* Stop reporting patches which can't be prefetched */
if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(from)) ||
g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(to))) {
return;
}
if (sizeof(gsize) + size > remaining) { return; }
gsize *dst_backpatch_size =
@ -68,6 +82,9 @@ void prefetch_write(void *addr) {
/* Bail if we aren't initialized */
if (prefetch_data == NULL) return;
/* Stop reporting blocks which can't be prefetched */
if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(addr))) { return; }
/*
* Our shared memory IPC is large enough for about 1000 entries, we can fine
* tune this if we need to. But if we have more new blocks that this in a
@ -84,6 +101,38 @@ void prefetch_write(void *addr) {
}
typedef struct {
GumAddress address;
gboolean executable;
} check_executable_t;
static gboolean prefetch_find_executable(const GumRangeDetails *details,
gpointer user_data) {
check_executable_t *ctx = (check_executable_t *)user_data;
if (GUM_MEMORY_RANGE_INCLUDES(details->range, ctx->address)) {
ctx->executable = TRUE;
return FALSE;
}
return TRUE;
}
static gboolean prefetch_is_executable(void *address) {
check_executable_t ctx = {.address = GUM_ADDRESS(address),
.executable = FALSE};
gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, prefetch_find_executable,
&ctx);
return ctx.executable;
}
static void prefetch_read_blocks(void) {
GumStalker *stalker = stalker_get();
@ -92,7 +141,24 @@ static void prefetch_read_blocks(void) {
for (size_t i = 0; i < prefetch_data->count; i++) {
void *addr = prefetch_data->entry[i];
gum_stalker_prefetch(stalker, addr, 1);
if (prefetch_is_executable(addr)) {
gum_stalker_prefetch(stalker, addr, 1);
} else {
/*
* If our child process creates a new executable mapping, e.g. by
* dynamically loading a new DSO, then this won't appear in our parent
* process' memory map and hence we can't prefetch it. Add it to a
* hashtable which the child will inherit on the next fork to prevent the
* child from keep reporting it and exhausting the shared memory buffers
* used to pass new blocks from the child back to the parent.
*/
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(addr));
}
}
@ -125,7 +191,36 @@ static void prefetch_read_patches(void) {
}
backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset];
gum_stalker_prefetch_backpatch(stalker, backpatch);
gpointer from = gum_stalker_backpatch_get_from(backpatch);
gpointer to = gum_stalker_backpatch_get_to(backpatch);
/*
* If our child process creates a new executable mapping, e.g. by
* dynamically loading a new DSO, then this won't appear in our parent
* process' memory map and hence we can't prefetch it. Add it to a
* hashtable which the child will inherit on the next fork to prevent the
* child from keep reporting it and exhausting the shared memory buffers
* used to pass new blocks from the child back to the parent.
*/
if (!prefetch_is_executable(from)) {
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(from));
}
if (!prefetch_is_executable(to)) {
g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(to));
}
if (prefetch_is_executable(from) && prefetch_is_executable(to)) {
gum_stalker_prefetch_backpatch(stalker, backpatch);
}
offset += size;
}
@ -215,6 +310,13 @@ void prefetch_init(void) {
prefetch_hook_fork();
cant_prefetch = g_hash_table_new(g_direct_hash, g_direct_equal);
if (cant_prefetch == NULL) {
FFATAL("Failed to g_hash_table_new, errno: %d", errno);
}
if (!prefetch_backpatch) { return; }
GumStalkerObserver * observer = stalker_get_observer();

View File

@ -131,6 +131,8 @@ void stalker_init(void) {
}
gum_stalker_activate_experimental_unwind_support();
#if defined(__x86_64__) || defined(__i386__)
stalker = g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries,
"adjacent-blocks", stalker_adjacent_blocks, NULL);

View File

@ -0,0 +1,76 @@
PWD:=$(shell pwd)/
ROOT:=$(PWD)../../../
BUILD_DIR:=$(PWD)build/
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)dummy.dat
TESTINSTBIN:=$(BUILD_DIR)testinstr
TESTINSTSRC:=$(PWD)testinstr.c
TESTINSTLIB:=$(BUILD_DIR)testinstrlib.so
TESTINSTLIBSRC:=$(PWD)testinstrlib.c
QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
ADDR_BIN:=$(ROOT)frida_mode/build/addr
GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN))
AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) testinstr $(AFL_FRIDA_BASE_ADDR))
CFLAGS+=-D_GNU_SOURCE=1
LDFLAGS+=-ldl
.PHONY: all clean qemu frida
all: $(TESTINSTBIN) $(TESTINSTLIB)
make -C $(ROOT)frida_mode/
$(BUILD_DIR):
mkdir -p $@
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
dd if=/dev/zero bs=1048576 count=1 of=$@
$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
mkdir -p $@
$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
echo -n "000" > $@
$(TESTINSTLIB): $(TESTINSTLIBSRC) | $(BUILD_DIR)
$(CC) \
$(CFLAGS) \
-shared \
-o $@ \
$(LDFLAGS) \
$<
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
$(CC) \
$(CFLAGS) \
-o $@ \
$< \
$(LDFLAGS) \
-Wl,-rpath,'$$ORIGIN'
clean:
rm -rf $(BUILD_DIR)
frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) $(AFLPP_DRIVER_DUMMY_INPUT)
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 \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) $(AFLPP_DRIVER_DUMMY_INPUT)

View File

@ -0,0 +1,19 @@
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
qemu:
@gmake qemu
frida:
@gmake frida
debug:
@gmake debug

View File

@ -0,0 +1,98 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2022 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 <dlfcn.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef void (*fntestinstrlib)(char *buf, int len);
void testinstr(char *buf, int len) {
void *lib = dlopen("testinstrlib.so", RTLD_NOW);
if (lib == NULL) {
puts("Library not found");
abort();
}
fntestinstrlib fn = (fntestinstrlib)(dlsym(lib, "testinstrlib"));
if (fn == NULL) {
puts("Function not found");
abort();
}
fn(buf, len);
}
int main(int argc, char **argv) {
char * file;
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
if (argc != 2) { return 1; }
do {
file = argv[1];
printf("file: %s\n", file);
dprintf(STDERR_FILENO, "Running: %s\n", file);
fd = open(file, O_RDONLY);
if (fd < 0) {
perror("open");
break;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
perror("lseek (SEEK_END)");
break;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
perror("lseek (SEEK_SET)");
break;
}
printf("len: %ld\n", len);
buf = malloc(len);
if (buf == NULL) {
perror("malloc");
break;
}
n_read = read(fd, buf, len);
if (n_read != len) {
perror("read");
break;
}
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
testinstr(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
result = 0;
} while (false);
if (buf != NULL) { free(buf); }
if (fd != -1) { close(fd); }
return result;
}

View File

@ -0,0 +1,14 @@
#include <stdio.h>
void testinstrlib(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");
}