354 lines
7.3 KiB
Go
354 lines
7.3 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
type Generator struct {
|
|
data []byte
|
|
dataSize uint32
|
|
position uint32
|
|
mapStruct map[string]interface{}
|
|
arrayStruct []interface{}
|
|
fieldInfo map[string]interface{}
|
|
}
|
|
|
|
func NewGenerator(fuzzData []byte) *Generator {
|
|
return &Generator{
|
|
data: fuzzData,
|
|
dataSize: uint32(len(fuzzData)),
|
|
fieldInfo: make(map[string]interface{}),
|
|
}
|
|
}
|
|
|
|
func (g *Generator) SetPreFilled(fieldInfo map[string]interface{}) {
|
|
g.fieldInfo = fieldInfo
|
|
}
|
|
|
|
func (g *Generator) fillAny(any reflect.Value) error {
|
|
|
|
if fieldInfoValue, ok := g.fieldInfo[any.Type().String()]; ok {
|
|
fieldInfoData := reflect.ValueOf(fieldInfoValue)
|
|
any.Set(fieldInfoData)
|
|
return nil
|
|
}
|
|
|
|
switch any.Kind() {
|
|
case reflect.Struct:
|
|
for i := 0; i < any.NumField(); i++ {
|
|
err := g.fillAny(any.Field(i))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
newInt, err := g.GenerateInt()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetInt(int64(newInt))
|
|
|
|
case reflect.Ptr:
|
|
any.Set(reflect.New(any.Type().Elem()))
|
|
err := g.fillAny(any.Elem())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
case reflect.String:
|
|
str, err := g.GenerateString()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetString(str)
|
|
|
|
case reflect.Float32:
|
|
newFloat, err := g.GenerateFloat32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetFloat(float64(newFloat))
|
|
|
|
case reflect.Float64:
|
|
newFloat, err := g.GenerateFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetFloat(float64(newFloat))
|
|
|
|
case reflect.Complex64:
|
|
newFloatReal, err := g.GenerateFloat32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newFloatImag, err := g.GenerateFloat32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetComplex(complex(float64(newFloatReal), float64(newFloatImag)))
|
|
|
|
case reflect.Complex128:
|
|
newFloatReal, err := g.GenerateFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newFloatImag, err := g.GenerateFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetComplex(complex(newFloatReal, newFloatImag))
|
|
|
|
case reflect.Map:
|
|
any.Set(reflect.MakeMap(any.Type()))
|
|
|
|
mapLen, err := g.GenerateUInt32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for i := uint32(0); i < mapLen; i++ {
|
|
key := fmt.Sprintf("key%d", i)
|
|
mapValue := reflect.New(any.Type().Elem())
|
|
err := g.fillAny(mapValue.Elem())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetMapIndex(reflect.ValueOf(key), mapValue.Elem())
|
|
}
|
|
|
|
case reflect.Array:
|
|
any.Set(reflect.New(any.Type()).Elem())
|
|
arrayLen := any.Len()
|
|
for i := 0; i < arrayLen; i++ {
|
|
arrayValue := reflect.New(any.Type().Elem())
|
|
err := g.fillAny(arrayValue.Elem())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.Index(i).Set(arrayValue.Elem())
|
|
}
|
|
|
|
case reflect.Bool:
|
|
newBool, err := g.GenerateBool()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetBool(newBool)
|
|
|
|
case reflect.Uint8:
|
|
newUInt8, err := g.GenerateUInt8()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetUint(uint64(newUInt8))
|
|
|
|
case reflect.Uint16:
|
|
newUInt16, err := g.GenerateUInt16()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetUint(uint64(newUInt16))
|
|
|
|
case reflect.Uint, reflect.Uint32:
|
|
newUInt32, err := g.GenerateUInt32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetUint(uint64(newUInt32))
|
|
|
|
case reflect.Uint64, reflect.Uintptr:
|
|
newUInt64, err := g.GenerateUInt64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetUint(newUInt64)
|
|
|
|
case reflect.Chan:
|
|
maxSize := uint8(50)
|
|
size, err := g.GenerateUInt8()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
size = size % maxSize
|
|
channel := reflect.MakeChan(any.Type(), int(size))
|
|
for i := 0; i < int(size); i++ {
|
|
elem := reflect.New(channel.Type().Elem()).Elem()
|
|
err = g.fillAny(elem)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
channel.Send(elem)
|
|
}
|
|
any.Set(channel)
|
|
|
|
case reflect.Slice:
|
|
maxSize := uint8(50)
|
|
size, err := g.GenerateUInt8()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
size = size % maxSize
|
|
|
|
slice := reflect.MakeSlice(any.Type(), int(size), int(size))
|
|
for i := 0; i < int(size); i++ {
|
|
err := g.fillAny(slice.Index(i))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if any.CanSet() {
|
|
any.Set(slice)
|
|
}
|
|
|
|
case reflect.UnsafePointer:
|
|
addr, err := g.GenerateUInt64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
any.SetPointer(unsafe.Pointer(uintptr(addr)))
|
|
|
|
case reflect.Interface:
|
|
|
|
default:
|
|
panic("unhandled default case")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Generator) GenerateStruct(targetStruct interface{}) error {
|
|
e := reflect.ValueOf(targetStruct).Elem()
|
|
return g.fillAny(e)
|
|
}
|
|
|
|
func (g *Generator) GenerateInt() (int, error) {
|
|
if g.position >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
result := int(g.data[g.position])
|
|
g.position++
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateUInt32() (uint32, error) {
|
|
if g.position+3 >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
result := uint32(0)
|
|
for i := 0; i < 4; i++ {
|
|
result = result<<8 | uint32(g.data[g.position])
|
|
g.position++
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateString() (string, error) {
|
|
maxStrLength := uint32(1000)
|
|
|
|
if g.position >= g.dataSize {
|
|
return "nil", errors.New("the data bytes are over")
|
|
}
|
|
|
|
length, err := g.GenerateUInt32()
|
|
if err != nil {
|
|
return "nil", errors.New("the data bytes are over")
|
|
}
|
|
length = length % maxStrLength
|
|
|
|
startBytePos := g.position
|
|
if startBytePos >= g.dataSize {
|
|
return "nil", errors.New("the data bytes are over")
|
|
}
|
|
|
|
if startBytePos+length > g.dataSize {
|
|
return "nil", errors.New("the data bytes are over")
|
|
}
|
|
|
|
if startBytePos > startBytePos+length {
|
|
return "nil", errors.New("overflow")
|
|
}
|
|
|
|
g.position = startBytePos + length
|
|
result := string(g.data[startBytePos:g.position])
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateFloat32() (float32, error) {
|
|
if g.position+3 >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
|
|
bits := uint32(0)
|
|
for i := 0; i < 4; i++ {
|
|
bits = bits<<8 | uint32(g.data[g.position])
|
|
g.position++
|
|
}
|
|
|
|
floatBits := uint32(math.Float32bits(math.Float32frombits(bits)))
|
|
result := math.Float32frombits(floatBits)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateFloat64() (float64, error) {
|
|
if g.position+7 >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
|
|
bits := uint64(0)
|
|
for i := 0; i < 8; i++ {
|
|
bits = bits<<8 | uint64(g.data[g.position])
|
|
g.position++
|
|
}
|
|
|
|
result := math.Float64frombits(bits)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateBool() (bool, error) {
|
|
if g.position >= g.dataSize {
|
|
return false, errors.New("the data bytes are over")
|
|
}
|
|
result := g.data[g.position]%2 == 0
|
|
g.position++
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateUInt8() (uint8, error) {
|
|
if g.position >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
result := g.data[g.position]
|
|
g.position++
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateUInt16() (uint16, error) {
|
|
if g.position+1 >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
result := uint16(0)
|
|
for i := 0; i < 2; i++ {
|
|
result = result<<8 | uint16(g.data[g.position])
|
|
g.position++
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generator) GenerateUInt64() (uint64, error) {
|
|
if g.position+7 >= g.dataSize {
|
|
return 0, errors.New("the data bytes are over")
|
|
}
|
|
result := uint64(0)
|
|
for i := 0; i < 8; i++ {
|
|
result = result<<8 | uint64(g.data[g.position])
|
|
g.position++
|
|
}
|
|
return result, nil
|
|
}
|