17
17
package abi
18
18
19
19
import (
20
- "bytes"
21
20
"fmt"
22
- "math/rand"
23
21
"reflect"
24
22
"strings"
25
23
26
24
"github.com/ethereum/go-ethereum/accounts/abi"
27
- "github.com/ethereum/go-ethereum/crypto"
28
25
fuzz "github.com/google/gofuzz"
29
26
)
30
27
31
- func unpackPack (abi abi.ABI , method string , inputType []interface {}, input []byte ) bool {
32
- outptr := reflect .New (reflect .TypeOf (inputType ))
33
- if err := abi .UnpackIntoInterface (outptr .Interface (), method , input ); err == nil {
34
- output , err := abi .Pack (method , input )
28
+ var (
29
+ names = []string {"_name" , "name" , "NAME" , "name_" , "__" , "_name_" , "n" }
30
+ stateMut = []string {"" , "pure" , "view" , "payable" }
31
+ stateMutabilites = []* string {& stateMut [0 ], & stateMut [1 ], & stateMut [2 ], & stateMut [3 ]}
32
+ pays = []string {"" , "true" , "false" }
33
+ payables = []* string {& pays [0 ], & pays [1 ]}
34
+ vNames = []string {"a" , "b" , "c" , "d" , "e" , "f" , "g" }
35
+ varNames = append (vNames , names ... )
36
+ varTypes = []string {"bool" , "address" , "bytes" , "string" ,
37
+ "uint8" , "int8" , "uint8" , "int8" , "uint16" , "int16" ,
38
+ "uint24" , "int24" , "uint32" , "int32" , "uint40" , "int40" , "uint48" , "int48" , "uint56" , "int56" ,
39
+ "uint64" , "int64" , "uint72" , "int72" , "uint80" , "int80" , "uint88" , "int88" , "uint96" , "int96" ,
40
+ "uint104" , "int104" , "uint112" , "int112" , "uint120" , "int120" , "uint128" , "int128" , "uint136" , "int136" ,
41
+ "uint144" , "int144" , "uint152" , "int152" , "uint160" , "int160" , "uint168" , "int168" , "uint176" , "int176" ,
42
+ "uint184" , "int184" , "uint192" , "int192" , "uint200" , "int200" , "uint208" , "int208" , "uint216" , "int216" ,
43
+ "uint224" , "int224" , "uint232" , "int232" , "uint240" , "int240" , "uint248" , "int248" , "uint256" , "int256" ,
44
+ "bytes1" , "bytes2" , "bytes3" , "bytes4" , "bytes5" , "bytes6" , "bytes7" , "bytes8" , "bytes9" , "bytes10" , "bytes11" ,
45
+ "bytes12" , "bytes13" , "bytes14" , "bytes15" , "bytes16" , "bytes17" , "bytes18" , "bytes19" , "bytes20" , "bytes21" ,
46
+ "bytes22" , "bytes23" , "bytes24" , "bytes25" , "bytes26" , "bytes27" , "bytes28" , "bytes29" , "bytes30" , "bytes31" ,
47
+ "bytes32" , "bytes" }
48
+ )
49
+
50
+ func unpackPack (abi abi.ABI , method string , input []byte ) ([]interface {}, bool ) {
51
+ if out , err := abi .Unpack (method , input ); err == nil {
52
+ _ , err := abi .Pack (method , out ... )
35
53
if err != nil {
36
54
// We have some false positives as we can unpack these type successfully, but not pack them
37
55
if err .Error () == "abi: cannot use []uint8 as type [0]int8 as argument" ||
38
56
err .Error () == "abi: cannot use uint8 as type int8 as argument" {
39
- return false
57
+ return out , false
40
58
}
41
59
panic (err )
42
60
}
43
- if ! bytes .Equal (input , output [4 :]) {
44
- panic (fmt .Sprintf ("unpackPack is not equal, \n input : %x\n output: %x" , input , output [4 :]))
45
- }
46
- return true
61
+ return out , true
47
62
}
48
- return false
63
+ return nil , false
49
64
}
50
65
51
- func packUnpack (abi abi.ABI , method string , input []interface {}) bool {
66
+ func packUnpack (abi abi.ABI , method string , input * []interface {}) bool {
52
67
if packed , err := abi .Pack (method , input ); err == nil {
53
68
outptr := reflect .New (reflect .TypeOf (input ))
54
69
err := abi .UnpackIntoInterface (outptr .Interface (), method , packed )
@@ -100,64 +115,23 @@ func createABI(name string, stateMutability, payable *string, inputs []args) (ab
100
115
return abi .JSON (strings .NewReader (sig ))
101
116
}
102
117
103
- func fillStruct (structs []interface {}, data []byte ) {
104
- if structs != nil && len (data ) != 0 {
105
- fuzz .NewFromGoFuzz (data ).Fuzz (& structs )
106
- }
107
- }
108
-
109
- func createStructs (args []args ) []interface {} {
110
- structs := make ([]interface {}, len (args ))
111
- for i , arg := range args {
112
- t , err := abi .NewType (arg .typ , "" , nil )
113
- if err != nil {
114
- panic (err )
115
- }
116
- structs [i ] = reflect .New (t .GetType ()).Elem ()
117
- }
118
- return structs
119
- }
120
-
121
118
func runFuzzer (input []byte ) int {
122
119
good := false
120
+ fuzzer := fuzz .NewFromGoFuzz (input )
123
121
124
- names := []string {"_name" , "name" , "NAME" , "name_" , "__" , "_name_" , "n" }
125
- stateMut := []string {"" , "pure" , "view" , "payable" }
126
- stateMutabilites := []* string {nil , & stateMut [0 ], & stateMut [1 ], & stateMut [2 ], & stateMut [3 ]}
127
- pays := []string {"true" , "false" }
128
- payables := []* string {nil , & pays [0 ], & pays [1 ]}
129
- varNames := []string {"a" , "b" , "c" , "d" , "e" , "f" , "g" }
130
- varNames = append (varNames , names ... )
131
- varTypes := []string {"bool" , "address" , "bytes" , "string" ,
132
- "uint8" , "int8" , "uint8" , "int8" , "uint16" , "int16" ,
133
- "uint24" , "int24" , "uint32" , "int32" , "uint40" , "int40" , "uint48" , "int48" , "uint56" , "int56" ,
134
- "uint64" , "int64" , "uint72" , "int72" , "uint80" , "int80" , "uint88" , "int88" , "uint96" , "int96" ,
135
- "uint104" , "int104" , "uint112" , "int112" , "uint120" , "int120" , "uint128" , "int128" , "uint136" , "int136" ,
136
- "uint144" , "int144" , "uint152" , "int152" , "uint160" , "int160" , "uint168" , "int168" , "uint176" , "int176" ,
137
- "uint184" , "int184" , "uint192" , "int192" , "uint200" , "int200" , "uint208" , "int208" , "uint216" , "int216" ,
138
- "uint224" , "int224" , "uint232" , "int232" , "uint240" , "int240" , "uint248" , "int248" , "uint256" , "int256" ,
139
- "bytes1" , "bytes2" , "bytes3" , "bytes4" , "bytes5" , "bytes6" , "bytes7" , "bytes8" , "bytes9" , "bytes10" , "bytes11" ,
140
- "bytes12" , "bytes13" , "bytes14" , "bytes15" , "bytes16" , "bytes17" , "bytes18" , "bytes19" , "bytes20" , "bytes21" ,
141
- "bytes22" , "bytes23" , "bytes24" , "bytes25" , "bytes26" , "bytes27" , "bytes28" , "bytes29" , "bytes30" , "bytes31" ,
142
- "bytes32" , "bytes" }
143
- rnd := rand .New (rand .NewSource (123456 ))
144
- if len (input ) > 0 {
145
- kec := crypto .Keccak256 (input )
146
- rnd = rand .New (rand .NewSource (int64 (kec [0 ])))
147
- }
148
- name := names [rnd .Intn (len (names ))]
149
- stateM := stateMutabilites [rnd .Intn (len (stateMutabilites ))]
150
- payable := payables [rnd .Intn (len (payables ))]
122
+ name := names [getUInt (fuzzer )% len (names )]
123
+ stateM := stateMutabilites [getUInt (fuzzer )% len (stateMutabilites )]
124
+ payable := payables [getUInt (fuzzer )% len (payables )]
151
125
maxLen := 5
152
126
for k := 1 ; k < maxLen ; k ++ {
153
127
var arg []args
154
128
for i := k ; i > 0 ; i -- {
155
129
argName := varNames [i ]
156
- argTyp := varTypes [rnd . Int31n ( int32 ( len (varTypes )) )]
157
- if rnd . Int31n ( 10 ) == 0 {
130
+ argTyp := varTypes [getUInt ( fuzzer ) % len (varTypes )]
131
+ if getUInt ( fuzzer ) % 10 == 0 {
158
132
argTyp += "[]"
159
- } else if rnd . Int31n ( 10 ) == 0 {
160
- arrayArgs := rnd . Int31n ( 30 ) + 1
133
+ } else if getUInt ( fuzzer ) % 10 == 0 {
134
+ arrayArgs := getUInt ( fuzzer ) % 30 + 1
161
135
argTyp += fmt .Sprintf ("[%d]" , arrayArgs )
162
136
}
163
137
arg = append (arg , args {
@@ -169,10 +143,8 @@ func runFuzzer(input []byte) int {
169
143
if err != nil {
170
144
continue
171
145
}
172
- structs := createStructs (arg )
173
- b := unpackPack (abi , name , structs , input )
174
- fillStruct (structs , input )
175
- c := packUnpack (abi , name , structs )
146
+ structs , b := unpackPack (abi , name , input )
147
+ c := packUnpack (abi , name , & structs )
176
148
good = good || b || c
177
149
}
178
150
if good {
@@ -184,3 +156,12 @@ func runFuzzer(input []byte) int {
184
156
func Fuzz (input []byte ) int {
185
157
return runFuzzer (input )
186
158
}
159
+
160
+ func getUInt (fuzzer * fuzz.Fuzzer ) int {
161
+ var i int
162
+ fuzzer .Fuzz (& i )
163
+ if i < 0 {
164
+ i *= - 1
165
+ }
166
+ return i
167
+ }
0 commit comments