Skip to content

Commit

Permalink
Begin work on a "structured" mutator mode (#795)
Browse files Browse the repository at this point in the history
* Begin work on a "structured" mutator mode

* mutator: fill in structured mode

* worker: re-enable udis86

* README: document the MODE env var
  • Loading branch information
woodruffw authored Jan 9, 2021
1 parent 067ff92 commit d80063a
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 12 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Run the fuzzer for a bit:
* `V=1` enables verbose output on `stderr`
* `D=1` enables the "dummy" mutation mode for debugging purposes
* `M=1` enables the "manual" mutation mode (i.e., read from `stdin`)
* `MODE=mode` can be used to configure the mutation mode in the absence of `D` and `M`
* Valid mutation modes are `sliding` (default), `havoc`, and `structured`

Convert mishegos's raw output into JSONL suitable for analysis:

Expand Down
1 change: 1 addition & 0 deletions src/include/mish_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ typedef enum {
typedef enum {
M_HAVOC = 0,
M_SLIDING,
M_STRUCTURED,
M_DUMMY,
M_MANUAL,
} mutator_mode;
Expand Down
24 changes: 23 additions & 1 deletion src/mishegos/mishegos.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,25 @@ static void mishegos_sem_init() {
}
}

static mutator_mode get_mut_mode() {
const char *mode = getenv("MODE");

/* default to the "sliding" strategy in the mutator. */
if (mode == NULL) {
return M_SLIDING;
}

if (strcmp(mode, "sliding") == 0) {
return M_SLIDING;
} else if (strcmp(mode, "havoc") == 0) {
return M_HAVOC;
} else if (strcmp(mode, "structured") == 0) {
return M_STRUCTURED;
}

errx(1, "unknown mutator mode requested: %s", mode);
}

static void config_init() {
/* TODO(ww): Configurable RNG seed.
*/
Expand All @@ -195,7 +214,10 @@ static void config_init() {
} else if (debugging) {
GET_CONFIG()->mut_mode = M_DUMMY;
} else {
GET_CONFIG()->mut_mode = M_SLIDING;
/* If we're not in a manual or debugging mode, try to figure out what
* actual fuzzing mode the user wants from us.
*/
GET_CONFIG()->mut_mode = get_mut_mode();
}
}

Expand Down
86 changes: 75 additions & 11 deletions src/mishegos/mutator.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,72 @@ static bool sliding_candidate(input_slot *slot) {
return true;
}

/* Structured: generate an instruction candidate with the
* "structured" approach.
*/
static bool structured_candidate(input_slot *slot) {
/* We mirror build_sliding_candidate here, but with the constraint that
* we never overapproximate: we constrain ourselves to trying
* to build something that looks like an instruction of no more
* than 15 bytes.
*/

uint8_t len = 0;

/* Up to 4 legacy prefixes. Like sliding, we don't try to enforce group rules.
* Unlike sliding, we allow for the possibility of no legacy prefixes.
* Running max: 4.
*/
uint8_t prefix_count = (rand_byte() % 5);
for (int i = 0; i < prefix_count; ++i) {
slot->raw_insn[i] = legacy_prefixes[rand_byte() % sizeof(legacy_prefixes)];
}
len = prefix_count;

/* One or none REX prefixes.
* Always choose a valid REX prefix if we're inserting one.
* Running max: 5.
*/
if (rand_byte() % 2) {
slot->raw_insn[len] = rex_prefixes[rand_byte() % sizeof(rex_prefixes)];
len++;
}

/* Random (but structured) opcode. Same as sliding.
* Running max: 8
*/
opcode opc;
rand_opcode(&opc);
memcpy(slot->raw_insn + len, opc.op, opc.len);
len += opc.len;

/* One or none ModR/M bytes, and one or none SIB bytes.
* Both of these are just 8-bit LUTs, so they can be fully random.
* Running max: 10.
*/
if (rand_byte() % 2) {
slot->raw_insn[len] = rand_byte();
len++;
}

if (rand_byte() % 2) {
slot->raw_insn[len] = rand_byte();
len++;
}

/* Finally, we have up to 5 bytes to play with for the immediate and
* displacement. Fill some amount of that (maybe not all) with randomness.
*/
uint64_t tail = rand_long();
uint8_t tail_size = rand_byte() % 6;
memcpy(slot->raw_insn + len, &tail, tail_size);
len += tail_size;

slot->len = len;

return true;
}

/* Dummy: Generates a single NOP for debugging purposes.
*/
static bool dummy_candidate(input_slot *slot) {
Expand Down Expand Up @@ -285,25 +351,23 @@ void mutator_init() {
* Returns false if the configured mutation mode has been exhausted.
*/
bool candidate(input_slot *slot) {
bool exhausted;

switch (mut_mode) {
case M_HAVOC: {
exhausted = havoc_candidate(slot);
break;
return havoc_candidate(slot);
}
case M_SLIDING: {
exhausted = sliding_candidate(slot);
break;
return sliding_candidate(slot);
}
case M_STRUCTURED: {
return structured_candidate(slot);
}
case M_DUMMY: {
exhausted = dummy_candidate(slot);
break;
return dummy_candidate(slot);
}
case M_MANUAL: {
exhausted = manual_candidate(slot);
break;
return manual_candidate(slot);
}
}
return exhausted;

__builtin_unreachable();
}

0 comments on commit d80063a

Please sign in to comment.