* First somewhat working version.

This commit is contained in:
Sam Hocevar 2006-12-15 00:26:01 +00:00 committed by sam
parent e09dc41893
commit c77ff249ed
12 changed files with 471 additions and 142 deletions

5
README
View File

@ -0,0 +1,5 @@
About Zzuf
==========
Zzuf is a transparent application input fuzzer. It works by intercepting
file operations and changing random bits in the program's input.

1
TODO
View File

@ -0,0 +1 @@
* Only very basic support for [f]open/[f]read, no seek, no close, etc.

View File

@ -1,9 +1,9 @@
bin_PROGRAMS = zzuf
zzuf_SOURCES = zzuf.c random.c
zzuf_SOURCES = zzuf.c
pkglib_LTLIBRARIES = libzzuf.la
libzzuf_la_SOURCES = libzzuf.c
libzzuf_la_SOURCES = libzzuf.c libzzuf.h fuzz.c fuzz.h debug.c debug.h preload.c preload.h random.c random.h
libzzuf_la_LDFLAGS = -module
libzzuf_la_LIBADD = -ldl

49
src/debug.c Normal file
View File

@ -0,0 +1,49 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* debug.c: debugging support
*/
#include "config.h"
#if defined HAVE_STDINT_H
# include <stdint.h>
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include "libzzuf.h"
#include "debug.h"
void zzuf_debug(const char *format, ...)
{
va_list args;
int saved_errno;
if(!_zzuf_debug)
return;
saved_errno = errno;
va_start(args, format);
fprintf(stderr, "** zzuf debug ** ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
errno = saved_errno;
}

21
src/debug.h Normal file
View File

@ -0,0 +1,21 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* debug.h: debugging support
*/
extern void zzuf_debug(const char *format, ...);
#define debug zzuf_debug

75
src/fuzz.c Normal file
View File

@ -0,0 +1,75 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* fuzz.c: fuzz functions
*/
#include "config.h"
#if defined HAVE_STDINT_H
# include <stdint.h>
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <string.h>
#include "libzzuf.h"
#include "debug.h"
#include "random.h"
#include "fuzz.h"
#define CHUNK_SIZE 1024
void zzuf_fuzz(int fd, uint8_t *buf, uint64_t len)
{
uint8_t bits[CHUNK_SIZE];
uint64_t pos;
unsigned int i;
if(!files[fd].managed)
return;
pos = files[fd].pos;
debug("fuzzing %lu bytes", (unsigned long int)len);
debug("offset is %lu", (unsigned long int)pos);
for(i = pos / CHUNK_SIZE; i < (pos + len) / CHUNK_SIZE + 1; i++)
{
uint64_t offset;
int todo;
offset = i * CHUNK_SIZE;
todo = _zzuf_percent * CHUNK_SIZE;
zzuf_srand(_zzuf_seed ^ (i * 0x23ea84f7) ^ (todo * 0x783bc31f));
memset(bits, 0, CHUNK_SIZE);
while(todo--)
{
int idx = zzuf_rand(CHUNK_SIZE);
uint8_t byte = (1 << zzuf_rand(8));
if(offset + idx < pos)
continue;
if(offset + idx >= pos + len)
continue;
buf[idx] ^= byte;
}
}
}

20
src/fuzz.h Normal file
View File

@ -0,0 +1,20 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* fuzz.h: fuzz functions
*/
extern void zzuf_fuzz(int, uint8_t *, uint64_t);

View File

@ -25,93 +25,66 @@
# include <inttypes.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <dlfcn.h>
#define STR(x) #x
#define ORIG(x) x##_orig
#define LOADSYM(x) \
do { \
ORIG(x) = dlsym(RTLD_NEXT, STR(x)); \
if(!ORIG(x)) \
{ \
debug("could not load %s", STR(x)); \
abort(); \
} \
} while(0)
#include "libzzuf.h"
#include "debug.h"
#include "preload.h"
static int do_debug = 0;
static void debug(const char *format, ...)
{
if(!do_debug)
return;
/* Global variables */
int _zzuf_debug = 0;
int _zzuf_seed = 0;
float _zzuf_percent = 0.04f;
va_list args;
va_start(args, format);
fprintf(stderr, "** zzuf debug ** ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
}
/* Library functions that we divert */
static FILE * (*fopen_orig) (const char *path, const char *mode);
static int (*open_orig) (const char *file, int oflag, ...);
static int (*open64_orig) (const char *file, int oflag, ...);
#define MAXFD 1024
struct zzuf files[MAXFD];
/* Library initialisation shit */
void zzufinit(void) __attribute__((constructor));
void zzufinit(void)
void zzuf_init(void)
{
char *tmp;
int i;
LOADSYM(fopen);
LOADSYM(open);
LOADSYM(open64);
if(zzuf_preload())
abort();
tmp = getenv("ZZUF_DEBUG");
if(tmp && *tmp)
do_debug = 1;
_zzuf_debug = 1;
tmp = getenv("ZZUF_SEED");
if(tmp && *tmp)
_zzuf_seed = atol(tmp);
tmp = getenv("ZZUF_PERCENT");
if(tmp && *tmp)
_zzuf_percent = atof(tmp);
if(_zzuf_percent < 0.0f)
_zzuf_percent = 0.0f;
else if(_zzuf_percent > 1.0f)
_zzuf_percent = 1.0f;
for(i = 0; i < MAXFD; i++)
files[i].managed = 0;
}
/* Our function wrappers */
FILE *fopen(const char *path, const char *mode)
/* Deinitialisation */
void zzuf_fini(void)
{
debug("fopen(\"%s\", \"%s\");", path, mode);
return fopen_orig(path, mode);
}
#define OPEN(ret, fn, file, oflag) \
do { if(oflag & O_CREAT) \
{ \
int mode; \
va_list va; \
va_start(va, oflag); \
mode = va_arg(va, int); \
va_end(va); \
debug(STR(fn) "(\"%s\", %i, %i);", file, oflag, mode); \
ret = ORIG(fn)(file, oflag, mode); \
} \
else \
{ \
debug(STR(fn) "(\"%s\", %i);", file, oflag); \
ret = ORIG(fn)(file, oflag); \
} } while(0)
int open(const char *file, int oflag, ...)
{
int ret;
OPEN(ret, open, file, oflag);
return ret;
}
int open64(const char *file, int oflag, ...)
{
int ret;
OPEN(ret, open64, file, oflag);
return ret;
int i;
for(i = 0; i < MAXFD; i++)
{
if(!files[i].managed)
continue;
/* TODO */
}
}

37
src/libzzuf.h Normal file
View File

@ -0,0 +1,37 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* libzzuf.h: preloaded wrapper library
*/
struct zzuf
{
int managed;
uint64_t seed;
uint64_t pos;
char *data;
};
extern struct zzuf files[];
/* Internal stuff */
extern int _zzuf_debug;
extern int _zzuf_seed;
extern float _zzuf_percent;
/* Library initialisation shit */
extern void zzuf_init(void) __attribute__((constructor));
extern void zzuf_fini(void) __attribute__((destructor));

154
src/preload.c Normal file
View File

@ -0,0 +1,154 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* preload.c: preloaded library functions
*/
#include "config.h"
#define _GNU_SOURCE
#if defined HAVE_STDINT_H
# include <stdint.h>
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <dlfcn.h>
#include "libzzuf.h"
#include "debug.h"
#include "fuzz.h"
#include "preload.h"
/* Library functions that we divert */
static FILE * (*fopen_orig) (const char *path, const char *mode);
static size_t (*fread_orig) (void *ptr, size_t size, size_t nmemb, FILE *stream);
static int (*open_orig) (const char *file, int oflag, ...);
static int (*open64_orig) (const char *file, int oflag, ...);
static ssize_t (*read_orig) (int fd, void *buf, size_t count);
#define STR(x) #x
#define ORIG(x) x##_orig
#define LOADSYM(x) \
do { \
ORIG(x) = dlsym(RTLD_NEXT, STR(x)); \
if(!ORIG(x)) \
return -1; \
} while(0)
int zzuf_preload(void)
{
LOADSYM(fopen);
LOADSYM(fread);
LOADSYM(open);
LOADSYM(open64);
LOADSYM(read);
debug("libzzuf initialised");
return 0;
}
/* Our function wrappers */
FILE *fopen(const char *path, const char *mode)
{
FILE *f;
f = fopen_orig(path, mode);
debug("fopen(\"%s\", \"%s\") = %p", path, mode, f);
if(!f)
return NULL;
files[fileno(f)].managed = 1;
files[fileno(f)].pos = 0;
return f;
}
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t ret = fread_orig(ptr, size, nmemb, stream);
debug("fread(%p, %li, %li, \"%s\") = %li",
ptr, (long int)size, (long int)nmemb, stream, (long int)ret);
if(ret > 0)
{
zzuf_fuzz(fileno(stream), ptr, ret * size);
files[fileno(stream)].pos += ret * size;
}
return ret;
}
#define OPEN(ret, fn, file, oflag) \
do \
{ \
if(oflag & O_CREAT) \
{ \
int mode; \
va_list va; \
va_start(va, oflag); \
mode = va_arg(va, int); \
va_end(va); \
ret = ORIG(fn)(file, oflag, mode); \
debug(STR(fn) "(\"%s\", %i, %i) = %i", file, oflag, mode, ret); \
} \
else \
{ \
ret = ORIG(fn)(file, oflag); \
debug(STR(fn) "(\"%s\", %i) = %i", file, oflag, ret); \
} \
\
if(ret >= 0) \
{ \
if((oflag & (O_RDONLY | O_RDWR | O_WRONLY)) != O_WRONLY) \
{ \
files[ret].managed = 1; \
files[ret].pos = 0; \
} \
} \
} while(0)
int open(const char *file, int oflag, ...)
{
int ret;
OPEN(ret, open, file, oflag);
return ret;
}
int open64(const char *file, int oflag, ...)
{
int ret;
OPEN(ret, open64, file, oflag);
return ret;
}
ssize_t read(int fd, void *buf, size_t count)
{
int ret = read_orig(fd, buf, count);
debug("read(%i, %p, %li) = %i", fd, buf, (long int)count, ret);
if(ret > 0)
{
zzuf_fuzz(fd, buf, ret);
files[fd].pos += ret;
}
return ret;
}

20
src/preload.h Normal file
View File

@ -0,0 +1,20 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* preload.h: preloaded library functions
*/
extern int zzuf_preload(void);

View File

@ -29,9 +29,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "random.h"
static void set_ld_preload(char const *);
static void version(void);
#if defined(HAVE_GETOPT_H)
static void usage(void);
@ -39,11 +41,10 @@ static void usage(void);
int main(int argc, char *argv[])
{
char *input = NULL, *output = NULL;
FILE *in, *out;
char *data;
long int i, todo, size, seed = -1;
float percent = -1.0;
char buf[BUFSIZ];
char **newargv;
long int seed = 0;
float percent = 0.04;
#if defined(HAVE_GETOPT_H)
for(;;)
@ -54,31 +55,23 @@ int main(int argc, char *argv[])
static struct option long_options[] =
{
/* Long option, needs arg, flag, short option */
{ "input", 1, NULL, 'i' },
{ "output", 1, NULL, 'o' },
{ "seed", 1, NULL, 's' },
{ "percent", 1, NULL, 'p' },
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'v' },
};
int c = getopt_long(argc, argv, "i:o:s:p:hv",
int c = getopt_long(argc, argv, "s:p:hv",
long_options, &option_index);
# else
# define MOREINFO "Try `%s -h' for more information.\n"
int c = getopt(argc, argv, "i:o:s:p:hv");
int c = getopt(argc, argv, "s:p:hv");
# endif
if(c == -1)
break;
switch(c)
{
case 'i': /* --input */
input = optarg;
break;
case 'o': /* --output */
output = optarg;
break;
case 's': /* --seed */
seed = atol(optarg);
break;
@ -102,69 +95,52 @@ int main(int argc, char *argv[])
int optind = 1;
#endif
/* Open the files */
if(input)
if(optind >= argc)
{
in = fopen(input, "rb");
if(!in)
{
fprintf(stderr, "could not open `%s'\n", input);
return 1;
}
}
else
in = stdin;
if(output)
{
out = fopen(output, "wb");
if(!out)
{
fprintf(stderr, "could not open `%s' for writing\n", output);
return 1;
}
}
else
out = stdout;
/* Checking parameters */
if(seed == -1)
{
unsigned long int a = getpid();
seed = (0x7931fea7 * a) ^ (0xb7390af7 + a);
fprintf(stderr, "no seed specified, using %lu\n", seed);
usage();
return -1;
}
if(percent == -1.0)
{
percent = 0.1;
fprintf(stderr, "no percent specified, using %g\n", percent);
}
/* Create new argv */
newargv = malloc((argc - optind + 1) * sizeof(char *));
memcpy(newargv, argv + optind, (argc - optind) * sizeof(char *));
newargv[argc - optind] = (char *)NULL;
/* Read file contents */
fseek(in, 0, SEEK_END);
size = ftell(in);
data = malloc(size);
fseek(in, 0, SEEK_SET);
fread(data, size, 1, in);
fclose(in);
/* Preload libzzuf.so */
set_ld_preload(argv[0]);
/* Randomise shit */
zzuf_srand(seed);
todo = percent * 0.01 * size;
while(todo--)
{
i = zzuf_rand(size);
data[i] ^= 1 << zzuf_rand(8);
}
/* Set environment */
sprintf(buf, "%lu", (unsigned long int)seed);
setenv("ZZUF_SEED", buf, 1);
sprintf(buf, "%g", percent);
setenv("ZZUF_PERCENT", buf, 1);
/* Write result */
fwrite(data, size, 1, out);
fclose(out);
/* Call our process */
execvp(newargv[0], newargv);
return 0;
}
static void set_ld_preload(char const *progpath)
{
char *libpath, *tmp;
int len = strlen(progpath);
libpath = malloc(len + strlen("/.libs/libzzuf.so") + 1);
strcpy(libpath, progpath);
tmp = strrchr(libpath, '/');
strcpy(tmp ? tmp + 1 : libpath, ".libs/libzzuf.so");
if(access(libpath, R_OK) == 0)
{
setenv("LD_PRELOAD", libpath, 1);
return;
}
free(libpath);
/* FIXME: use real path */
setenv("LD_PRELOAD", "/usr/lib/zzuf/libzzuf.so", 1);
}
static void version(void)
{
printf("zzuf %s by Sam Hocevar <sam@zoy.org>\n", VERSION);
@ -173,8 +149,7 @@ static void version(void)
#if defined(HAVE_GETOPT_H)
static void usage(void)
{
printf("Usage: zzuf [ -vh ] [ -i input ] [ -o output ]\n");
printf(" [ -p percent ] [ -s seed ]\n");
printf("Usage: zzuf [ -vh ] [ -p percent ] [ -s seed ] PROG ARGS...\n");
# ifdef HAVE_GETOPT_LONG
printf(" -h, --help display this help and exit\n");
printf(" -v, --version output version information and exit\n");
@ -185,4 +160,3 @@ static void usage(void)
}
#endif