blob: 23c3d8105e5ad866aad2fcc145862f4ee4956c46 [file] [log] [blame]
/*
*
* honggfuzz - run->dynfile->datafer mangling routines
* -----------------------------------------
*
* Author:
* Robert Swiecki <swiecki@google.com>
*
* Copyright 2010-2018 by Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
#include "mangle.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "input.h"
#include "libhfcommon/common.h"
#include "libhfcommon/log.h"
#include "libhfcommon/util.h"
typedef enum {
MANGLE_SHRINK = 0,
MANGLE_EXPAND,
MANGLE_BIT,
MANGLE_INC_BYTE,
MANGLE_DEC_BYTE,
MANGLE_NEG_BYTE,
MANGLE_ADD_SUB,
MANGLE_ARITH8,
MANGLE_MEM_SET,
MANGLE_MEM_CLR,
MANGLE_MEM_SWAP,
MANGLE_MEM_COPY,
MANGLE_BLOCK_MOVE,
MANGLE_BLOCK_REPEAT,
MANGLE_BLOCK_SWAP,
MANGLE_CHUNK_SHUFFLE,
MANGLE_BYTES,
MANGLE_BYTE_REPEAT,
MANGLE_RANDOM_BUF,
MANGLE_INTERESTING_VALUES,
MANGLE_ASCII_NUM,
MANGLE_ASCII_NUM_CHANGE,
MANGLE_MAGIC,
MANGLE_STATIC_DICT,
MANGLE_CONST_FEEDBACK_DICT,
MANGLE_CMP_SOLVE,
MANGLE_SPLICE,
MANGLE_CROSS_OVER,
MANGLE_SPECIAL_STRINGS,
MANGLE_COUNT
} mangle_t;
static inline size_t mangle_LenLeft(run_t* run, size_t off) {
if (off >= run->dynfile->size) {
LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
}
return (run->dynfile->size - off - 1);
}
/*
* Get a random value <1:max>, but prefer smaller ones
* Based on an idea by https://twitter.com/gamozolabs
*/
static inline size_t mangle_getLen(size_t max) {
if (max > _HF_INPUT_MAX_SIZE) {
LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
}
if (max == 0) {
LOG_F("max == 0");
}
if (max == 1) {
return 1;
}
/* Give 50% chance the the uniform distribution */
if (util_rnd64() & 1) {
return (size_t)util_rndGet(1, max);
}
/* effectively exprand() */
return (size_t)util_rndGet(1, util_rndGet(1, max));
}
/* Prefer smaller values here, so use mangle_getLen() */
static inline size_t mangle_getOffSet(run_t* run) {
return mangle_getLen(run->dynfile->size) - 1;
}
/* Offset which can be equal to the file size */
static inline size_t mangle_getOffSetPlus1(run_t* run) {
size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
return mangle_getLen(reqlen) - 1;
}
static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
if (off_from >= run->dynfile->size) {
return;
}
if (off_to >= run->dynfile->size) {
return;
}
if (off_from == off_to) {
return;
}
size_t len_from = run->dynfile->size - off_from;
len = HF_MIN(len, len_from);
size_t len_to = run->dynfile->size - off_to;
len = HF_MIN(len, len_to);
memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
}
static inline void mangle_Overwrite(
run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
if (len == 0) {
return;
}
size_t maxToCopy = run->dynfile->size - off;
if (len > maxToCopy) {
len = maxToCopy;
}
memmove(&run->dynfile->data[off], src, len);
if (printable) {
util_turnToPrintable(&run->dynfile->data[off], len);
}
}
static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
if (run->dynfile->size >= run->global->mutate.maxInputSz) {
return 0;
}
if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
len = run->global->mutate.maxInputSz - run->dynfile->size;
}
input_setSize(run, run->dynfile->size + len);
mangle_Move(run, off, off + len, run->dynfile->size);
if (printable) {
memset(&run->dynfile->data[off], ' ', len);
}
return len;
}
static inline void mangle_Insert(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
len = mangle_Inflate(run, off, len, printable);
mangle_Overwrite(run, off, val, len, printable);
}
static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
} else {
mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
}
}
static inline void mangle_UseValueAt(
run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
if (util_rnd64() & 1) {
mangle_Overwrite(run, off, val, len, printable);
} else {
mangle_Insert(run, off, val, len, printable);
}
}
static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
/* No big deal if those two are overlapping */
size_t off1 = mangle_getOffSet(run);
size_t maxlen1 = run->dynfile->size - off1;
size_t off2 = mangle_getOffSet(run);
size_t maxlen2 = run->dynfile->size - off2;
size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
if (off1 == off2) {
return;
}
for (size_t i = 0; i < (len / 2); i++) {
/*
* First - from the head, next from the tail. Don't worry about layout of the overlapping
* part - there's no good solution to that, and it can be left somewhat scrambled,
* while still preserving the entropy
*/
const uint8_t tmp1 = run->dynfile->data[off2 + i];
run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
run->dynfile->data[off1 + i] = tmp1;
const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
run->dynfile->data[off1 + (len - 1) - i] = tmp2;
}
}
static void mangle_BlockMove(run_t* run, bool printable HF_ATTR_UNUSED) {
size_t off_from = mangle_getOffSet(run);
size_t off_to = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size);
mangle_Move(run, off_from, off_to, len);
}
static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
/* Use a temp buf, as Insert/Inflate can change source bytes */
uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
defer {
free(tmpbuf);
};
memmove(tmpbuf, &run->dynfile->data[off], len);
mangle_UseValue(run, tmpbuf, len, printable);
}
static void mangle_Bytes(run_t* run, bool printable) {
uint16_t buf;
if (printable) {
util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
} else {
buf = util_rnd64();
}
/* Overwrite with random 1-2-byte values */
size_t toCopy = util_rndGet(1, 2);
mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
}
static void mangle_ByteRepeat(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t destOff = off + 1;
size_t maxSz = run->dynfile->size - destOff;
/* No space to repeat */
if (!maxSz) {
mangle_Bytes(run, printable);
return;
}
size_t len = mangle_getLen(maxSz);
if (util_rnd64() & 0x1) {
len = mangle_Inflate(run, destOff, len, printable);
}
memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
}
static void mangle_Bit(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
if (printable) {
util_turnToPrintable(&(run->dynfile->data[off]), 1);
}
}
static const struct {
#if __has_attribute(nonstring)
const uint8_t val[8] __attribute__((nonstring));
#else
const uint8_t val[8];
#endif /* __has_attribute(nonstring) */
const size_t size;
} mangleMagicVals[] = {
/* 1B - No endianness */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 1},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 1},
/* 2B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x01\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x80\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\xFF\x00\x00\x00\x00\x00\x00", 2},
/* 2B - BE */
{"\x00\x01\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x02\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x03\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x04\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x05\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x06\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x07\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x08\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x09\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0A\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0B\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0C\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0D\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0E\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x0F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x10\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x20\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x40\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x7E\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x7F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x81\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xC0\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xFE\x00\x00\x00\x00\x00\x00", 2},
{"\x00\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x7E\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x7F\xFF\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x01\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\xFE\x00\x00\x00\x00\x00\x00", 2},
/* 2B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x7E\x00\x00\x00\x00\x00\x00", 2},
{"\xFF\x7F\x00\x00\x00\x00\x00\x00", 2},
{"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
{"\x01\x80\x00\x00\x00\x00\x00\x00", 2},
{"\xFE\xFF\x00\x00\x00\x00\x00\x00", 2},
/* 4B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x01\x01\x01\x01\x00\x00\x00\x00", 4},
{"\x80\x80\x80\x80\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", 4},
/* 4B - BE */
{"\x00\x00\x00\x01\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x02\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x03\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x04\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x05\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x06\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x07\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x08\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x09\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0A\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0B\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0C\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0D\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0E\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x0F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x10\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x20\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x40\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x7E\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x7F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x81\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xC0\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xFE\x00\x00\x00\x00", 4},
{"\x00\x00\x00\xFF\x00\x00\x00\x00", 4},
{"\x7E\xFF\xFF\xFF\x00\x00\x00\x00", 4},
{"\x7F\xFF\xFF\xFF\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x01\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\xFE\x00\x00\x00\x00", 4},
/* 4B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\x7E\x00\x00\x00\x00", 4},
{"\xFF\xFF\xFF\x7F\x00\x00\x00\x00", 4},
{"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
{"\x01\x00\x00\x80\x00\x00\x00\x00", 4},
{"\xFE\xFF\xFF\xFF\x00\x00\x00\x00", 4},
/* 8B - NE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x01\x01\x01\x01\x01\x01\x01\x01", 8},
{"\x80\x80\x80\x80\x80\x80\x80\x80", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
/* 8B - BE */
{"\x00\x00\x00\x00\x00\x00\x00\x01", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x02", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x03", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x04", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x05", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x06", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x07", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x08", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x09", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0A", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0B", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0C", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0D", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0E", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x0F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x10", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x20", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x40", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x7E", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x7F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x81", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xC0", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xFE", 8},
{"\x00\x00\x00\x00\x00\x00\x00\xFF", 8},
{"\x7E\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
{"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x01", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 8},
/* 8B - LE */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x02\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x03\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x04\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x05\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x06\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x07\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x08\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x09\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0A\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0B\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0C\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0D\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0E\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x0F\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x10\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x20\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x40\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x7E\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x7F\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
{"\x81\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xC0\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFE\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFF\x00\x00\x00\x00\x00\x00\x00", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7E", 8},
{"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 8},
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
};
static void mangle_Magic(run_t* run, bool printable) {
uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
}
static void mangle_StaticDict(run_t* run, bool printable) {
if (run->global->mutate.dictionaryCnt == 0) {
mangle_Bytes(run, printable);
return;
}
uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
run->global->mutate.dictionary[choice].len, printable);
}
static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
if (!run->global->feedback.cmpFeedback) {
return NULL;
}
cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
if (cnt == 0) {
return NULL;
}
if (cnt > ARRAYSIZE(cmpf->valArr)) {
cnt = ARRAYSIZE(cmpf->valArr);
}
uint32_t choice = util_rndGet(0, cnt - 1);
*len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
if (*len == 0) {
return NULL;
}
return cmpf->valArr[choice].val;
}
static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
size_t len;
const uint8_t* val = mangle_FeedbackDict(run, &len);
if (val == NULL) {
mangle_Bytes(run, printable);
return;
}
mangle_UseValue(run, val, len, printable);
}
static void mangle_MemSet(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
memset(&run->dynfile->data[off], val, len);
}
static void mangle_MemClr(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
int val = printable ? ' ' : 0;
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
memset(&run->dynfile->data[off], val, len);
}
static void mangle_RandomBuf(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
if (util_rnd64() & 1) {
len = mangle_Inflate(run, off, len, printable);
}
if (printable) {
util_rndBufPrintable(&run->dynfile->data[off], len);
} else {
util_rndBuf(&run->dynfile->data[off], len);
}
}
static inline void mangle_AddSubWithRange(
run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
switch (varLen) {
case 1: {
run->dynfile->data[off] += delta;
break;
}
case 2: {
int16_t val;
util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap16(val);
val += delta;
val = __builtin_bswap16(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
case 4: {
int32_t val;
util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap32(val);
val += delta;
val = __builtin_bswap32(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
case 8: {
int64_t val;
util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val));
if (util_rnd64() & 0x1) {
val += delta;
} else {
/* Foreign endianess */
val = __builtin_bswap64(val);
val += delta;
val = __builtin_bswap64(val);
}
mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
break;
}
default: {
LOG_F("Unknown variable length size: %zu", varLen);
}
}
}
static void mangle_AddSub(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
/* 1,2,4,8 */
size_t varLen = 1U << util_rndGet(0, 3);
if ((run->dynfile->size - off) < varLen) {
varLen = 1;
}
/* Ranges relative to the width of the type */
const uint64_t range8Bit = 16;
const uint64_t range16Bit = 4096;
const uint64_t range32Bit = 1048576;
const uint64_t range64Bit = 268435456;
uint64_t range;
switch (varLen) {
case 1:
range = range8Bit;
break;
case 2:
range = range16Bit;
break;
case 4:
range = range32Bit;
break;
case 8:
range = range64Bit;
break;
default:
LOG_F("Invalid operand size: %zu", varLen);
}
mangle_AddSubWithRange(run, off, varLen, range, printable);
}
static void mangle_IncByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
} else {
run->dynfile->data[off] += (uint8_t)1UL;
}
}
static void mangle_DecByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
} else {
run->dynfile->data[off] -= (uint8_t)1UL;
}
}
static void mangle_NegByte(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
if (printable) {
run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
} else {
run->dynfile->data[off] = ~(run->dynfile->data[off]);
}
}
static void mangle_Expand(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len;
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
} else {
len = mangle_getLen(run->global->mutate.maxInputSz - off);
}
mangle_Inflate(run, off, len, printable);
}
static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
if (run->dynfile->size <= 2U) {
return;
}
size_t off_start = mangle_getOffSet(run);
size_t len = mangle_LenLeft(run, off_start);
if (len == 0) {
return;
}
if (util_rnd64() % 16) {
len = mangle_getLen(HF_MIN(16, len));
} else {
len = mangle_getLen(len);
}
size_t off_end = off_start + len;
size_t len_to_move = run->dynfile->size - off_end;
mangle_Move(run, off_end, off_start, len_to_move);
input_setSize(run, run->dynfile->size - len);
}
static void mangle_ASCIINum(run_t* run, bool printable) {
size_t len = util_rndGet(2, 8);
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
mangle_UseValue(run, (const uint8_t*)buf, len, printable);
}
static void mangle_ASCIINumChange(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
/* Find a digit */
for (; off < run->dynfile->size; off++) {
if (isdigit(run->dynfile->data[off])) {
break;
}
}
size_t left = run->dynfile->size - off;
if (left == 0) {
return;
}
size_t len = 0;
uint64_t val = 0;
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
for (len = 0; (len < 20) && (len < left); len++) {
char c = run->dynfile->data[off + len];
if (!isdigit(c)) {
break;
}
val *= 10;
val += (c - '0');
}
enum { OP_INC = 0, OP_DEC, OP_MUL, OP_DIV, OP_RND, OP_ADD_RND, OP_SUB_RND, OP_NOT, OP_COUNT };
switch (util_rndGet(0, OP_COUNT - 1)) {
case OP_INC:
val++;
break;
case OP_DEC:
val--;
break;
case OP_MUL:
val *= 2;
break;
case OP_DIV:
val /= 2;
break;
case OP_RND:
val = util_rnd64();
break;
case OP_ADD_RND:
val += util_rndGet(1, 256);
break;
case OP_SUB_RND:
val -= util_rndGet(1, 256);
break;
case OP_NOT:
val = ~(val);
break;
default:
LOG_F("Invalid choice");
};
char buf[20];
snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable);
}
static void mangle_Splice(run_t* run, bool printable) {
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
mangle_Bytes(run, printable);
return;
}
size_t sz = 0;
const uint8_t* buf = input_getRandomInputAsBuf(run, &sz);
if (!buf) {
LOG_E("input_getRandomInputAsBuf() returned no input");
mangle_Bytes(run, printable);
return;
}
if (!sz) {
mangle_Bytes(run, printable);
return;
}
size_t remoteOff = mangle_getLen(sz) - 1;
size_t len = mangle_getLen(sz - remoteOff);
mangle_UseValue(run, &buf[remoteOff], len, printable);
}
static void mangle_Resize(run_t* run, bool printable) {
ssize_t oldsz = run->dynfile->size;
ssize_t newsz = 0;
/* Probability distribution (out of 32)
* 0: arbitrary size (1/32)
* 1-4: small increase (4/32)
* 5: large increase (1/32)
* 6-9: small decrease (4/32)
* 10: large decrease (1/32)
* 11-32: no change (21/32)
*/
uint64_t choice = util_rndGet(0, 32);
switch (choice) {
case 0: /* Set new size arbitrarily */
newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
break;
case 1 ... 4: /* Increase size by a small value */
newsz = oldsz + (ssize_t)util_rndGet(0, 8);
break;
case 5: /* Increase size by a larger value */
newsz = oldsz + (ssize_t)util_rndGet(9, 128);
break;
case 6 ... 9: /* Decrease size by a small value */
newsz = oldsz - (ssize_t)util_rndGet(0, 8);
break;
case 10: /* Decrease size by a larger value */
newsz = oldsz - (ssize_t)util_rndGet(9, 128);
break;
default: /* Do nothing */
newsz = oldsz;
break;
}
if (newsz < 1) {
newsz = 1;
}
if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
newsz = run->global->mutate.maxInputSz;
}
input_setSize(run, (size_t)newsz);
if (newsz > oldsz) {
if (printable) {
memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
}
}
}
static void mangle_BlockRepeat(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
size_t len = mangle_getLen(run->dynfile->size - off);
len = HF_MIN(len, 1024);
uint8_t* tmp = util_Malloc(len);
defer {
free(tmp);
};
memcpy(tmp, run->dynfile->data + off, len);
size_t repeats = util_rndGet(1, 16);
size_t total_add = len * repeats;
size_t added = mangle_Inflate(run, off + len, total_add, printable);
for (size_t i = 0; i < added; i += len) {
size_t copy_len = HF_MIN(len, added - i);
memcpy(run->dynfile->data + off + len + i, tmp, copy_len);
}
}
static void mangle_BlockSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
if (run->dynfile->size < 8) return;
size_t max_len = run->dynfile->size / 4;
if (max_len < 1) return;
size_t len = util_rndGet(1, HF_MIN(max_len, 256));
size_t space = run->dynfile->size - len * 2;
if (space < 1) return;
size_t off1 = util_rndGet(0, space);
size_t gap = run->dynfile->size - off1 - len * 2;
size_t off2 = off1 + len + (gap > 0 ? util_rndGet(0, gap) : 0);
if (off2 + len > run->dynfile->size) return;
uint8_t* tmp = util_Malloc(len);
defer {
free(tmp);
};
memcpy(tmp, run->dynfile->data + off1, len);
memmove(run->dynfile->data + off1, run->dynfile->data + off2, len);
memcpy(run->dynfile->data + off2, tmp, len);
}
static void mangle_CmpSolve(run_t* run, bool printable) {
if (!run->global->feedback.cmpFeedback) {
mangle_ConstFeedbackDict(run, printable);
return;
}
cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
uint32_t cnt = ATOMIC_GET(cmpf->cnt);
if (cnt == 0) {
mangle_Magic(run, printable);
return;
}
if (cnt > ARRAYSIZE(cmpf->valArr)) {
cnt = ARRAYSIZE(cmpf->valArr);
}
uint32_t choice = util_rndGet(0, cnt - 1);
size_t cmp_len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
if (cmp_len == 0 || cmp_len > 32) {
mangle_Magic(run, printable);
return;
}
uint8_t cmp_val[32];
memcpy(cmp_val, cmpf->valArr[choice].val, cmp_len);
/* Find partial match in input */
for (size_t off = 0; off + cmp_len <= run->dynfile->size; off++) {
size_t matches = 0;
for (size_t i = 0; i < cmp_len; i++) {
if (run->dynfile->data[off + i] == cmp_val[i]) matches++;
}
if (matches > 0 && matches < cmp_len) {
/* Gradient - 50% exact, 25% val+1, 25% val-1 */
uint64_t r = util_rndGet(0, 3);
if (r == 1 && cmp_len <= 8) {
/* Increment as little-endian integer */
for (size_t i = 0; i < cmp_len; i++) {
if (++cmp_val[i] != 0) break;
}
} else if (r == 2 && cmp_len <= 8) {
/* Decrement as little-endian integer */
for (size_t i = 0; i < cmp_len; i++) {
if (cmp_val[i]-- != 0) break;
}
}
mangle_Overwrite(run, off, cmp_val, cmp_len, printable);
return;
}
}
mangle_UseValue(run, cmp_val, cmp_len, printable);
}
static void mangle_InterestingValues(run_t* run, bool printable) {
static const struct {
const uint8_t val[8];
const size_t len;
} interestingVals[] = {
/* 8-bit */
{{0x00}, 1},
{{0x01}, 1},
{{0x7f}, 1},
{{0x80}, 1},
{{0xff}, 1},
/* 16-bit */
{{0x7f, 0xff}, 2},
{{0x80, 0x00}, 2},
{{0xff, 0xff}, 2},
{{0x00, 0x01}, 2},
{{0x00, 0x00}, 2},
/* 32-bit */
{{0x7f, 0xff, 0xff, 0xff}, 4},
{{0x80, 0x00, 0x00, 0x00}, 4},
{{0xff, 0xff, 0xff, 0xff}, 4},
{{0x00, 0x00, 0x00, 0x01}, 4},
{{0x00, 0x00, 0x00, 0x00}, 4},
/* 64-bit */
{{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 8},
{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8},
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 8},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 8},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8},
};
size_t choice = util_rndGet(0, ARRAYSIZE(interestingVals) - 1);
mangle_UseValue(run, interestingVals[choice].val, interestingVals[choice].len, printable);
}
static void mangle_SpecialStrings(run_t* run, bool printable) {
static const char* const strings[] = {
/* Format strings */
"%s",
"%n",
"%x",
"%p",
/* SQL Injection / Quote imbalance */
"'",
"\"",
"`",
"1=1",
"--",
"/*",
"*/",
/* Path */
"../",
"..\\",
"/etc/passwd",
"boot.ini",
/* XML/HTML */
"<",
">",
"<script>",
"javascript:",
"CDATA",
/* JSON/Misc */
"null",
"true",
"false",
"NaN",
"Infinity",
"undefined",
"{}",
"[]",
/* Command Injection */
"|",
";",
"`",
"$(",
};
const char* val = strings[util_rndGet(0, ARRAYSIZE(strings) - 1)];
mangle_UseValue(run, (const uint8_t*)val, strlen(val), printable);
}
static void mangle_ChunkShuffle(run_t* run, bool printable HF_ATTR_UNUSED) {
if (run->dynfile->size < 8) return;
size_t chunk_size = util_rndGet(1, 4);
size_t num_chunks = run->dynfile->size / chunk_size;
if (num_chunks < 2) return;
size_t max_swaps = num_chunks / 2;
if (max_swaps < 1) max_swaps = 1;
size_t swaps = util_rndGet(1, max_swaps);
for (size_t s = 0; s < swaps; s++) {
size_t i = util_rndGet(0, num_chunks - 1);
size_t j = util_rndGet(0, num_chunks - 1);
if (i == j) continue;
for (size_t k = 0; k < chunk_size; k++) {
uint8_t tmp = run->dynfile->data[i * chunk_size + k];
run->dynfile->data[i * chunk_size + k] = run->dynfile->data[j * chunk_size + k];
run->dynfile->data[j * chunk_size + k] = tmp;
}
}
}
static void mangle_Arith8(run_t* run, bool printable) {
size_t off = mangle_getOffSet(run);
int8_t delta = (int8_t)util_rndGet(1, 35) * (util_rnd64() & 1 ? 1 : -1);
run->dynfile->data[off] = (uint8_t)((int8_t)run->dynfile->data[off] + delta);
if (printable) {
util_turnToPrintable(&run->dynfile->data[off], 1);
}
}
static void mangle_CrossOver(run_t* run, bool printable) {
if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
mangle_Bytes(run, printable);
return;
}
if (run->dynfile->size < 2) {
mangle_Bytes(run, printable);
return;
}
/* Use diverse input selection for better coverage combination */
size_t other_sz = 0;
const uint8_t* other = input_getDiverseInputAsBuf(run, &other_sz);
if (!other || other_sz == 0) {
mangle_Bytes(run, printable);
return;
}
size_t crossover_point = util_rndGet(1, run->dynfile->size - 1);
size_t other_point = util_rndGet(0, other_sz - 1);
size_t copy_len = HF_MIN(run->dynfile->size - crossover_point, other_sz - other_point);
if (copy_len > 0) {
mangle_Overwrite(run, crossover_point, &other[other_point], copy_len, printable);
}
}
/*
* Mutation scheduling
*/
typedef enum { TIER_DATA = 0, TIER_ARITH = 1, TIER_SPLICE = 2, TIER_OTHER = 3 } tier_t;
/* Mutation tier arrays - shared between picker and stagnation booster */
static const mangle_t tierData[] = {
MANGLE_INTERESTING_VALUES,
MANGLE_MAGIC,
MANGLE_STATIC_DICT,
MANGLE_CONST_FEEDBACK_DICT,
MANGLE_CMP_SOLVE,
MANGLE_SPECIAL_STRINGS,
};
static const mangle_t tierArith[] = {
MANGLE_BIT,
MANGLE_INC_BYTE,
MANGLE_DEC_BYTE,
MANGLE_NEG_BYTE,
MANGLE_ADD_SUB,
MANGLE_ARITH8,
};
static const mangle_t tierSplice[] = {MANGLE_SPLICE, MANGLE_CROSS_OVER};
static const mangle_t tierStructure[] = {
MANGLE_CHUNK_SHUFFLE,
MANGLE_BLOCK_REPEAT,
MANGLE_BLOCK_SWAP,
MANGLE_BLOCK_MOVE,
};
static inline mangle_t mangle_pickFromList(const mangle_t* list, size_t cnt) {
return cnt > 0 ? list[util_rndGet(0, cnt - 1)] : (mangle_t)util_rndGet(0, MANGLE_COUNT - 1);
}
static inline mangle_t mangle_sanitize(run_t* run, mangle_t m) {
if ((unsigned)m >= MANGLE_COUNT) {
return (mangle_t)util_rndGet(0, MANGLE_COUNT - 1);
}
static const struct {
const uint8_t needs;
const mangle_t fallback;
} reqs[MANGLE_COUNT] = {
[MANGLE_STATIC_DICT] = {1, MANGLE_MAGIC},
[MANGLE_CONST_FEEDBACK_DICT] = {2, MANGLE_MAGIC},
[MANGLE_CMP_SOLVE] = {2, MANGLE_MAGIC},
[MANGLE_SPLICE] = {4, MANGLE_RANDOM_BUF},
[MANGLE_CROSS_OVER] = {4, MANGLE_BYTES},
};
uint8_t need = reqs[m].needs;
if (!need) return m;
if ((need & 1) && run->global->mutate.dictionaryCnt == 0) return reqs[m].fallback;
if ((need & 2) && !run->global->feedback.cmpFeedback) return reqs[m].fallback;
if ((need & 4) && run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE)
return reqs[m].fallback;
return m;
}
static mangle_t mangle_pickWeighted(run_t* run, uint8_t* tier_out) {
/*
* Adaptive weights - start with defaults, adjust based on success rate.
* Use a simplified momentum-like approach where recent success bumps the weight
*/
uint8_t w[4] = {40, 25, 20, 15};
for (int i = 0; i < 4; i++) {
uint64_t tries = ATOMIC_GET(run->global->mutate.stats[i].tries);
if (tries < 500) {
continue; /* Not enough data yet */
}
uint64_t hits = ATOMIC_GET(run->global->mutate.stats[i].successes);
uint64_t rate = (hits * 10000) / tries; /* x10000 for precision */
/*
* Baseline success rate is low (fuzzing is hard), so even small rates are good.
* Adjust weights proportionally to performance relative to others.
*/
if (rate > 50) { /* > 0.5% success rate is very good */
w[i] = HF_MIN(w[i] + 10, 80);
} else if (rate > 10) { /* > 0.1% */
w[i] = HF_MIN(w[i] + 2, 60);
} else if (rate < 1) { /* < 0.01% */
w[i] = HF_MAX(w[i] / 2, 5);
}
}
/* Roll weighted random */
uint16_t sum = w[0] + w[1] + w[2] + w[3];
uint8_t roll = util_rndGet(0, sum - 1);
mangle_t choice;
uint8_t tier;
if (roll < w[0]) {
choice = mangle_pickFromList(tierData, ARRAYSIZE(tierData));
tier = TIER_DATA;
} else if (roll < w[0] + w[1]) {
choice = mangle_pickFromList(tierArith, ARRAYSIZE(tierArith));
tier = TIER_ARITH;
} else if (roll < w[0] + w[1] + w[2]) {
choice = mangle_pickFromList(tierSplice, ARRAYSIZE(tierSplice));
tier = TIER_SPLICE;
} else {
choice = (mangle_t)util_rndGet(0, MANGLE_COUNT - 1);
tier = TIER_OTHER;
}
*tier_out = tier;
return mangle_sanitize(run, choice);
}
/* Dispatch table - enum -> function pointer */
static void (*const mangleFuncs[MANGLE_COUNT])(run_t*, bool) = {
[MANGLE_SHRINK] = mangle_Shrink,
[MANGLE_EXPAND] = mangle_Expand,
[MANGLE_BIT] = mangle_Bit,
[MANGLE_INC_BYTE] = mangle_IncByte,
[MANGLE_DEC_BYTE] = mangle_DecByte,
[MANGLE_NEG_BYTE] = mangle_NegByte,
[MANGLE_ADD_SUB] = mangle_AddSub,
[MANGLE_ARITH8] = mangle_Arith8,
[MANGLE_MEM_SET] = mangle_MemSet,
[MANGLE_MEM_CLR] = mangle_MemClr,
[MANGLE_MEM_SWAP] = mangle_MemSwap,
[MANGLE_MEM_COPY] = mangle_MemCopy,
[MANGLE_BLOCK_MOVE] = mangle_BlockMove,
[MANGLE_BLOCK_REPEAT] = mangle_BlockRepeat,
[MANGLE_BLOCK_SWAP] = mangle_BlockSwap,
[MANGLE_CHUNK_SHUFFLE] = mangle_ChunkShuffle,
[MANGLE_BYTES] = mangle_Bytes,
[MANGLE_BYTE_REPEAT] = mangle_ByteRepeat,
[MANGLE_RANDOM_BUF] = mangle_RandomBuf,
[MANGLE_INTERESTING_VALUES] = mangle_InterestingValues,
[MANGLE_ASCII_NUM] = mangle_ASCIINum,
[MANGLE_ASCII_NUM_CHANGE] = mangle_ASCIINumChange,
[MANGLE_MAGIC] = mangle_Magic,
[MANGLE_STATIC_DICT] = mangle_StaticDict,
[MANGLE_CONST_FEEDBACK_DICT] = mangle_ConstFeedbackDict,
[MANGLE_CMP_SOLVE] = mangle_CmpSolve,
[MANGLE_SPLICE] = mangle_Splice,
[MANGLE_CROSS_OVER] = mangle_CrossOver,
[MANGLE_SPECIAL_STRINGS] = mangle_SpecialStrings,
};
static inline void mangle_dispatch(run_t* run, mangle_t m, bool printable) {
mangleFuncs[mangle_sanitize(run, m)](run, printable);
}
void mangle_mangleContent(run_t* run) {
if (run->mutationsPerRun == 0U) {
return;
}
bool printable = run->global->cfg.only_printable;
if (run->dynfile->size == 0U) {
mangle_Resize(run, printable);
}
time_t stagnation = time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate);
uint64_t base = run->mutationsPerRun;
bool haveCmp = run->global->feedback.cmpFeedback;
run->mutationTiers = 0;
const time_t timeStagnated = 10;
const time_t timeStuck = 60;
const time_t timeGivenUp = 300;
/* Scale mutation count with stagnation */
uint8_t mult = 1, cap = 16, min = 1;
if (stagnation > timeGivenUp) {
mult = 4;
cap = 64;
min = 2;
} else if (stagnation > timeStuck) {
mult = 2;
cap = 32;
}
uint64_t count = util_rndGet(min, HF_MIN(base * mult, cap));
/*
* Extra mutations when stagnating.
* If we are stuck, we want to try more specific strategies (dictionaries, splices)
*/
if (stagnation > timeStagnated) {
if (haveCmp && util_rnd64() % 3 == 0) {
run->mutationTiers |= (1 << TIER_DATA);
mangle_dispatch(run, MANGLE_CMP_SOLVE, printable);
}
if (util_rnd64() % 2 == 0) {
run->mutationTiers |= (1 << TIER_SPLICE);
mangle_dispatch(run, MANGLE_SPLICE, printable);
}
}
if (stagnation > timeStuck && util_rnd64() % 3 == 0) {
run->mutationTiers |= (1 << TIER_SPLICE);
mangle_dispatch(run, MANGLE_CROSS_OVER, printable);
}
if (stagnation > timeGivenUp && util_rnd64() % 8 == 0) {
run->mutationTiers |= (1 << TIER_OTHER);
mangle_dispatch(
run, mangle_pickFromList(tierStructure, ARRAYSIZE(tierStructure)), printable);
}
/* Main mutation loop */
for (uint64_t i = 0; i < count; i++) {
uint8_t tier;
mangle_t m = mangle_pickWeighted(run, &tier);
/*
* Boost data mutations when stagnating - if stuck for >30s,
* 25% chance to force a data mutation (dictionaries, magic values)
*/
if (stagnation > (timeStuck / 2) && util_rnd64() % 4 == 0) {
m = mangle_sanitize(run, mangle_pickFromList(tierData, ARRAYSIZE(tierData)));
tier = TIER_DATA;
}
run->mutationTiers |= (1 << tier);
ATOMIC_POST_INC(run->global->mutate.stats[tier].tries);
mangle_dispatch(run, m, printable);
}
}