mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-14 11:08:06 +00:00
fix custom mutator C examples
This commit is contained in:
@ -1,342 +0,0 @@
|
|||||||
#ifndef CUSTOM_MUTATOR_HELPERS
|
|
||||||
#define CUSTOM_MUTATOR_HELPERS
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define INITIAL_GROWTH_SIZE (64)
|
|
||||||
|
|
||||||
#define RAND_BELOW(limit) (rand() % (limit))
|
|
||||||
|
|
||||||
/* Use in a struct: creates a name_buf and a name_size variable. */
|
|
||||||
#define BUF_VAR(type, name) \
|
|
||||||
type * name##_buf; \
|
|
||||||
size_t name##_size;
|
|
||||||
/* this fills in `&structptr->something_buf, &structptr->something_size`. */
|
|
||||||
#define BUF_PARAMS(struct, name) \
|
|
||||||
(void **)&struct->name##_buf, &struct->name##_size
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
} afl_t;
|
|
||||||
|
|
||||||
static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
|
|
||||||
|
|
||||||
static s8 interesting_8[] = {INTERESTING_8};
|
|
||||||
static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
|
|
||||||
static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
|
|
||||||
|
|
||||||
switch (RAND_BELOW(12)) {
|
|
||||||
|
|
||||||
case 0: {
|
|
||||||
|
|
||||||
/* Flip a single bit somewhere. Spooky! */
|
|
||||||
|
|
||||||
s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
|
|
||||||
|
|
||||||
out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: {
|
|
||||||
|
|
||||||
/* Set byte to interesting value. */
|
|
||||||
|
|
||||||
u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
|
|
||||||
out_buf[(RAND_BELOW(end - begin) + begin)] = val;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2: {
|
|
||||||
|
|
||||||
/* Set word to interesting value, randomly choosing endian. */
|
|
||||||
|
|
||||||
if (end - begin < 2) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 1) break;
|
|
||||||
|
|
||||||
switch (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
*(u16 *)(out_buf + byte_idx) =
|
|
||||||
interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*(u16 *)(out_buf + byte_idx) =
|
|
||||||
SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3: {
|
|
||||||
|
|
||||||
/* Set dword to interesting value, randomly choosing endian. */
|
|
||||||
|
|
||||||
if (end - begin < 4) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 3) break;
|
|
||||||
|
|
||||||
switch (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
*(u32 *)(out_buf + byte_idx) =
|
|
||||||
interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*(u32 *)(out_buf + byte_idx) =
|
|
||||||
SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4: {
|
|
||||||
|
|
||||||
/* Set qword to interesting value, randomly choosing endian. */
|
|
||||||
|
|
||||||
if (end - begin < 8) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 7) break;
|
|
||||||
|
|
||||||
switch (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
*(u64 *)(out_buf + byte_idx) =
|
|
||||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*(u64 *)(out_buf + byte_idx) = SWAP64(
|
|
||||||
(s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 5: {
|
|
||||||
|
|
||||||
/* Randomly subtract from byte. */
|
|
||||||
|
|
||||||
out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 6: {
|
|
||||||
|
|
||||||
/* Randomly add to byte. */
|
|
||||||
|
|
||||||
out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 7: {
|
|
||||||
|
|
||||||
/* Randomly subtract from word, random endian. */
|
|
||||||
|
|
||||||
if (end - begin < 2) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 1) break;
|
|
||||||
|
|
||||||
if (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
*(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
*(u16 *)(out_buf + byte_idx) =
|
|
||||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 8: {
|
|
||||||
|
|
||||||
/* Randomly add to word, random endian. */
|
|
||||||
|
|
||||||
if (end - begin < 2) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 1) break;
|
|
||||||
|
|
||||||
if (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
*(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
u16 num = 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
*(u16 *)(out_buf + byte_idx) =
|
|
||||||
SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 9: {
|
|
||||||
|
|
||||||
/* Randomly subtract from dword, random endian. */
|
|
||||||
|
|
||||||
if (end - begin < 4) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 3) break;
|
|
||||||
|
|
||||||
if (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
*(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
*(u32 *)(out_buf + byte_idx) =
|
|
||||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 10: {
|
|
||||||
|
|
||||||
/* Randomly add to dword, random endian. */
|
|
||||||
|
|
||||||
if (end - begin < 4) break;
|
|
||||||
|
|
||||||
s32 byte_idx = (RAND_BELOW(end - begin) + begin);
|
|
||||||
|
|
||||||
if (byte_idx >= end - 3) break;
|
|
||||||
|
|
||||||
if (RAND_BELOW(2)) {
|
|
||||||
|
|
||||||
*(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
u32 num = 1 + RAND_BELOW(ARITH_MAX);
|
|
||||||
|
|
||||||
*(u32 *)(out_buf + byte_idx) =
|
|
||||||
SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
case 11: {
|
|
||||||
|
|
||||||
/* Just set a random byte to a random value. Because,
|
|
||||||
why not. We use XOR with 1-255 to eliminate the
|
|
||||||
possibility of a no-op. */
|
|
||||||
|
|
||||||
out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function calculates the next power of 2 greater or equal its argument.
|
|
||||||
@return The rounded up power of 2 (if no overflow) or 0 on overflow.
|
|
||||||
*/
|
|
||||||
static inline size_t next_pow2(size_t in) {
|
|
||||||
|
|
||||||
if (in == 0 || in > (size_t)-1)
|
|
||||||
return 0; /* avoid undefined behaviour under-/overflow */
|
|
||||||
size_t out = in - 1;
|
|
||||||
out |= out >> 1;
|
|
||||||
out |= out >> 2;
|
|
||||||
out |= out >> 4;
|
|
||||||
out |= out >> 8;
|
|
||||||
out |= out >> 16;
|
|
||||||
return out + 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function makes sure *size is > size_needed after call.
|
|
||||||
It will realloc *buf otherwise.
|
|
||||||
*size will grow exponentially as per:
|
|
||||||
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
|
|
||||||
Will return NULL and free *buf if size_needed is <1 or realloc failed.
|
|
||||||
@return For convenience, this function returns *buf.
|
|
||||||
*/
|
|
||||||
static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
|
|
||||||
|
|
||||||
/* No need to realloc */
|
|
||||||
if (likely(size_needed && *size >= size_needed)) return *buf;
|
|
||||||
|
|
||||||
/* No initial size was set */
|
|
||||||
if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
|
|
||||||
|
|
||||||
/* grow exponentially */
|
|
||||||
size_t next_size = next_pow2(size_needed);
|
|
||||||
|
|
||||||
/* handle overflow */
|
|
||||||
if (!next_size) { next_size = size_needed; }
|
|
||||||
|
|
||||||
/* alloc */
|
|
||||||
*buf = realloc(*buf, next_size);
|
|
||||||
*size = *buf ? next_size : 0;
|
|
||||||
|
|
||||||
return *buf;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
|
|
||||||
static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
|
|
||||||
size_t *size2) {
|
|
||||||
|
|
||||||
void * scratch_buf = *buf1;
|
|
||||||
size_t scratch_size = *size1;
|
|
||||||
*buf1 = *buf2;
|
|
||||||
*size1 = *size2;
|
|
||||||
*buf2 = scratch_buf;
|
|
||||||
*size2 = scratch_size;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef INITIAL_GROWTH_SIZE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -10,21 +10,21 @@
|
|||||||
// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
|
// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "custom_mutator_helpers.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
typedef struct my_mutator {
|
typedef struct my_mutator {
|
||||||
|
|
||||||
afl_t *afl;
|
afl_state_t *afl;
|
||||||
|
|
||||||
} my_mutator_t;
|
} my_mutator_t;
|
||||||
|
|
||||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||||
|
|
||||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// You need to use -I/path/to/AFLplusplus/include -I.
|
// You need to use -I/path/to/AFLplusplus/include -I.
|
||||||
#include "custom_mutator_helpers.h"
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -26,19 +26,14 @@ static const char *commands[] = {
|
|||||||
|
|
||||||
typedef struct my_mutator {
|
typedef struct my_mutator {
|
||||||
|
|
||||||
afl_t *afl;
|
afl_state_t *afl;
|
||||||
|
|
||||||
// any additional data here!
|
// any additional data here!
|
||||||
size_t trim_size_current;
|
size_t trim_size_current;
|
||||||
int trimmming_steps;
|
int trimmming_steps;
|
||||||
int cur_step;
|
int cur_step;
|
||||||
|
|
||||||
// Reused buffers:
|
u8 *mutated_out, *post_process_buf, *trim_buf;
|
||||||
BUF_VAR(u8, fuzz);
|
|
||||||
BUF_VAR(u8, data);
|
|
||||||
BUF_VAR(u8, havoc);
|
|
||||||
BUF_VAR(u8, trim);
|
|
||||||
BUF_VAR(u8, post_process);
|
|
||||||
|
|
||||||
} my_mutator_t;
|
} my_mutator_t;
|
||||||
|
|
||||||
@ -53,7 +48,7 @@ typedef struct my_mutator {
|
|||||||
* There may be multiple instances of this mutator in one afl-fuzz run!
|
* There may be multiple instances of this mutator in one afl-fuzz run!
|
||||||
* Return NULL on error.
|
* Return NULL on error.
|
||||||
*/
|
*/
|
||||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||||
|
|
||||||
srand(seed); // needed also by surgical_havoc_mutate()
|
srand(seed); // needed also by surgical_havoc_mutate()
|
||||||
|
|
||||||
@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
|
||||||
|
|
||||||
|
perror("afl_custom_init malloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
|
||||||
|
|
||||||
|
perror("afl_custom_init malloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
|
||||||
|
|
||||||
|
perror("afl_custom_init malloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
data->afl = afl;
|
data->afl = afl;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -96,31 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
|||||||
// the fuzzer
|
// the fuzzer
|
||||||
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
|
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
|
||||||
|
|
||||||
// maybe_grow is optimized to be quick for reused buffers.
|
memcpy(data->mutated_out, buf, buf_size);
|
||||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
|
|
||||||
if (!mutated_out) {
|
|
||||||
|
|
||||||
*out_buf = NULL;
|
|
||||||
perror("custom mutator allocation (maybe_grow)");
|
|
||||||
return 0; /* afl-fuzz will very likely error out after this. */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Randomly select a command string to add as a header to the packet
|
// Randomly select a command string to add as a header to the packet
|
||||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
memcpy(data->mutated_out, commands[rand() % 3], 3);
|
||||||
|
|
||||||
// Mutate the payload of the packet
|
if (mutated_size > max_size) { mutated_size = max_size; }
|
||||||
int i;
|
|
||||||
for (i = 0; i < 8; ++i) {
|
|
||||||
|
|
||||||
// Randomly perform one of the (no len modification) havoc mutations
|
*out_buf = data->mutated_out;
|
||||||
surgical_havoc_mutate(mutated_out, 3, mutated_size);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_size > mutated_size) { mutated_size = max_size; }
|
|
||||||
|
|
||||||
*out_buf = mutated_out;
|
|
||||||
return mutated_size;
|
return mutated_size;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -144,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
|||||||
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
|
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
|
||||||
size_t buf_size, uint8_t **out_buf) {
|
size_t buf_size, uint8_t **out_buf) {
|
||||||
|
|
||||||
uint8_t *post_process_buf =
|
if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; }
|
||||||
maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
|
|
||||||
if (!post_process_buf) {
|
|
||||||
|
|
||||||
perror("custom mutator realloc failed.");
|
memcpy(data->post_process_buf + 5, buf, buf_size);
|
||||||
*out_buf = NULL;
|
data->post_process_buf[0] = 'A';
|
||||||
return 0;
|
data->post_process_buf[1] = 'F';
|
||||||
|
data->post_process_buf[2] = 'L';
|
||||||
|
data->post_process_buf[3] = '+';
|
||||||
|
data->post_process_buf[4] = '+';
|
||||||
|
|
||||||
}
|
*out_buf = data->post_process_buf;
|
||||||
|
|
||||||
memcpy(post_process_buf + 5, buf, buf_size);
|
|
||||||
post_process_buf[0] = 'A';
|
|
||||||
post_process_buf[1] = 'F';
|
|
||||||
post_process_buf[2] = 'L';
|
|
||||||
post_process_buf[3] = '+';
|
|
||||||
post_process_buf[4] = '+';
|
|
||||||
|
|
||||||
*out_buf = post_process_buf;
|
|
||||||
|
|
||||||
return buf_size + 5;
|
return buf_size + 5;
|
||||||
|
|
||||||
@ -197,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
|
|||||||
|
|
||||||
data->cur_step = 0;
|
data->cur_step = 0;
|
||||||
|
|
||||||
if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
|
|
||||||
|
|
||||||
perror("init_trim grow");
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(data->trim_buf, buf, buf_size);
|
memcpy(data->trim_buf, buf, buf_size);
|
||||||
|
|
||||||
data->trim_size_current = buf_size;
|
data->trim_size_current = buf_size;
|
||||||
@ -284,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
|
|||||||
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
|
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
|
||||||
u8 **out_buf, size_t max_size) {
|
u8 **out_buf, size_t max_size) {
|
||||||
|
|
||||||
if (buf_size == 0) {
|
*out_buf = buf; // in-place mutation
|
||||||
|
|
||||||
*out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
|
if (buf_size <= sizeof(size_t)) { return buf_size; }
|
||||||
if (!*out_buf) {
|
|
||||||
|
|
||||||
perror("custom havoc: maybe_grow");
|
size_t victim = rand() % (buf_size - sizeof(size_t));
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
**out_buf = rand() % 256;
|
|
||||||
buf_size = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// We reuse buf here. It's legal and faster.
|
|
||||||
*out_buf = buf;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t victim = rand() % buf_size;
|
|
||||||
(*out_buf)[victim] += rand() % 10;
|
(*out_buf)[victim] += rand() % 10;
|
||||||
|
|
||||||
return buf_size;
|
return buf_size;
|
||||||
@ -371,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
|
|||||||
void afl_custom_deinit(my_mutator_t *data) {
|
void afl_custom_deinit(my_mutator_t *data) {
|
||||||
|
|
||||||
free(data->post_process_buf);
|
free(data->post_process_buf);
|
||||||
free(data->havoc_buf);
|
free(data->mutated_out);
|
||||||
free(data->data_buf);
|
|
||||||
free(data->fuzz_buf);
|
|
||||||
free(data->trim_buf);
|
free(data->trim_buf);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
|
@ -45,9 +45,8 @@
|
|||||||
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
|
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
|
||||||
and return the original `len`.
|
and return the original `len`.
|
||||||
|
|
||||||
NOTE: the following is currently NOT true, we abort in this case!
|
|
||||||
2) If you want to skip this test case altogether and have AFL generate a
|
2) If you want to skip this test case altogether and have AFL generate a
|
||||||
new one, return 0 or set `*out_buf = NULL`.
|
new one, return 0.
|
||||||
Use this sparingly - it's faster than running the target program
|
Use this sparingly - it's faster than running the target program
|
||||||
with patently useless inputs, but still wastes CPU time.
|
with patently useless inputs, but still wastes CPU time.
|
||||||
|
|
||||||
@ -59,8 +58,6 @@
|
|||||||
Note that the buffer will *not* be freed for you. To avoid memory leaks,
|
Note that the buffer will *not* be freed for you. To avoid memory leaks,
|
||||||
you need to free it or reuse it on subsequent calls (as shown below).
|
you need to free it or reuse it on subsequent calls (as shown below).
|
||||||
|
|
||||||
*** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
|
|
||||||
|
|
||||||
Alright. The example below shows a simple postprocessor that tries to make
|
Alright. The example below shows a simple postprocessor that tries to make
|
||||||
sure that all input files start with "GIF89a".
|
sure that all input files start with "GIF89a".
|
||||||
|
|
||||||
@ -72,7 +69,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "alloc-inl.h"
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
/* Header that must be present at the beginning of every test case: */
|
/* Header that must be present at the beginning of every test case: */
|
||||||
|
|
||||||
@ -80,7 +77,6 @@
|
|||||||
|
|
||||||
typedef struct post_state {
|
typedef struct post_state {
|
||||||
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
} post_state_t;
|
} post_state_t;
|
||||||
@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
|
||||||
if (!state->buf) {
|
|
||||||
|
|
||||||
free(state);
|
|
||||||
perror("calloc");
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) {
|
|||||||
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
||||||
unsigned int len, unsigned char **out_buf) {
|
unsigned int len, unsigned char **out_buf) {
|
||||||
|
|
||||||
|
/* we do in-place modification as we do not increase the size */
|
||||||
|
|
||||||
|
*out_buf = in_buf;
|
||||||
|
|
||||||
/* Skip execution altogether for buffers shorter than 6 bytes (just to
|
/* Skip execution altogether for buffers shorter than 6 bytes (just to
|
||||||
show how it's done). We can trust len to be sane. */
|
show how it's done). We can trust len to be sane. */
|
||||||
|
|
||||||
@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
|||||||
|
|
||||||
/* Do nothing for buffers that already start with the expected header. */
|
/* Do nothing for buffers that already start with the expected header. */
|
||||||
|
|
||||||
if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
|
if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; }
|
||||||
|
|
||||||
*out_buf = in_buf;
|
|
||||||
return len;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate memory for new buffer, reusing previous allocation if
|
|
||||||
possible. Note we have to use afl-fuzz's own realloc!
|
|
||||||
We use afl_realloc because it is effective.
|
|
||||||
You can also work within in_buf, and assign it to *out_buf. */
|
|
||||||
|
|
||||||
*out_buf = afl_realloc(out_buf, len);
|
|
||||||
|
|
||||||
/* If we're out of memory, the most graceful thing to do is to return the
|
|
||||||
original buffer and give up on modifying it. Let AFL handle OOM on its
|
|
||||||
own later on. */
|
|
||||||
|
|
||||||
if (!*out_buf) {
|
|
||||||
|
|
||||||
*out_buf = in_buf;
|
|
||||||
return len;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > strlen(HEADER))
|
|
||||||
memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
|
|
||||||
len - strlen(HEADER));
|
|
||||||
|
|
||||||
/* Insert the new header. */
|
/* Insert the new header. */
|
||||||
|
|
||||||
@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
|
|||||||
/* Gets called afterwards */
|
/* Gets called afterwards */
|
||||||
void afl_custom_deinit(post_state_t *data) {
|
void afl_custom_deinit(post_state_t *data) {
|
||||||
|
|
||||||
free(data->buf);
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include "alloc-inl.h"
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
/* A macro to round an integer up to 4 kB. */
|
/* A macro to round an integer up to 4 kB. */
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state->buf = calloc(sizeof(unsigned char), 4096);
|
state->buf = calloc(sizeof(unsigned char), MAX_FILE);
|
||||||
if (!state->buf) {
|
if (!state->buf) {
|
||||||
|
|
||||||
free(state);
|
free(state);
|
||||||
@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is not a good way to do it, if you do not need to grow the buffer
|
|
||||||
then just work with in_buf instead for speed reasons.
|
|
||||||
But we want to show how to grow a buffer, so this is how it's done: */
|
|
||||||
|
|
||||||
unsigned int pos = 8;
|
unsigned int pos = 8;
|
||||||
unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
|
|
||||||
|
|
||||||
if (!new_buf) {
|
|
||||||
|
|
||||||
*out_buf = in_buf;
|
|
||||||
return len;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(new_buf, in_buf, len);
|
|
||||||
|
|
||||||
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
|
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
|
||||||
don't have that, we can bail out. */
|
don't have that, we can bail out. */
|
||||||
@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
|||||||
|
|
||||||
if (real_cksum != file_cksum) {
|
if (real_cksum != file_cksum) {
|
||||||
|
|
||||||
*(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
|
*(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_buf = new_buf;
|
*out_buf = data->buf;
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// This simple example just creates random buffer <= 100 filled with 'A'
|
// This simple example just creates random buffer <= 100 filled with 'A'
|
||||||
// needs -I /path/to/AFLplusplus/include
|
// needs -I /path/to/AFLplusplus/include
|
||||||
#include "custom_mutator_helpers.h"
|
#include "afl-fuzz.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -13,14 +13,14 @@
|
|||||||
|
|
||||||
typedef struct my_mutator {
|
typedef struct my_mutator {
|
||||||
|
|
||||||
afl_t *afl;
|
afl_state_t *afl;
|
||||||
|
|
||||||
// Reused buffers:
|
// Reused buffers:
|
||||||
BUF_VAR(u8, fuzz);
|
u8 *fuzz_buf;
|
||||||
|
|
||||||
} my_mutator_t;
|
} my_mutator_t;
|
||||||
|
|
||||||
my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
|
||||||
|
|
||||||
srand(seed);
|
srand(seed);
|
||||||
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
|
||||||
@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->fuzz_buf = (u8 *)malloc(MAX_FILE);
|
||||||
|
if (!data->fuzz_buf) {
|
||||||
|
|
||||||
|
perror("afl_custom_init malloc");
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
data->afl = afl;
|
data->afl = afl;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
|
|||||||
|
|
||||||
int size = (rand() % 100) + 1;
|
int size = (rand() % 100) + 1;
|
||||||
if (size > max_size) size = max_size;
|
if (size > max_size) size = max_size;
|
||||||
u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
|
|
||||||
if (!mutated_out) {
|
|
||||||
|
|
||||||
*out_buf = NULL;
|
memset(data->fuzz_buf, _FIXED_CHAR, size);
|
||||||
perror("custom mutator allocation (maybe_grow)");
|
|
||||||
return 0; /* afl-fuzz will very likely error out after this. */
|
|
||||||
|
|
||||||
}
|
*out_buf = data->fuzz_buf;
|
||||||
|
|
||||||
memset(mutated_out, _FIXED_CHAR, size);
|
|
||||||
|
|
||||||
*out_buf = mutated_out;
|
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
- unicorn_mode:
|
- unicorn_mode:
|
||||||
- updated and minor issues fixed
|
- updated and minor issues fixed
|
||||||
- new custom module: autotoken, a grammar free fuzzer for text inputs
|
- new custom module: autotoken, a grammar free fuzzer for text inputs
|
||||||
|
- fixed custom mutator C examples
|
||||||
- better sanitizer default options support for all tools
|
- better sanitizer default options support for all tools
|
||||||
- more minor fixes and cross-platform support
|
- more minor fixes and cross-platform support
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user