mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-08 08:11:34 +00:00
174 lines
3.8 KiB
C
174 lines
3.8 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dlfcn.h>
|
|
#include <glib.h>
|
|
#include "common.h"
|
|
#include "exports.h"
|
|
|
|
void *handle;
|
|
struct conf *config;
|
|
struct conf *(*configure)();
|
|
GByteArray *out;
|
|
void *cpu;
|
|
char cbuf[100];
|
|
|
|
// region GDB Imports
|
|
#pragma region GDB Imports
|
|
void cpu_single_step(void *cpu, int enabled);
|
|
int get_sstep_flags(void);
|
|
void gdb_accept_init(int fd);
|
|
int gdb_breakpoint_insert(int type, unsigned long long addr,
|
|
unsigned long long len);
|
|
int gdb_breakpoint_remove(int type, unsigned long long addr,
|
|
unsigned long long len);
|
|
void *qemu_get_cpu(int index);
|
|
int target_memory_rw_debug(void *cpu, unsigned long long addr, void *ptr,
|
|
unsigned long long len, char is_write);
|
|
int gdb_read_register(void *cs, GByteArray *mem_buf, int n);
|
|
int gdb_write_register(void *cs, char *mem_buf, int n);
|
|
void gdb_set_cpu_pc(unsigned long long pc);
|
|
void gdb_continue(void);
|
|
#pragma endregion GDB Imports
|
|
|
|
// region API
|
|
int r_mem(unsigned long long addr, unsigned long long len, void *dest) {
|
|
|
|
return target_memory_rw_debug(cpu, addr, dest, len, 0);
|
|
|
|
}
|
|
|
|
int w_mem(unsigned long long addr, unsigned long long len, void *src) {
|
|
|
|
return target_memory_rw_debug(cpu, addr, src, len, 1);
|
|
|
|
}
|
|
|
|
int r_reg(unsigned char reg, void *dest) {
|
|
|
|
g_byte_array_steal(out, NULL);
|
|
int op = gdb_read_register(cpu, out, reg);
|
|
memcpy(dest, out->data, out->len);
|
|
return op;
|
|
|
|
}
|
|
|
|
int w_reg(unsigned char reg, char *src) {
|
|
|
|
return gdb_write_register(cpu, src, reg);
|
|
|
|
}
|
|
|
|
// region Breakpoint handling
|
|
char single_stepped;
|
|
unsigned long long gen_addr;
|
|
struct ret *(*hook)();
|
|
struct ret *returned;
|
|
// Defined and imported gdbstub.c
|
|
void set_signal_callback(void (*cb)(int));
|
|
// Breakpoints are set here
|
|
void patch_block_trans_cb(struct qemu_plugin_tb *tb) {
|
|
|
|
unsigned long long addr;
|
|
addr = qemu_plugin_tb_vaddr(tb);
|
|
|
|
if (addr == config->entry_addr) {
|
|
|
|
// NOTE This means we cannot put a BP in the first basic block
|
|
gdb_accept_init(-1);
|
|
for (int i = 0; i < config->num_hooks; i++) {
|
|
|
|
gdb_breakpoint_insert(0, config->hooks[i], 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void handle_signal_callback(int sig) {
|
|
|
|
if (single_stepped) {
|
|
|
|
single_stepped = 0;
|
|
gdb_breakpoint_insert(0, gen_addr, 1);
|
|
cpu_single_step(cpu, 0);
|
|
gdb_continue();
|
|
return;
|
|
|
|
}
|
|
|
|
r_reg(config->IP_reg_num, cbuf);
|
|
gen_addr = *(unsigned long long *)cbuf;
|
|
|
|
sprintf(cbuf, "hook_%016llx", gen_addr);
|
|
// TODO maybe find a way to put the hook function pointers in the TCG data
|
|
// structure instead of this dlsym call
|
|
*(unsigned long long **)(&hook) = dlsym(handle, cbuf);
|
|
if (!hook) {
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
returned = hook();
|
|
|
|
if (returned->remove_bp ||
|
|
(returned->addr ==
|
|
gen_addr)) { //* force removal of bp in returning to the same address,
|
|
//otherwise hook will be called again
|
|
gdb_breakpoint_remove(0, gen_addr, 1);
|
|
|
|
}
|
|
|
|
if (returned->addr == gen_addr) {
|
|
|
|
single_stepped = 1;
|
|
cpu_single_step(cpu, get_sstep_flags());
|
|
|
|
} else {
|
|
|
|
//* no need to rexecute the IP instruction
|
|
gdb_set_cpu_pc(returned->addr);
|
|
|
|
}
|
|
|
|
gdb_continue();
|
|
|
|
}
|
|
|
|
// region Constructor/Destructor
|
|
void patch_finish_cb(void *userdata) {
|
|
|
|
g_byte_array_free(out, 1);
|
|
dlclose(handle);
|
|
|
|
}
|
|
|
|
void patch_vpu_init_cb(unsigned int vcpu_index) {
|
|
|
|
cpu = qemu_get_cpu(vcpu_index);
|
|
|
|
}
|
|
|
|
void patch_init(char *hook_lib) {
|
|
|
|
// TODO make OS agnostic, remove dlopen
|
|
handle = dlopen(hook_lib, RTLD_NOW);
|
|
if (!handle) {
|
|
|
|
fprintf(stderr, "DLOPEN Error: %s\n", dlerror());
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
single_stepped = 0;
|
|
|
|
*(void **)(&configure) = dlsym(handle, "configure");
|
|
config = configure();
|
|
|
|
set_signal_callback(handle_signal_callback);
|
|
out = g_byte_array_new();
|
|
|
|
}
|
|
|