aboutsummaryrefslogtreecommitdiff
path: root/custom_mutators
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2023-08-22 17:32:56 +0000
committerGitHub <noreply@github.com>2023-08-22 17:32:56 +0000
commitb397bdc3d976921a9b936f21273adc3a1bf9d4f4 (patch)
tree454e220dae35bd009710ef75a7ec77b44520b935 /custom_mutators
parentf596a297c4de6a5e1a6fb9fbb3b4e18124a24f58 (diff)
parente2026f7b71752c9b0bbba7438e2c62f2a4bca7f0 (diff)
downloadafl++-b397bdc3d976921a9b936f21273adc3a1bf9d4f4.tar.gz
Merge pull request #1841 from AFLplusplus/dev
Dev
Diffstat (limited to 'custom_mutators')
-rw-r--r--custom_mutators/aflpp_tritondse/aflpp_tritondse.py2
-rw-r--r--custom_mutators/examples/README.md3
-rw-r--r--custom_mutators/examples/elf_header_mutator.c679
3 files changed, 683 insertions, 1 deletions
diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
index 58b506b6..58739696 100644
--- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
+++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
@@ -164,7 +164,7 @@ def init(seed):
format = SeedFormat.COMPOSITE
# Now set up TritonDSE
config = Config(coverage_strategy = CoverageStrategy.PATH,
- debug = is_debug,
+ # debug = is_debug,
pipe_stdout = is_debug,
pipe_stderr = is_debug,
execution_timeout = 1,
diff --git a/custom_mutators/examples/README.md b/custom_mutators/examples/README.md
index 655f7a5e..112db243 100644
--- a/custom_mutators/examples/README.md
+++ b/custom_mutators/examples/README.md
@@ -33,3 +33,6 @@ like surgical_havoc_mutate() that allow to perform a randomly chosen
mutation from a subset of the havoc mutations.
If you do so, you have to specify -I /path/to/AFLplusplus/include when
compiling.
+
+elf_header_mutator.c - example ELF header mutator based on
+ [LibGolf](https://github.com/xcellerator/libgolf/)
diff --git a/custom_mutators/examples/elf_header_mutator.c b/custom_mutators/examples/elf_header_mutator.c
new file mode 100644
index 00000000..b985257a
--- /dev/null
+++ b/custom_mutators/examples/elf_header_mutator.c
@@ -0,0 +1,679 @@
+/*
+ AFL++ Custom Mutator for ELF Headers
+ Written by @echel0n <melih.sahin@protonmail.com>
+ based on libgolf.h by @xcellerator
+ $ gcc -O3 -fPIC -shared -o elf_mutator.so -I ~/AFLplusplus/include/
+ */
+#include "afl-fuzz.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <linux/elf.h>
+
+/* EI_ABIVERSION isn't used anymore and elf.h defines EI_PAD to be 0x09 */
+#define EI_ABIVERSION 0x08
+#define EI_PAD 0x09
+/* Define the Architecture and ISA constants to match those in <linux/elf.h> */
+#define X86_64 EM_X86_64
+#define ARM32 EM_ARM
+#define AARCH64 EM_AARCH64
+#define uchar unsigned char
+#define DATA_SIZE 0x100
+
+/*
+ * The ELF and Program headers are different sizes depending on 32- and 64-bit
+ * architectures
+ * taken from libgolf.h
+ */
+#define EHDR_T(x) Elf##x##_Ehdr
+#define PHDR_T(x) Elf##x##_Phdr
+#define EHDR(x) ehdr##x
+#define PHDR(x) phdr##x
+#define GET_EHDR(x) (&(elf_ptr->EHDR(x)));
+#define GET_PHDR(x) (&(elf_ptr->PHDR(x)));
+#define REF_EHDR(b, x) ((Elf##b##_Ehdr *)ehdr)->x
+#define REF_PHDR(b, x) ((Elf##b##_Phdr *)phdr)->x
+int ehdr_size;
+int phdr_size;
+/*
+ * This struct holds the bytes that will be executed, and the size.
+ */
+typedef struct text_segment {
+
+ size_t text_size;
+ unsigned char *text_segment;
+
+} TextSegment;
+
+// example shellcode that exits
+// taken from libgolf.h
+unsigned char buf[] = {0xb0, 0x3c, 0x31, 0xff, 0x0f, 0x05};
+
+/*
+ * This is the raw ELF file
+ * - EHDR(xx) is the ELF header
+ * - PHDR(xx) is the program header
+ * - text is the text segment
+ * - filename is the name of the golf'd binary
+ * - isa is the target architecture (X86_64, ARM32, AARCH64)
+ * taken from libgolf.h
+ */
+typedef struct rawbinary_t {
+
+ EHDR_T(32) EHDR(32);
+ PHDR_T(32) PHDR(32);
+ EHDR_T(64) EHDR(64);
+ PHDR_T(64) PHDR(64);
+ TextSegment text;
+ char *filename;
+ int isa;
+
+} RawBinary;
+
+/*
+ * Copy an E_IDENT array into the corresponding fields in the ELF header
+ * Called by populate_ehdr()
+ * taken from libgolf.h
+ */
+int populate_e_ident(RawBinary *elf_ptr, unsigned char e_ident[]) {
+
+ int i;
+ /* Depending on whether the target ISA is 32- or 64-bit, set e_ident */
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ for (i = 0; i < EI_NIDENT; i++)
+ elf_ptr->EHDR(64).e_ident[i] = e_ident[i];
+ break;
+ case ARM32:
+ for (i = 0; i < EI_NIDENT; i++)
+ elf_ptr->EHDR(32).e_ident[i] = e_ident[i];
+ break;
+ default:
+ exit(1);
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Copy bytes from buf[] array into text_segment in ELF struct
+ * taken from libgolf.h
+ */
+int copy_text_segment(RawBinary *elf_ptr, unsigned char buf[], int text_size) {
+
+ int i;
+
+ /* Set size of text segment and allocate the buffer */
+ elf_ptr->text.text_size = text_size;
+ elf_ptr->text.text_segment =
+ malloc(elf_ptr->text.text_size * sizeof(unsigned char));
+
+ /* Copy the bytes into the text segment buffer */
+ for (i = 0; i < elf_ptr->text.text_size; i++) {
+
+ elf_ptr->text.text_segment[i] = buf[i];
+
+ }
+
+}
+
+/*
+ * Populate the ELF Header with sane values
+ * Returns a pointer to an EHDR struct
+ * taken from libgolf.h
+ */
+void *populate_ehdr(RawBinary *elf_ptr) {
+
+ /*
+ * Set ehdr_size and phdr_size. Determined by whether target ISA is 32- or
+ * 64-bit.
+ */
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ ehdr_size = sizeof(EHDR_T(64));
+ phdr_size = sizeof(PHDR_T(64));
+ break;
+ case ARM32:
+ ehdr_size = sizeof(EHDR_T(32));
+ phdr_size = sizeof(PHDR_T(32));
+ break;
+ default:
+ exit(1);
+
+ };
+
+ /* Start with the E_IDENT area at the top of the file */
+ unsigned char e_ident[EI_NIDENT] = {0};
+
+ /* Magic Bytes */
+ e_ident[EI_MAG0] = 0x7F;
+ e_ident[EI_MAG1] = 0x45; // E
+ e_ident[EI_MAG2] = 0x4C; // L
+ e_ident[EI_MAG3] = 0x46; // F
+
+ /*
+ * EI_CLASS denotes the architecture:
+ * ELFCLASS32: 0x01
+ * ELFCLASS64: 0x02
+ */
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ e_ident[EI_CLASS] = ELFCLASS64;
+ break;
+ case ARM32:
+ e_ident[EI_CLASS] = ELFCLASS32;
+ break;
+ default:
+ exit(1);
+
+ }
+
+ /*
+ * EI_DATA denotes the endianness:
+ * ELFDATA2LSB: 0x01
+ * ELFDATA2MSB: 0x02
+ */
+ e_ident[EI_DATA] = ELFDATA2LSB;
+
+ /* EI_VERSION is always 0x01 */
+ e_ident[EI_VERSION] = EV_CURRENT;
+
+ /*
+ * EI_OSABI defines the target OS. Ignored by most modern ELF parsers.
+ */
+ e_ident[EI_OSABI] = ELFOSABI_NONE;
+
+ /* EI_ABIVERSION was for sub-classification. Un-defined since Linux 2.6 */
+ e_ident[EI_ABIVERSION] = 0x00;
+
+ /* EI_PAD is currently unused */
+ e_ident[EI_PAD] = 0x00;
+
+ /* Copy the E_IDENT section to the ELF struct */
+ populate_e_ident(elf_ptr, e_ident);
+
+ /*
+ * The remainder of the ELF header following E_IDENT follows.
+ *
+ * ehdr is a pointer to either an Elf32_Edhr, or Elf64_Ehdr struct.
+ */
+ void *ehdr = NULL;
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ ehdr = (&(elf_ptr->EHDR(64)));
+ break;
+ case ARM32:
+ ehdr = (&(elf_ptr->EHDR(32)));
+ break;
+ default:
+ exit(1);
+
+ }
+
+ /*
+ * Depending on whether the ISA is 32- or 64-bit determines the size of
+ * many of the fields in the ELF Header. This switch case deals with it.
+ */
+ switch (elf_ptr->isa) {
+
+ // 64-Bit ISAs
+ case X86_64:
+ case AARCH64:
+ /*
+ * e_type specifies what kind of ELF file this is:
+ * ET_NONE: 0x00 // Unknown Type
+ * ET_REL: 0x01 // Relocatable
+ * ET_EXEC: 0x02 // Executable File
+ * ET_DYN: 0x03 // Shared Object
+ * ET_CORE: 0x04 // Core Dump
+ */
+ REF_EHDR(64, e_type) = ET_EXEC; // 0x0002
+
+ /* e_machine specifies the target ISA */
+ REF_EHDR(64, e_machine) = elf_ptr->isa;
+
+ /* e_version is always set of 0x01 for the original ELF spec */
+ REF_EHDR(64, e_version) = EV_CURRENT; // 0x00000001
+
+ /*
+ * e_entry is the memory address of the entry point
+ * Set by set_entry_point() after p_vaddr is set in the phdr
+ */
+ REF_EHDR(64, e_entry) = 0x0;
+
+ /*
+ * e_phoff points to the start of the program header, which
+ * immediately follows the ELF header
+ */
+ REF_EHDR(64, e_phoff) = ehdr_size;
+
+ /* e_shoff points to the start of the section header table */
+ REF_EHDR(64, e_shoff) = 0x00;
+
+ /* e_flags is architecture dependent */
+ REF_EHDR(64, e_flags) = 0x0;
+
+ /* e_ehsize contains the size of the ELF header */
+ REF_EHDR(64, e_ehsize) = ehdr_size;
+
+ /* e_phentsize is the size of the program header */
+ REF_EHDR(64, e_phentsize) = phdr_size;
+
+ /*
+ * e_phnum contains the number of entries in the program header
+ * e_phnum * e_phentsize = size of program header table
+ */
+ REF_EHDR(64, e_phnum) = 0x1;
+
+ /* e_shentsize contains the size of a section header entry */
+ REF_EHDR(64, e_shentsize) = 0x0;
+
+ /*
+ * e_shnum contains the number of entries in the section header
+ * e_shnum * e_shentsize = size of section header table
+ */
+ REF_EHDR(64, e_shnum) = 0x0;
+
+ /*
+ * e_shstrndx contains the index of the section header table that
+ * contains the section names
+ */
+ REF_EHDR(64, e_shstrndx) = 0x0;
+
+ break;
+ // 32-Bit ISAs
+ case ARM32:
+ /*
+ * e_type specifies what kind of ELF file this is:
+ * ET_NONE: 0x00 // Unknown Type
+ * ET_REL: 0x01 // Relocatable
+ * ET_EXEC: 0x02 // Executable File
+ * ET_DYN: 0x03 // Shared Object
+ * ET_CORE: 0x04 // Core Dump
+ */
+ REF_EHDR(32, e_type) = ET_EXEC; // 0x0002
+
+ /* e_machine specifies the target ISA */
+ REF_EHDR(32, e_machine) = elf_ptr->isa;
+
+ /* e_version is always set of 0x01 for the original ELF spec */
+ REF_EHDR(32, e_version) = EV_CURRENT; // 0x00000001
+
+ /*
+ * e_entry is the memory address of the entry point
+ * Set by set_entry_point() after p_vaddr is set in the phdr
+ */
+ REF_EHDR(32, e_entry) = 0x0;
+
+ /*
+ * e_phoff points to the start of the program header, which
+ * immediately follows the ELF header
+ */
+ REF_EHDR(32, e_phoff) = ehdr_size;
+
+ /* e_shoff points to the start of the section header table */
+ REF_EHDR(32, e_shoff) = 0x0i;
+
+ /* e_flags is architecture dependent */
+ REF_EHDR(32, e_flags) = 0x0;
+
+ /* e_ehsize contains the size of the ELF header */
+ REF_EHDR(32, e_ehsize) = ehdr_size;
+
+ /* e_phentsize is the size of the program header */
+ REF_EHDR(32, e_phentsize) = phdr_size;
+
+ /*
+ * e_phnum contains the number of entries in the program header
+ * e_phnum * e_phentsize = size of program header table
+ */
+ REF_EHDR(32, e_phnum) = 0x1;
+
+ /* e_shentsize contains the size of a section header entry */
+ REF_EHDR(32, e_shentsize) = 0x0;
+
+ /*
+ * e_shnum contains the number of entries in the section header
+ * e_shnum * e_shentsize = size of section header table
+ */
+ REF_EHDR(32, e_shnum) = 0x0;
+
+ /*
+ * e_shstrndx contains the index of the section header table that
+ * contains the section names
+ */
+ REF_EHDR(32, e_shnum) = 0x0;
+
+ break;
+
+ }
+
+ return ehdr;
+
+}
+
+/*
+ * Populate the program headers with sane values
+ * Returns a pointer to a PHDR struct
+ * taken from libgolf.h
+ */
+void *populate_phdr(RawBinary *elf_ptr) {
+
+ /*
+ * All offsets are relative to the start of the program header (0x40)
+ *
+ * phdr is a pointer to either an Elf32_Phdr, or Elf64_Phdr struct.
+ */
+ void *phdr = NULL;
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ phdr = (&(elf_ptr->PHDR(64)));
+ break;
+ case ARM32:
+ phdr = (&(elf_ptr->PHDR(32)));
+ break;
+ default:
+ exit(1);
+
+ }
+
+ /*
+ * Depending on whether the ISA is 32- or 64-bit determines the size of
+ * many of the fields in the Progra Header. This switch case deals with it.
+ */
+ switch (elf_ptr->isa) {
+
+ // 64-Bit ISAs
+ case X86_64:
+ case AARCH64:
+ /*
+ * p_type identifies what type of segment this is
+ * PT_NULL: 0x0 // Unused
+ * PT_LOAD: 0x1 // Loadable Segment
+ * PT_DYNAMIC: 0x2 // Dynamic Linker Information
+ * PT_INTERP: 0x3 // Interpreter Information
+ * PT_NOTE: 0x4 // Auxiliary Information
+ * PT_SHLIB: 0x5 // Reserved
+ * PT_PHDR: 0x6 // Segment with Program Header
+ * PT_TLS: 0x7 // Thread Local Storage
+ */
+ REF_PHDR(64, p_type) = PT_LOAD; // 0x1
+
+ /*
+ * p_flags defines permissions for this section
+ * PF_R: 0x4 // Read
+ * PF_W: 0x2 // Write
+ * PF_X: 0x1 // Execute
+ */
+ REF_PHDR(64, p_flags) = PF_R | PF_X; // 0x5
+
+ /*
+ * p_offset is the offset in the file image (relative to the start
+ * of the program header) for this segment.
+ */
+ REF_PHDR(64, p_offset) = 0x0;
+
+ /*
+ * p_vaddr is the virtual address where this segment should be loaded
+ * p_paddr is for the physical address (unused by System V)
+ */
+ REF_PHDR(64, p_vaddr) = 0x400000;
+ REF_PHDR(64, p_paddr) = 0x400000;
+
+ /*
+ * p_filesz is the size of the segment in the file image
+ * p_memsz is the size of the segment in memory
+ *
+ * Note: p_filesz doesn't have to equal p_memsz
+ */
+ REF_PHDR(64, p_filesz) = elf_ptr->text.text_size;
+ REF_PHDR(64, p_memsz) = elf_ptr->text.text_size;
+
+ break;
+ // 32-Bit ISAs
+ case ARM32:
+ /*
+ * p_type identifies what type of segment this is
+ * PT_NULL: 0x0 // Unused
+ * PT_LOAD: 0x1 // Loadable Segment
+ * PT_DYNAMIC: 0x2 // Dynamic Linker Information
+ * PT_INTERP: 0x3 // Interpreter Information
+ * PT_NOTE: 0x4 // Auxiliary Information
+ * PT_SHLIB: 0x5 // Reserved
+ * PT_PHDR: 0x6 // Segment with Program Header
+ * PT_TLS: 0x7 // Thread Local Storage
+ */
+ REF_PHDR(32, p_type) = PT_LOAD; // 0x1
+
+ /*
+ * p_flags defines permissions for this section
+ * PF_R: 0x4 // Read
+ * PF_W: 0x2 // Write
+ * PF_X: 0x1 // Execute
+ */
+ REF_PHDR(32, p_flags) = PF_R | PF_X; // 0x5
+
+ /*
+ * p_offset is the offset in the file image (relative to the start
+ * of the program header) for this segment.
+ */
+ REF_PHDR(32, p_offset) = 0x0;
+
+ /*
+ * p_vaddr is the virtual address where this segment should be loaded
+ * p_paddr is for the physical address (unused by System V)
+ */
+ REF_PHDR(32, p_vaddr) = 0x10000;
+ REF_PHDR(32, p_paddr) = 0x10000;
+
+ /*
+ * p_filesz is the size of the segment in the file image
+ * p_memsz is the size of the segment in memory
+ *
+ * Note: p_filesz doesn't have to equal p_memsz
+ */
+ REF_PHDR(32, p_filesz) = elf_ptr->text.text_size;
+ REF_PHDR(32, p_memsz) = elf_ptr->text.text_size;
+
+ break;
+ default:
+ exit(1);
+
+ }
+
+ /*
+ * p_align is the memory alignment
+ *
+ * Note: p_vaddr = p_offset % p_align
+ */
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ REF_PHDR(64, p_align) = 0x400000;
+ break;
+ case ARM32:
+ REF_PHDR(32, p_align) = 0x10000;
+ break;
+ case AARCH64:
+ REF_PHDR(64, p_align) = 0x400000;
+ break;
+
+ }
+
+ return phdr;
+
+}
+
+/*
+ * e_entry depends on p_vaddr, so has to be set after populate_ehdr()
+ * and populate_phdr() have been called.
+ * taken from libgolf.h
+ */
+int set_entry_point(RawBinary *elf_ptr) {
+
+ /*
+ * Once the whole ELF file is copied into memory, control is handed to
+ * e_entry. Relative to the process's virtual memory address, the .text
+ * segment will be located immediately after the ELF and program header.
+ *
+ * ehdr and phdr are pointers to the ELF and Program headers respectively.
+ * The switch case casts and assigns them to the correct fields of the ELF
+ * struct, then sets ehdr->e_entry.
+ */
+ void *ehdr, *phdr;
+
+ switch (elf_ptr->isa) {
+
+ case X86_64:
+ case AARCH64:
+ ehdr = GET_EHDR(64);
+ phdr = GET_PHDR(64);
+ REF_EHDR(64, e_entry) = REF_PHDR(64, p_vaddr) + ehdr_size + phdr_size;
+ break;
+ case ARM32:
+ ehdr = GET_EHDR(32);
+ phdr = GET_PHDR(32);
+ REF_EHDR(32, e_entry) = REF_PHDR(32, p_vaddr) + ehdr_size + phdr_size;
+ break;
+ default:
+ exit(1);
+
+ }
+
+ return 0;
+
+}
+
+typedef struct my_mutator {
+
+ afl_state_t *afl;
+ size_t trim_size_current;
+ int trimmming_steps;
+ int cur_step;
+ u8 *mutated_out, *post_process_buf, *trim_buf;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+ srand(seed); // needed also by surgical_havoc_mutate()
+ my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+ if (!data) {
+
+ perror("afl_custom_init alloc");
+ return NULL;
+
+ }
+
+ 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;
+ return data;
+
+}
+
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *in_buf, size_t buf_size,
+ u8 **out_buf, uint8_t *add_buf,
+ size_t add_buf_size, // add_buf can be NULL
+ size_t max_size) {
+
+ RawBinary elf_obj;
+ RawBinary *elf = &elf_obj;
+ elf->isa = 62;
+ Elf64_Ehdr *ehdr;
+ Elf64_Phdr *phdr;
+ copy_text_segment(elf, buf, sizeof(buf));
+ ehdr = populate_ehdr(elf);
+ phdr = populate_phdr(elf);
+ set_entry_point(elf);
+
+ size_t mutated_size = ehdr_size + phdr_size + elf->text.text_size;
+ int pos = 0;
+ // example fields
+ ehdr->e_ident[EI_CLASS] = (uint8_t *)(in_buf + pos++);
+ ehdr->e_ident[EI_DATA] = (uint8_t *)(in_buf + pos++);
+ ehdr->e_ident[EI_VERSION] = (uint8_t *)(in_buf + pos++);
+ ehdr->e_ident[EI_OSABI] = (uint8_t *)(in_buf + pos++);
+ for (int i = 0x8; i < 0x10; ++i) {
+
+ (ehdr->e_ident)[i] = (uint8_t *)(in_buf + pos++);
+
+ }
+
+ ehdr->e_version = (uint32_t *)(in_buf + pos);
+ pos += 4;
+ // sections headers
+ ehdr->e_shoff = (uint64_t *)(in_buf + pos);
+ pos += 8;
+ ehdr->e_shentsize = (uint16_t *)(in_buf + pos);
+ pos += 2;
+ ehdr->e_shnum = (uint16_t *)(in_buf + pos);
+ pos += 2;
+ ehdr->e_shstrndx = (uint16_t *)(in_buf + pos);
+ pos += 2;
+ ehdr->e_flags = (uint32_t *)(in_buf + pos);
+ pos += 4;
+ // physical addr
+ phdr->p_paddr = (uint64_t *)(in_buf + pos);
+ pos += 8;
+ phdr->p_align = (uint64_t *)(in_buf + pos);
+ pos += 8;
+
+ /* mimic GEN_ELF()
+ * Write:
+ * - ELF Header
+ * - Program Header
+ * - Text Segment
+ */
+ memcpy(data->mutated_out, ehdr, ehdr_size);
+ memcpy(data->mutated_out + ehdr_size, phdr, phdr_size);
+ memcpy(data->mutated_out + ehdr_size + phdr_size, elf->text.text_segment,
+ elf->text.text_size);
+
+ *out_buf = data->mutated_out;
+ return mutated_size;
+
+}
+
+void afl_custom_deinit(my_mutator_t *data) {
+
+ free(data->post_process_buf);
+ free(data->mutated_out);
+ free(data->trim_buf);
+ free(data);
+
+}
+