From Practical Software Verification
Compile:
gcc fuzz.c -DLINUX -DSHOW_RESULTS -DX86_32 -fPIC -I/path/to/DR/build/include/ /path/to/DR/build/lib/libdynamorio.so -shared -o fuzz_client
Run:
./drdeploy -v -client /path/to/fuzz_client 0x1 "" netstat
/*
* This is a demo fuzzer to show some of the syscall and signal hooking
* features of DynamoRIO. The code is based on strace.c and signal.c from the DynamoRIO
* distribution. It intercepts read() syscalls and fuzzes the result.
*
* A real fuzzer based off this would probably want to intercept open() calls to
* track what input file the fuzz data came from and probably note the address
* of the instruction to call the read() for debugging purposes. Also allowing the
* user to specify the srand() seed would be useful
*
* To modify this to run on Windows see strace.c/signal.c (and also sort out the
* various glibc calls to whatever Windows alternative you want)
*
* nnp@unprotectedhex.com
* 14 April 2009
*/
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include "dr_api.h"
#define READ_SYSCALL 3
/* Use these to store the paramaters passed to read() */
static int read_count = 0;
static void *read_buf = 0x0;
static int read_fd = 0;
static FILE *fp;
static void event_exit(void);
static bool event_filter_syscall(void *drcontext, int sysnum);
static bool event_pre_syscall(void *drcontext, int sysnum);
static void event_post_syscall(void *drcontext, int sysnum);
static dr_signal_action_t event_signal(void *drcontext, dr_siginfo_t *info);
DR_EXPORT void
dr_init(client_id_t id)
{
fp = fopen("/dev/urandom", "r");
srand(time(0));
/* register events */
dr_register_exit_event(event_exit);
dr_register_filter_syscall_event(event_filter_syscall);
dr_register_pre_syscall_event(event_pre_syscall);
dr_register_post_syscall_event(event_post_syscall);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'taint' initializing\n");
#ifdef SHOW_RESULTS
/* also give notification to stderr */
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client 'taint' running\n");
#endif
}
static dr_signal_action_t
event_signal(void *drcontext, dr_siginfo_t *info)
{
if (info->sig == SIGTERM) {
dr_printf("[!] Program received SIGTERM\n");
} else if (info->sig == SIGSEGV) {
dr_printf("[!] Program received SIGSEGV\n");
}
return DR_SIGNAL_DELIVER;
}
static void
event_exit(void)
{
dr_fprintf(STDERR, "Client 'taint' exiting\n");
fclose(fp);
}
static bool
event_filter_syscall(void *drcontext, int sysnum)
{
if (sysnum == READ_SYSCALL)
return true;
else
return false;
}
static bool
event_pre_syscall(void *drcontext, int sysnum)
{
/* Need to check this because the filter may not be accurate */
if (sysnum == READ_SYSCALL) {
read_fd = dr_syscall_get_param(drcontext, 0);
read_buf = (void*)dr_syscall_get_param(drcontext, 1);
read_count = dr_syscall_get_param(drcontext, 2);
dr_printf("Read syscall (%d); fd : %d, buf : %p, count : %d\n",
sysnum, read_fd, read_buf, read_count);
}
/* returning false means the syscall isn't run */
return true;
}
static void
event_post_syscall(void *drcontext, int sysnum)
{
/* Need to check this because the filter may not be accurate */
if (sysnum == READ_SYSCALL) {
int i, x, buf_len, fuzzed_count, mod_op;
i = x = buf_len = fuzzed_count = mod_op = 0;
/*
* Decide whether to fuzz or not
* Decide whether to max the buffer or not
* Decide what bits to work the flip
* Profit... or fail miserably
*/
buf_len = dr_syscall_get_result(drcontext);
dr_printf("Syscall result %d\n", buf_len);
if (buf_len <= 0)
return;
/* Fuzz approx .5 of the reads, maybe decrease this for programs with many*/
if (!(rand() % 2)) {
dr_printf("[+] Fuzzing...\n");
/* Max out the read buffer */
if(!(rand() % 2) && buf_len < read_count) {
dr_printf("[+] Maxing out the read buffer to %d bytes\n", read_count);
dr_syscall_set_result(drcontext, read_count);
/* Fill the unused space with junk */
if(!(rand() % 2)) {
dr_printf("[+] Filling the remaining %d bytes with junk\n",
read_count - buf_len);
for (i = buf_len; i < read_count; i++) {
((char*)read_buf)[i] = fgetc(fp);
}
}
buf_len = read_count;
}
/* Flip bytes */
for (i = 0; i < buf_len; i++) {
/* Flip 10% */
x = buf_len/10;
mod_op = buf_len/x;
if(!(rand() % mod_op)) {
fuzzed_count++;
((char*)read_buf)[i] = fgetc(fp);
}
}
dr_printf("[+] Fuzzed %d/%d bytes\n", fuzzed_count, buf_len);
}
}
}