2024-04-05 14:53:02 +02:00

164 lines
4.1 KiB
C

#include "afl-fuzz.h"
#include "afl-mutations.h"
typedef struct my_mutator {
afl_state_t *afl;
u8 *buf;
u32 buf_size;
} my_mutator_t;
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
(void)seed;
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
perror("afl_custom_init alloc");
return NULL;
}
if ((data->buf = malloc(1024*1024)) == NULL) {
perror("afl_custom_init alloc");
return NULL;
} else {
data->buf_size = 1024*1024;
}
/* fake AFL++ state */
data->afl = calloc(1, sizeof(afl_state_t));
data->afl->queue_cycle = 1;
data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
if (data->afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
rand_set_seed(data->afl, getpid());
return data;
}
/* here we run the AFL++ mutator, which is the best! */
size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
if (max_size > data->buf_size) {
u8 *ptr = realloc(data->buf, max_size);
if (ptr) {
return 0;
} else {
data->buf = ptr;
data->buf_size = max_size;
}
}
u32 havoc_steps = 1 + rand_below(data->afl, 16);
/* set everything up, costly ... :( */
memcpy(data->buf, buf, buf_size);
/* the mutation */
u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
false, true, add_buf, add_buf_size, max_size);
/* return size of mutated data */
*out_buf = data->buf;
return out_buf_len;
}
int main(int argc, char *argv[]) {
if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
printf("Syntax: %s [-v] [inputfile [outputfile [splicefile]]]\n\n", argv[0]);
printf("Reads a testcase from stdin when no input file (or '-') is specified,\n");
printf("mutates according to AFL++'s mutation engine, and write to stdout when '-' or\n");
printf("no output filename is given. As an optional third parameter you can give a file\n");
printf("for splicing. Maximum input and output length is 1MB.\n");
printf("The -v verbose option prints debug output to stderr.\n");
return 0;
}
FILE *in = stdin, *out = stdout, *splice = NULL;
unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL;
int verbose = 0, splicelen = 0;
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
verbose = 1;
argc--;
argv++;
fprintf(stderr, "Verbose active\n");
}
my_mutator_t *data = afl_custom_init(NULL, 0);
if (argc > 1 && strcmp(argv[1], "-") != 0) {
if ((in = fopen(argv[1], "r")) == NULL) {
perror(argv[1]);
return -1;
}
if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
}
size_t inlen = fread(inbuf, 1, 1024*1024, in);
if (!inlen) {
fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
return -1;
}
if (argc > 2 && strcmp(argv[2], "-") != 0) {
if ((out = fopen(argv[2], "w")) == NULL) {
perror(argv[2]);
return -1;
}
if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
}
if (argc > 3) {
if ((splice = fopen(argv[3], "r")) == NULL) {
perror(argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
splicebuf = malloc(1024*1024);
size_t splicelen = fread(splicebuf, 1, 1024*1024, splice);
if (!splicelen) {
fprintf(stderr, "Error: empty file %s\n", argv[3]);
return -1;
}
if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
}
if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf, splicelen, 1024*1024);
if (outlen == 0 || !outbuf) {
fprintf(stderr, "Error: no mutation data returned.\n");
return -1;
}
if (verbose) fprintf(stderr, "Mutation output length: %u\n", outlen);
if (fwrite(outbuf, 1, outlen, out) != outlen) {
fprintf(stderr, "Warning: incomplete write.\n");
return -1;
}
return 0;
}