I discovered go-fuzz on github: https://github.com/dvyukov/go-fuzz and it otherwise seems fine, but it doesn’t support custom mutators for some reason…
I decided to add support for python custom mutators because I have written a specific custom mutator which I would like to use in the future.
I discovered this quick thing: https://github.com/tliron/py4go which seems to be a way to call python from go.
Let’s smash these two together and see what happens…
The go-fuzz-build/main.go file seems to be a nice place to put the custom mutator and stuff like that… except the thing is that I do not even know how to build the thing, so let’s figure out that first…
Ok, so because I don’t even know how to compile the darn thing from a local source, I decided to file this issue and ask for help: https://github.com/dvyukov/go-fuzz/issues/355
Instead of using my python custom mutator, let’s create a custom mutator in golang in a similar fashion.
Because the mutator has to be based on the input itself (remember we can’t use the custom mutator api) it needs to be based on the input data itself.
I think the way to do this is to have a kind of compression type thing going on where the first let’s say two bytes indicate the repeat count and then the next two bytes indicate the repeat length, and then there is “repeat length” number of characters after that get repeated “repeat count” times. I think that is a decent plan eh?
I think the best strategy is to use some kind of bitreader class type thing?????
Something like this??
func parse(data []byte) []byte { // Parse the bullshit
// Parse the byte array thing.
var out []byte // Output byte array.
repeat_count := 0 // How much to repeat
repeat_length := 0 // How many characters to repeat
for cur_idx := 0; cur_idx < len(data); cur_idx++ { // Our current index into the bytearray.
repeat_count = 0
repeat_length = 0
if len(data) - cur_idx <= 4 { // Break if the length of the data isn't useful anymore.
break
}
// First read the repeat_count
repeat_count |= int(data[cur_idx])
cur_idx++ // Increment
repeat_count |= int((data[cur_idx])) << 8 // Shift to the left to get the higher byte.
cur_idx++
// Then read the repeat_length.
repeat_length |= int(data[cur_idx])
cur_idx++ // Increment
repeat_length |= int((data[cur_idx])) << 8
cur_idx++
// Increment the index and then if it skips over the buffer, then break.
if cur_idx + repeat_length >= len(data) {
// Final append.
// What to append is basically bytes.Repeat(data[cur_idx:], repeat_count)
out = append(out, bytes.Repeat(data[cur_idx:], repeat_count)...) // Add to the output.
break
} else {
out = append(out, bytes.Repeat(data[cur_idx:cur_idx+repeat_length], repeat_count)...)
}
cur_idx += repeat_length
}
return out
}
that seems quite succifient at a first glance…
Let’s see what happens…
I think a good idea is to add an absolute maximum to our input and also add a hard cap to the repeat stuff such that we do not spit out obscenely large outputs…
Something like this???
func parse(data []byte) []byte { // Parse the bullshit
// Parse the byte array thing.
var out []byte // Output byte array.
repeat_count := 0 // How much to repeat
repeat_length := 0 // How many characters to repeat
// Hardcoded constants.
max_repeat_count := 10000
max_repeat_length := 100
max_output_size := 100000 // Hardcap at 100k
for cur_idx := 0; cur_idx < len(data); cur_idx++ { // Our current index into the bytearray.
repeat_count = 0
repeat_length = 0
if len(data) - cur_idx <= 4 { // Break if the length of the data isn't useful anymore.
break
}
// First read the repeat_count
repeat_count |= int(data[cur_idx])
cur_idx++ // Increment
repeat_count |= int((data[cur_idx])) << 8 // Shift to the left to get the higher byte.
cur_idx++
repeat_count = repeat_count % max_repeat_count
// Then read the repeat_length.
repeat_length |= int(data[cur_idx])
cur_idx++ // Increment
repeat_length |= int((data[cur_idx])) << 8
cur_idx++
repeat_length = repeat_length % max_repeat_length
// Increment the index and then if it skips over the buffer, then break.
if cur_idx + repeat_length >= len(data) {
// Final append.
// What to append is basically bytes.Repeat(data[cur_idx:], repeat_count)
out = append(out, bytes.Repeat(data[cur_idx:], repeat_count)...) // Add to the output.
break
} else {
out = append(out, bytes.Repeat(data[cur_idx:cur_idx+repeat_length], repeat_count)...)
}
cur_idx += repeat_length
}
// Final output check...
if len(out) > max_output_size {
out = out[:max_output_size] // Slice
}
return out
}