mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-13 18:48:08 +00:00
Update examples of the custom mutator
- Merge `examples/python_mutators` into `examples/custom_mutators` - Remove `examples/python_mutators` - Update existing examples to demonstrate new APIs
This commit is contained in:
@ -231,7 +231,7 @@ checks or alter some of the more exotic semantics of the tool:
|
|||||||
performed with the custom mutator.
|
performed with the custom mutator.
|
||||||
This feature allows to configure custom mutators which can be very helpful,
|
This feature allows to configure custom mutators which can be very helpful,
|
||||||
e.g. fuzzing XML or other highly flexible structured input.
|
e.g. fuzzing XML or other highly flexible structured input.
|
||||||
Please see [custom_mutator.md](custom_mutator.md).
|
Please see [custom_mutators.md](custom_mutators.md).
|
||||||
|
|
||||||
- AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less
|
- AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less
|
||||||
precise), which can help when starting a session against a slow target.
|
precise), which can help when starting a session against a slow target.
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
# A simple example for AFL_CUSTOM_MUTATOR_LIBRARY
|
# Examples for the custom mutator
|
||||||
|
|
||||||
This is a simple example for the AFL_CUSTOM_MUTATOR_LIBRARY feature.
|
These are example and helper files for the custom mutator feature.
|
||||||
For more information see [docs/custom_mutator.md](../docs/custom_mutator.md)
|
See [docs/python_mutators.md](../docs/custom_mutators.md) for more information
|
||||||
|
|
||||||
|
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||||
|
you use pyton2.7 to compile python2 scripts!
|
||||||
|
|
||||||
|
example.c - this is a simple example written in C and should be compiled to a
|
||||||
|
shared library
|
||||||
|
|
||||||
|
example.py - this is the template you can use, the functions are there but they
|
||||||
|
are empty
|
||||||
|
|
||||||
|
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
||||||
|
|
||||||
|
common.py - this can be used for common functions and helpers.
|
||||||
|
the examples do not use this though. But you can :)
|
||||||
|
|
||||||
|
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
||||||
|
|
||||||
|
XmlMutatorMin.py - module for XML mutation
|
||||||
|
@ -7,6 +7,7 @@ from copy import deepcopy
|
|||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
import random, re, io
|
import random, re, io
|
||||||
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# The XmlMutatorMin class #
|
# The XmlMutatorMin class #
|
||||||
###########################
|
###########################
|
||||||
@ -149,7 +150,7 @@ class XmlMutatorMin:
|
|||||||
|
|
||||||
# We have the attribute to modify
|
# We have the attribute to modify
|
||||||
# Get its value
|
# Get its value
|
||||||
attrib_value = rand_elem.get(rand_attrib);
|
attrib_value = rand_elem.get(rand_attrib)
|
||||||
# print("- Value: " + attrib_value)
|
# print("- Value: " + attrib_value)
|
||||||
|
|
||||||
# Should we work on the whole value?
|
# Should we work on the whole value?
|
@ -19,16 +19,19 @@ import random
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def randel(l):
|
def randel(l):
|
||||||
if not l:
|
if not l:
|
||||||
return None
|
return None
|
||||||
return l[random.randint(0, len(l)-1)]
|
return l[random.randint(0, len(l)-1)]
|
||||||
|
|
||||||
|
|
||||||
def randel_pop(l):
|
def randel_pop(l):
|
||||||
if not l:
|
if not l:
|
||||||
return None
|
return None
|
||||||
return l.pop(random.randint(0, len(l)-1))
|
return l.pop(random.randint(0, len(l)-1))
|
||||||
|
|
||||||
|
|
||||||
def write_exc_example(data, exc):
|
def write_exc_example(data, exc):
|
||||||
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
|
exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
|
||||||
|
|
177
examples/custom_mutators/example.c
Normal file
177
examples/custom_mutators/example.c
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
New Custom Mutator for AFL++
|
||||||
|
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
||||||
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||||
|
Shengtuo Hu <h1994st@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char *commands[] = {
|
||||||
|
|
||||||
|
"GET",
|
||||||
|
"PUT",
|
||||||
|
"DEL",
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t data_size = 100;
|
||||||
|
|
||||||
|
void afl_custom_init(unsigned int seed) {
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform custom mutations on a given input
|
||||||
|
*
|
||||||
|
* (Optional for now. Required in the future)
|
||||||
|
*
|
||||||
|
* @param[in] buf Input data to be mutated
|
||||||
|
* @param[in] buf_size Size of input data
|
||||||
|
* @param[in] add_buf Buffer containing the additional test case
|
||||||
|
* @param[in] add_buf_size Size of the additional test case
|
||||||
|
* @param[out] mutated_out Buffer to store the mutated input
|
||||||
|
* @param[in] max_size Maximum size of the mutated output. The mutation must not
|
||||||
|
* produce data larger than max_size.
|
||||||
|
* @return Size of the mutated output.
|
||||||
|
*/
|
||||||
|
size_t afl_custom_fuzz(uint8_t *buf, size_t buf_size,
|
||||||
|
uint8_t *add_buf,size_t add_buf_size, // add_buf can be NULL
|
||||||
|
uint8_t *mutated_out, size_t max_size) {
|
||||||
|
|
||||||
|
// Make sure that the packet size does not exceed the maximum size expected by
|
||||||
|
// the fuzzer
|
||||||
|
size_t mutated_size = data_size <= max_size ? data_size : max_size;
|
||||||
|
|
||||||
|
// Randomly select a command string to add as a header to the packet
|
||||||
|
memcpy(mutated_out, commands[rand() % 3], 3);
|
||||||
|
|
||||||
|
// Mutate the payload of the packet
|
||||||
|
for (int i = 3; i < mutated_size; i++) {
|
||||||
|
|
||||||
|
mutated_out[i] = (data[i] + rand() % 10) & 0xff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutated_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A post-processing function to use right before AFL writes the test case to
|
||||||
|
* disk in order to execute the target.
|
||||||
|
*
|
||||||
|
* (Optional) If this functionality is not needed, simply don't define this
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* @param[in] buf Buffer containing the test case to be executed
|
||||||
|
* @param[in] buf_size Size of the test case
|
||||||
|
* @param[out] out_buf Pointer to the buffer containing the test case after
|
||||||
|
* processing. External library should allocate memory for out_buf. AFL++
|
||||||
|
* will release the memory after saving the test case.
|
||||||
|
* @return Size of the output buffer after processing
|
||||||
|
*/
|
||||||
|
size_t afl_custom_pre_save(uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
|
||||||
|
|
||||||
|
size_t out_buf_size;
|
||||||
|
|
||||||
|
out_buf_size = buf_size;
|
||||||
|
|
||||||
|
// External mutator should allocate memory for `out_buf`
|
||||||
|
*out_buf = malloc(out_buf_size);
|
||||||
|
memcpy(*out_buf, buf, out_buf_size);
|
||||||
|
|
||||||
|
return out_buf_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *trim_buf;
|
||||||
|
size_t trim_buf_size
|
||||||
|
int trimmming_steps;
|
||||||
|
int cur_step;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called at the start of each trimming operation and receives
|
||||||
|
* the initial buffer. It should return the amount of iteration steps possible
|
||||||
|
* on this input (e.g. if your input has n elements and you want to remove
|
||||||
|
* them one by one, return n, if you do a binary search, return log(n),
|
||||||
|
* and so on...).
|
||||||
|
*
|
||||||
|
* If your trimming algorithm doesn't allow you to determine the amount of
|
||||||
|
* (remaining) steps easily (esp. while running), then you can alternatively
|
||||||
|
* return 1 here and always return 0 in post_trim until you are finished and
|
||||||
|
* no steps remain. In that case, returning 1 in post_trim will end the
|
||||||
|
* trimming routine. The whole current index/max iterations stuff is only used
|
||||||
|
* to show progress.
|
||||||
|
*
|
||||||
|
* (Optional)
|
||||||
|
*
|
||||||
|
* @param buf Buffer containing the test case
|
||||||
|
* @param buf_size Size of the test case
|
||||||
|
* @return The amount of possible iteration steps to trim the input
|
||||||
|
*/
|
||||||
|
int afl_custom_init_trim(uint8_t *buf, size_t buf_size) {
|
||||||
|
|
||||||
|
// We simply trim once
|
||||||
|
trimmming_steps = 1;
|
||||||
|
|
||||||
|
cur_step = 0;
|
||||||
|
trim_buf = buf;
|
||||||
|
trim_buf_size = buf_size;
|
||||||
|
|
||||||
|
return trimmming_steps;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called for each trimming operation. It doesn't have any
|
||||||
|
* arguments because we already have the initial buffer from init_trim and we
|
||||||
|
* can memorize the current state in global variables. This can also save
|
||||||
|
* reparsing steps for each iteration. It should return the trimmed input
|
||||||
|
* buffer, where the returned data must not exceed the initial input data in
|
||||||
|
* length. Returning anything that is larger than the original data (passed
|
||||||
|
* to init_trim) will result in a fatal abort of AFLFuzz.
|
||||||
|
*
|
||||||
|
* (Optional)
|
||||||
|
*
|
||||||
|
* @param[out] out_buf Pointer to the buffer containing the trimmed test case.
|
||||||
|
* External library should allocate memory for out_buf. AFL++ will release
|
||||||
|
* the memory after saving the test case.
|
||||||
|
* @param[out] out_buf_size Pointer to the size of the trimmed test case
|
||||||
|
*/
|
||||||
|
void afl_custom_trim(uint8_t **out_buf, size_t* out_buf_size) {
|
||||||
|
|
||||||
|
*out_buf_size = trim_buf_size - 1;
|
||||||
|
|
||||||
|
// External mutator should allocate memory for `out_buf`
|
||||||
|
*out_buf = malloc(*out_buf_size);
|
||||||
|
// Remove the last byte of the trimming input
|
||||||
|
memcpy(*out_buf, trim_buf, *out_buf_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after each trim operation to inform you if your
|
||||||
|
* trimming step was successful or not (in terms of coverage). If you receive
|
||||||
|
* a failure here, you should reset your input to the last known good state.
|
||||||
|
*
|
||||||
|
* (Optional)
|
||||||
|
*
|
||||||
|
* @param success Indicates if the last trim operation was successful.
|
||||||
|
* @return The next trim iteration index (from 0 to the maximum amount of
|
||||||
|
* steps returned in init_trim)
|
||||||
|
*/
|
||||||
|
int afl_custom_post_trim(int success) {
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
++cur_step;
|
||||||
|
return cur_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmming_steps;
|
||||||
|
|
||||||
|
}
|
@ -16,6 +16,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
def init(seed):
|
def init(seed):
|
||||||
'''
|
'''
|
||||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||||
@ -24,9 +25,9 @@ def init(seed):
|
|||||||
@param seed: A 32-bit random value
|
@param seed: A 32-bit random value
|
||||||
'''
|
'''
|
||||||
random.seed(seed)
|
random.seed(seed)
|
||||||
return 0
|
|
||||||
|
|
||||||
def fuzz(buf, add_buf):
|
|
||||||
|
def fuzz(buf, add_buf, max_size):
|
||||||
'''
|
'''
|
||||||
Called per fuzzing iteration.
|
Called per fuzzing iteration.
|
||||||
|
|
||||||
@ -36,6 +37,10 @@ def fuzz(buf, add_buf):
|
|||||||
@type add_buf: bytearray
|
@type add_buf: bytearray
|
||||||
@param add_buf: A second buffer that can be used as mutation source.
|
@param add_buf: A second buffer that can be used as mutation source.
|
||||||
|
|
||||||
|
@type max_size: int
|
||||||
|
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||||
|
produce data larger than max_size.
|
||||||
|
|
||||||
@rtype: bytearray
|
@rtype: bytearray
|
||||||
@return: A new bytearray containing the mutated data
|
@return: A new bytearray containing the mutated data
|
||||||
'''
|
'''
|
||||||
@ -101,3 +106,17 @@ def fuzz(buf, add_buf):
|
|||||||
# # removed in the last step
|
# # removed in the last step
|
||||||
#
|
#
|
||||||
# return next_index
|
# return next_index
|
||||||
|
#
|
||||||
|
# def pre_save(buf):
|
||||||
|
# '''
|
||||||
|
# Called just before the execution to write the test case in the format
|
||||||
|
# expected by the target
|
||||||
|
#
|
||||||
|
# @type buf: bytearray
|
||||||
|
# @param buf: The buffer containing the test case to be executed
|
||||||
|
#
|
||||||
|
# @rtype: bytearray
|
||||||
|
# @return: The buffer containing the test case after
|
||||||
|
# '''
|
||||||
|
# return buf
|
||||||
|
#
|
@ -16,6 +16,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
def init(seed):
|
def init(seed):
|
||||||
'''
|
'''
|
||||||
Called once when AFLFuzz starts up. Used to seed our RNG.
|
Called once when AFLFuzz starts up. Used to seed our RNG.
|
||||||
@ -25,9 +26,9 @@ def init(seed):
|
|||||||
'''
|
'''
|
||||||
# Seed our RNG
|
# Seed our RNG
|
||||||
random.seed(seed)
|
random.seed(seed)
|
||||||
return 0
|
|
||||||
|
|
||||||
def fuzz(buf, add_buf):
|
|
||||||
|
def fuzz(buf, add_buf, max_size):
|
||||||
'''
|
'''
|
||||||
Called per fuzzing iteration.
|
Called per fuzzing iteration.
|
||||||
|
|
||||||
@ -37,6 +38,10 @@ def fuzz(buf, add_buf):
|
|||||||
@type add_buf: bytearray
|
@type add_buf: bytearray
|
||||||
@param add_buf: A second buffer that can be used as mutation source.
|
@param add_buf: A second buffer that can be used as mutation source.
|
||||||
|
|
||||||
|
@type max_size: int
|
||||||
|
@param max_size: Maximum size of the mutated output. The mutation must not
|
||||||
|
produce data larger than max_size.
|
||||||
|
|
||||||
@rtype: bytearray
|
@rtype: bytearray
|
||||||
@return: A new bytearray containing the mutated data
|
@return: A new bytearray containing the mutated data
|
||||||
'''
|
'''
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
Simple Custom Mutator for AFL
|
|
||||||
|
|
||||||
Written by Khaled Yakdan <yakdan@code-intelligence.de>
|
|
||||||
|
|
||||||
This a simple mutator that assumes that the generates messages starting with
|
|
||||||
one of the three strings GET, PUT, or DEL followed by a payload. The mutator
|
|
||||||
randomly selects a commend and mutates the payload of the seed provided as
|
|
||||||
input.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static const char *commands[] = {
|
|
||||||
|
|
||||||
"GET",
|
|
||||||
"PUT",
|
|
||||||
"DEL",
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t data_size = 100;
|
|
||||||
|
|
||||||
size_t afl_custom_mutator(uint8_t *data, size_t size, uint8_t *mutated_out,
|
|
||||||
size_t max_size, unsigned int seed) {
|
|
||||||
|
|
||||||
// Seed the PRNG
|
|
||||||
srand(seed);
|
|
||||||
|
|
||||||
// Make sure that the packet size does not exceed the maximum size expected by
|
|
||||||
// the fuzzer
|
|
||||||
size_t mutated_size = data_size <= max_size ? data_size : max_size;
|
|
||||||
|
|
||||||
// Randomly select a command string to add as a header to the packet
|
|
||||||
memcpy(mutated_out, commands[rand() % 3], 3);
|
|
||||||
|
|
||||||
// Mutate the payload of the packet
|
|
||||||
for (int i = 3; i < mutated_size; i++) {
|
|
||||||
|
|
||||||
mutated_out[i] = (data[i] + rand() % 10) & 0xff;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutated_size;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -9,8 +9,8 @@ __seed__ = "RANDOM"
|
|||||||
__log__ = False
|
__log__ = False
|
||||||
__log_file__ = "wrapper.log"
|
__log_file__ = "wrapper.log"
|
||||||
|
|
||||||
# AFL functions
|
|
||||||
|
|
||||||
|
# AFL functions
|
||||||
def log(text):
|
def log(text):
|
||||||
"""
|
"""
|
||||||
Logger
|
Logger
|
||||||
@ -24,6 +24,7 @@ def log(text):
|
|||||||
with open(__log_file__, "a") as logf:
|
with open(__log_file__, "a") as logf:
|
||||||
logf.write("[%s] %s\n" % (__seed__, text))
|
logf.write("[%s] %s\n" % (__seed__, text))
|
||||||
|
|
||||||
|
|
||||||
def init(seed):
|
def init(seed):
|
||||||
"""
|
"""
|
||||||
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
Called once when AFL starts up. Seed is used to identify the AFL instance in log files
|
||||||
@ -42,7 +43,8 @@ def init(seed):
|
|||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
log("init(): Can't create mutator: %s" % e.message)
|
log("init(): Can't create mutator: %s" % e.message)
|
||||||
|
|
||||||
def fuzz(buf, add_buf):
|
|
||||||
|
def fuzz(buf, add_buf, max_size):
|
||||||
"""
|
"""
|
||||||
Called for each fuzzing iteration.
|
Called for each fuzzing iteration.
|
||||||
"""
|
"""
|
||||||
@ -62,7 +64,7 @@ def fuzz(buf, add_buf):
|
|||||||
try:
|
try:
|
||||||
buf_str = str(buf)
|
buf_str = str(buf)
|
||||||
log("fuzz(): AFL buffer converted to a string")
|
log("fuzz(): AFL buffer converted to a string")
|
||||||
except:
|
except Exception:
|
||||||
via_buffer = False
|
via_buffer = False
|
||||||
log("fuzz(): Can't convert AFL buffer to a string")
|
log("fuzz(): Can't convert AFL buffer to a string")
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ def fuzz(buf, add_buf):
|
|||||||
try:
|
try:
|
||||||
__mutator__.init_from_string(buf_str)
|
__mutator__.init_from_string(buf_str)
|
||||||
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
|
||||||
except:
|
except Exception:
|
||||||
via_buffer = False
|
via_buffer = False
|
||||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||||
|
|
||||||
@ -84,7 +86,7 @@ def fuzz(buf, add_buf):
|
|||||||
try:
|
try:
|
||||||
__mutator__.mutate(max=5)
|
__mutator__.mutate(max=5)
|
||||||
log("fuzz(): Input mutated")
|
log("fuzz(): Input mutated")
|
||||||
except:
|
except Exception:
|
||||||
log("fuzz(): Can't mutate input => returning buf")
|
log("fuzz(): Can't mutate input => returning buf")
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ def fuzz(buf, add_buf):
|
|||||||
try:
|
try:
|
||||||
data = bytearray(__mutator__.save_to_string())
|
data = bytearray(__mutator__.save_to_string())
|
||||||
log("fuzz(): Mutated data converted as bytes")
|
log("fuzz(): Mutated data converted as bytes")
|
||||||
except:
|
except Exception:
|
||||||
log("fuzz(): Can't convert mutated data to bytes => returning buf")
|
log("fuzz(): Can't convert mutated data to bytes => returning buf")
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
@ -100,8 +102,8 @@ def fuzz(buf, add_buf):
|
|||||||
log("fuzz(): Returning %d bytes" % len(data))
|
log("fuzz(): Returning %d bytes" % len(data))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# Main (for debug)
|
|
||||||
|
|
||||||
|
# Main (for debug)
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
__log__ = True
|
__log__ = True
|
||||||
@ -114,4 +116,3 @@ if __name__ == '__main__':
|
|||||||
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
|
||||||
out = fuzz(in_1, in_2)
|
out = fuzz(in_1, in_2)
|
||||||
print(out)
|
print(out)
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
These are example and helper files for the AFL_PYTHON_MODULE feature.
|
|
||||||
See [docs/python_mutators.md](../docs/python_mutators.md) for more information
|
|
||||||
|
|
||||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
|
||||||
you use pyton2.7 to compile python2 scripts!
|
|
||||||
|
|
||||||
|
|
||||||
example.py - this is the template you can use, the functions are there
|
|
||||||
but they are empty
|
|
||||||
|
|
||||||
simple-chunk-replace.py - this is a simple example where chunks are replaced
|
|
||||||
|
|
||||||
common.py - this can be used for common functions and helpers.
|
|
||||||
the examples do not use this though. But you can :)
|
|
||||||
|
|
||||||
wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
|
|
||||||
|
|
||||||
XmlMutatorMin.py - module for XML mutation
|
|
Reference in New Issue
Block a user