use crate::loader::Loader;
use crate::utils::*;
pub const MAGIC_VALUES: &[&[u8]] = &[
&[0x00],
&[0x01],
&[0x7f],
&[0x80],
&[0xff],
&[0x00, 0x00],
&[0x00, 0x01],
&[0x00, 0x7f],
&[0x00, 0x80],
&[0xff, 0xff],
&[0x00, 0x00, 0x00, 0x00],
&[0x00, 0x00, 0x00, 0x01],
&[0x00, 0x00, 0x00, 0x7f],
&[0x00, 0x00, 0x00, 0x80],
&[0xff, 0xff, 0xff, 0xff],
&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f],
&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80],
&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
];
pub struct Mutator {
pub rand: Random,
}
impl Mutator {
pub fn new(rand: Random) -> Self {
Self { rand }
}
#[inline]
pub fn mutate<L: Loader>(
&mut self,
loader: &L,
data: &mut Vec<u8>,
max_size: usize,
max_mutations: usize,
) -> u64 {
let prng_state = self.rand.get_state();
loader.mutate(self, data, max_size, max_mutations);
prng_state
}
#[inline]
pub fn bitflip(&mut self, data: &mut Vec<u8>, _: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let idx = (rand >> 7) % data.len();
let size = (rand >> 3) & 0xf;
let bit_idx = rand & 0x7;
match size {
0x0..0x8 => data[idx] ^= 0b0001 << bit_idx,
0x8..0xd => data[idx] ^= 0b0011 << bit_idx,
0xd..0xf => data[idx] ^= 0b0111 << bit_idx,
0xf => data[idx] ^= 0b1111 << bit_idx,
_ => unreachable!(),
}
}
#[inline]
pub fn byte_op(&mut self, data: &mut Vec<u8>, _: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let val = rand as u32;
let op = (rand >> 32) & 0x3;
let mut size_bits = (rand >> 34) & 0xf;
let mut size = 1 << size_bits;
if data.len() < size {
size_bits = log2_floor(data.len());
size = 1 << size_bits;
}
let idx = (rand >> 36) % (data.len() - size + 1);
match size_bits {
0x0..0x8 => {
let val = val as u8;
match op {
0b00 => data[idx] = data[idx].wrapping_add(val),
0b01 => data[idx] = data[idx].wrapping_sub(val),
0b10 => data[idx] ^= val,
0b11 => data[idx] = !data[idx],
_ => unreachable!(),
};
}
0x8..0xd => {
let val = val as u16;
let in_value = u16::from_le_bytes(data[idx..idx + 2].try_into().unwrap());
let out_value = match op {
0b00 => in_value.wrapping_add(val),
0b01 => in_value.wrapping_sub(val),
0b10 => in_value ^ val,
0b11 => !in_value,
_ => unreachable!(),
};
data[idx..idx + 2].copy_from_slice(&out_value.to_le_bytes());
}
0xd..0xf => {
let val = val as u32;
let in_value = u32::from_le_bytes(data[idx..idx + 4].try_into().unwrap());
let out_value = match op {
0b00 => in_value.wrapping_add(val),
0b01 => in_value.wrapping_sub(val),
0b10 => in_value ^ val,
0b11 => !in_value,
_ => unreachable!(),
};
data[idx..idx + 4].copy_from_slice(&out_value.to_le_bytes());
}
0xf => {
let val = self.rand.u64();
let in_value = u64::from_le_bytes(data[idx..idx + 8].try_into().unwrap());
let out_value = match op {
0b00 => in_value.wrapping_add(val),
0b01 => in_value.wrapping_sub(val),
0b10 => in_value ^ val,
0b11 => !in_value,
_ => unreachable!(),
};
data[idx..idx + 8].copy_from_slice(&out_value.to_le_bytes());
}
_ => unreachable!(),
};
}
#[inline]
pub fn extend(&mut self, data: &mut Vec<u8>, max_size: usize) {
let rand = self.rand.u64() as usize;
let idx = if data.is_empty() {
0
} else {
let idx_type = rand & 1;
match idx_type {
0 => data.len(),
1 => (rand >> 34) % data.len(),
_ => unreachable!(),
}
};
let remaining_size = max_size
.checked_sub(data.len())
.unwrap_or_else(|| panic!("max_size={:#x}, data_len={:#x}", max_size, data.len()));
if remaining_size == 0 {
return;
}
let extend_size = (rand >> 5) & 0x1fffffff;
let extend_type = (rand >> 1) & 0xf;
let extend_size = match extend_type {
x if (0x0..0x8).contains(&x) && remaining_size >= 4 => 4,
x if (0x8..0xd).contains(&x) && remaining_size >= 8 => 8,
x if (0xd..0xf).contains(&x) && remaining_size >= 16 => 16,
_ => extend_size % (remaining_size + 1),
};
let extend_iter = std::iter::repeat(0u8).take(extend_size);
data.splice(idx..idx, extend_iter);
assert!(data.len() <= max_size);
}
#[inline]
pub fn shrink(&mut self, data: &mut Vec<u8>, _max_size: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let shrink_size = (rand >> 5) & 0x1fffffff;
let shrink_type = (rand >> 1) & 0xf;
let shrink_size = match shrink_type {
x if (0x0..0x8).contains(&x) && data.len() > 4 => 4,
x if (0x8..0xd).contains(&x) && data.len() > 8 => 8,
x if (0xd..0xf).contains(&x) && data.len() > 16 => 16,
_ => shrink_size % data.len(),
};
let idx_type = rand & 1;
let idx = match idx_type {
0 => data.len() - shrink_size,
1 => (rand >> 34) % (data.len() - shrink_size),
_ => unreachable!(),
};
data.drain(idx..idx + shrink_size);
}
#[inline]
pub fn magic_replace(&mut self, data: &mut Vec<u8>, _max_size: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let i_idx = (rand >> 8) % data.len();
let magic_idx = (rand & 0xff) % MAGIC_VALUES.len();
let magic = MAGIC_VALUES[magic_idx];
let max_size = std::cmp::min(magic.len(), data.len() - i_idx);
data[i_idx..i_idx + max_size].copy_from_slice(&magic[..max_size]);
}
#[inline]
pub fn magic_insert(&mut self, data: &mut Vec<u8>, max_size: usize) {
let rand = self.rand.u64() as usize;
let i_idx = if !data.is_empty() {
(rand >> 8) % data.len()
} else {
0
};
let magic_idx = (rand & 0xff) % MAGIC_VALUES.len();
let magic = MAGIC_VALUES[magic_idx];
let remaining_size = max_size
.checked_sub(data.len())
.unwrap_or_else(|| panic!("max_size={:#x}, data_len={:#x}", max_size, data.len()));
if remaining_size == 0 {
return;
}
let i_size = std::cmp::min(magic.len(), remaining_size);
data.splice(i_idx..i_idx, magic[..i_size].iter().copied());
assert!(data.len() <= max_size);
}
#[inline]
pub fn random_replace(&mut self, data: &mut Vec<u8>, _max_size: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let r_idx = (rand >> 34) % data.len();
let r_size = (rand >> 4) & 0x3fff_ffff;
let r_type = rand & 0xf;
let r_size = match r_type {
0x0..0x8 => 1,
0x8..0xc => 2,
0xc..0xe => 4,
0xe => 8,
0xf => r_size % data.len(),
_ => unreachable!(),
};
let max_size = std::cmp::min(r_size, data.len() - r_idx);
self.rand.bytes_into_slice(data, r_idx, max_size);
}
#[inline]
pub fn random_insert(&mut self, data: &mut Vec<u8>, max_size: usize) {
let rand = self.rand.u64() as usize;
let i_idx = if !data.is_empty() {
(rand >> 34) % data.len()
} else {
0
};
let i_size = (rand >> 4) & 0x3fff_ffff;
let i_type = rand & 0xf;
let remaining_size = max_size
.checked_sub(data.len())
.unwrap_or_else(|| panic!("max_size={:#x}, data_len={:#x}", max_size, data.len()));
if remaining_size == 0 {
return;
}
let i_size = match i_type {
0x0..0x8 => 1,
0x8..0xc => 2,
0xc..0xe => 4,
0xe => 8,
0xf => i_size % remaining_size,
_ => unreachable!(),
};
let i_size = std::cmp::min(i_size, remaining_size);
data.splice(i_idx..i_idx, self.rand.bytes(i_size));
assert!(data.len() <= max_size);
}
#[inline]
pub fn repetition_replace(&mut self, data: &mut Vec<u8>, _max_size: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let r_idx = (rand >> 38) % data.len();
let r_size = (rand >> 12) & 0x3ff_ffff;
let r_byte = (rand >> 4) as u8;
let r_type = rand & 0xf;
let r_size = match r_type {
0x0..0x8 => 1,
0x8..0xc => 2,
0xc..0xe => 4,
0xe => 8,
0xf => r_size % data.len(),
_ => unreachable!(),
};
let max_size = std::cmp::min(r_size, data.len() - r_idx);
data[r_idx..r_idx + max_size].copy_from_slice(&vec![r_byte; max_size]);
}
#[inline]
pub fn repetition_insert(&mut self, data: &mut Vec<u8>, max_size: usize) {
if data.is_empty() {
return;
}
let rand = self.rand.u64() as usize;
let i_idx = if !data.is_empty() {
(rand >> 38) % data.len()
} else {
0
};
let i_size = (rand >> 12) & 0x3ff_ffff;
let i_byte = (rand >> 4) as u8;
let i_type = rand & 0xf;
let remaining_size = max_size
.checked_sub(data.len())
.unwrap_or_else(|| panic!("max_size={:#x}, data_len={:#x}", max_size, data.len()));
if remaining_size == 0 {
return;
}
let i_size = match i_type {
0x0..0x8 => 1,
0x8..0xc => 2,
0xc..0xe => 4,
0xe => 8,
0xf => i_size % remaining_size,
_ => unreachable!(),
};
let i_size = std::cmp::min(i_size, remaining_size);
data.splice(i_idx..i_idx, std::iter::repeat(i_byte).take(i_size));
assert!(data.len() <= max_size);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mutator_bitflip() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42];
mutator.bitflip(&mut data, 0x100);
println!("bitflip = {:?}", data);
mutator.bitflip(&mut data, 0x100);
println!("bitflip = {:?}", data);
mutator.bitflip(&mut data, 0x100);
println!("bitflip = {:?}", data);
mutator.bitflip(&mut data, 0x100);
println!("bitflip = {:?}", data);
mutator.bitflip(&mut data, 0x100);
println!("bitflip = {:?}", data);
}
#[test]
fn mutator_byte_operations() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.byte_op(&mut data, 0x100);
println!("byte_op = {:?}", data);
mutator.byte_op(&mut data, 0x100);
println!("byte_op = {:?}", data);
mutator.byte_op(&mut data, 0x100);
println!("byte_op = {:?}", data);
mutator.byte_op(&mut data, 0x100);
println!("byte_op = {:?}", data);
mutator.byte_op(&mut data, 0x100);
println!("byte_op = {:?}", data);
}
#[test]
fn mutator_extend_shrink() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.extend(&mut data, 0x100);
println!("extend = {:?}", data);
mutator.shrink(&mut data, 0x100);
println!("shrink = {:?}", data);
mutator.extend(&mut data, 0x100);
println!("extend = {:?}", data);
mutator.shrink(&mut data, 0x100);
println!("shrink = {:?}", data);
mutator.extend(&mut data, 0x100);
println!("extend = {:?}", data);
mutator.shrink(&mut data, 0x100);
println!("shrink = {:?}", data);
mutator.extend(&mut data, 0x100);
println!("extend = {:?}", data);
mutator.shrink(&mut data, 0x100);
println!("shrink = {:?}", data);
mutator.extend(&mut data, 0x100);
println!("extend = {:?}", data);
mutator.shrink(&mut data, 0x100);
println!("shrink = {:?}", data);
}
#[test]
fn mutator_magic_replace() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.magic_replace(&mut data, 0x100);
println!("magic_replace = {:?}", data);
mutator.magic_replace(&mut data, 0x100);
println!("magic_replace = {:?}", data);
mutator.magic_replace(&mut data, 0x100);
println!("magic_replace = {:?}", data);
mutator.magic_replace(&mut data, 0x100);
println!("magic_replace = {:?}", data);
mutator.magic_replace(&mut data, 0x100);
println!("magic_replace = {:?}", data);
}
#[test]
fn mutator_magic_insert() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.magic_insert(&mut data, 0x100);
println!("magic_insert = {:?}", data);
mutator.magic_insert(&mut data, 0x100);
println!("magic_insert = {:?}", data);
mutator.magic_insert(&mut data, 0x100);
println!("magic_insert = {:?}", data);
mutator.magic_insert(&mut data, 0x100);
println!("magic_insert = {:?}", data);
mutator.magic_insert(&mut data, 0x100);
println!("magic_insert = {:?}", data);
}
#[test]
fn mutator_random_replace() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.random_replace(&mut data, 0x100);
println!("random_replace = {:?}", data);
mutator.random_replace(&mut data, 0x100);
println!("random_replace = {:?}", data);
mutator.random_replace(&mut data, 0x100);
println!("random_replace = {:?}", data);
mutator.random_replace(&mut data, 0x100);
println!("random_replace = {:?}", data);
mutator.random_replace(&mut data, 0x100);
println!("random_replace = {:?}", data);
}
#[test]
fn mutator_random_insert() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.random_insert(&mut data, 0x100);
println!("random_insert = {:?}", data);
mutator.random_insert(&mut data, 0x100);
println!("random_insert = {:?}", data);
mutator.random_insert(&mut data, 0x100);
println!("random_insert = {:?}", data);
mutator.random_insert(&mut data, 0x100);
println!("random_insert = {:?}", data);
mutator.random_insert(&mut data, 0x100);
println!("random_insert = {:?}", data);
}
#[test]
fn mutator_repetition_replace() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.repetition_replace(&mut data, 0x100);
println!("repetition_replace = {:?}", data);
mutator.repetition_replace(&mut data, 0x100);
println!("repetition_replace = {:?}", data);
mutator.repetition_replace(&mut data, 0x100);
println!("repetition_replace = {:?}", data);
mutator.repetition_replace(&mut data, 0x100);
println!("repetition_replace = {:?}", data);
mutator.repetition_replace(&mut data, 0x100);
println!("repetition_replace = {:?}", data);
}
#[test]
fn mutator_repetition_insert() {
let rand = Random::new(0xa5a5a5a5a5a5a5);
let mut mutator = Mutator::new(rand);
let mut data = vec![0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42];
mutator.repetition_insert(&mut data, 0x100);
println!("repetition_insert = {:?}", data);
mutator.repetition_insert(&mut data, 0x100);
println!("repetition_insert = {:?}", data);
mutator.repetition_insert(&mut data, 0x100);
println!("repetition_insert = {:?}", data);
mutator.repetition_insert(&mut data, 0x100);
println!("repetition_insert = {:?}", data);
mutator.repetition_insert(&mut data, 0x100);
println!("repetition_insert = {:?}", data);
}
}