From 50d24cdf513bc8ef7adb69fd91162fb951fb6b9a Mon Sep 17 00:00:00 2001 From: lu4p Date: Sun, 19 Jul 2020 06:58:12 +0200 Subject: [PATCH] Add float, int, and boolean literal obfuscation. Add ast helper functions to reduce ast footprint. Add binsubfloat and binsubint functions for testing. Fixes #55. --- internal/literals/asthelpers.go | 71 ++++++++++ internal/literals/literals.go | 121 +++++++++-------- internal/literals/numbers.go | 229 ++++++++++++++++++++++++++++++++ internal/literals/xor.go | 22 ++- main_test.go | 103 +++++++++++++- testdata/scripts/literals.txt | 103 +++++++++++++- 6 files changed, 574 insertions(+), 75 deletions(-) create mode 100644 internal/literals/asthelpers.go create mode 100644 internal/literals/numbers.go diff --git a/internal/literals/asthelpers.go b/internal/literals/asthelpers.go new file mode 100644 index 0000000..e5b3a7b --- /dev/null +++ b/internal/literals/asthelpers.go @@ -0,0 +1,71 @@ +package literals + +import ( + "go/ast" + "go/token" + "strconv" +) + +func ident(name string) *ast.Ident { + return &ast.Ident{Name: name} +} +func intLiteral(value string) *ast.BasicLit { + return &ast.BasicLit{ + Kind: token.INT, + Value: value, + } +} + +// name[index] +func indexExpr(name string, index ast.Expr) *ast.IndexExpr { + return &ast.IndexExpr{ + X: ident(name), + Index: index, + } +} + +// fun(arg) +func callExpr(fun ast.Expr, arg ast.Expr) *ast.CallExpr { + var args []ast.Expr + if arg != nil { + args = []ast.Expr{arg} + } + + return &ast.CallExpr{ + Fun: fun, + Args: args, + } +} + +// func() resultType {block}() +func lambdaCall(resultType ast.Expr, block *ast.BlockStmt) *ast.CallExpr { + funcLit := &ast.FuncLit{ + Type: &ast.FuncType{ + Params: &ast.FieldList{}, + Results: &ast.FieldList{ + List: []*ast.Field{ + {Type: resultType}, + }, + }, + }, + Body: block, + } + return callExpr(funcLit, nil) +} + +// return result +func returnStmt(results ...ast.Expr) *ast.ReturnStmt { + return &ast.ReturnStmt{ + Results: results, + } +} + +// _ = data[pos] +func boundsCheckData(pos int) *ast.AssignStmt { + posStr := strconv.Itoa(pos) + return &ast.AssignStmt{ + Lhs: []ast.Expr{ident("_")}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{indexExpr("data", intLiteral(posStr))}, + } +} diff --git a/internal/literals/literals.go b/internal/literals/literals.go index 6c13622..3c481e2 100644 --- a/internal/literals/literals.go +++ b/internal/literals/literals.go @@ -11,36 +11,22 @@ import ( "golang.org/x/tools/go/ast/astutil" ) -func callExpr(resultType ast.Expr, block *ast.BlockStmt) *ast.CallExpr { - return &ast.CallExpr{Fun: &ast.FuncLit{ - Type: &ast.FuncType{ - Params: &ast.FieldList{}, - Results: &ast.FieldList{ - List: []*ast.Field{ - {Type: resultType}, - }, - }, - }, - Body: block, - }} -} +var ( + usesUnsafe bool + universalTrue = types.Universe.Lookup("true") + universalFalse = types.Universe.Lookup("false") +) func randObfuscator() obfuscator { randPos := mathrand.Intn(len(obfuscators)) return obfuscators[randPos] } -func returnStmt(result ast.Expr) *ast.ReturnStmt { - return &ast.ReturnStmt{ - Results: []ast.Expr{result}, - } -} - // Obfuscate replace literals with obfuscated lambda functions func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blacklist map[types.Object]struct{}) []*ast.File { pre := func(cursor *astutil.Cursor) bool { - switch x := cursor.Node().(type) { + switch x := cursor.Node().(type) { case *ast.GenDecl: if x.Tok != token.CONST { return true @@ -84,6 +70,10 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli case *ast.CompositeLit: byteType := types.Universe.Lookup("byte").Type() + if len(x.Elts) == 0 { + return true + } + switch y := info.TypeOf(x.Type).(type) { case *types.Array: if y.Elem() != byteType { @@ -112,7 +102,7 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli return true } - var data []byte + data := make([]byte, 0, len(x.Elts)) for _, el := range x.Elts { lit, ok := el.(*ast.BasicLit) @@ -139,6 +129,8 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli } switch x.Kind { + case token.FLOAT, token.INT: + obfuscateNumberLiteral(cursor, info) case token.STRING: typeInfo := info.TypeOf(x) if typeInfo != types.Typ[types.String] && typeInfo != types.Typ[types.UntypedString] { @@ -149,15 +141,40 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli panic(fmt.Sprintf("cannot unquote string: %v", err)) } + if len(value) == 0 { + return true + } + cursor.Replace(obfuscateString(value)) } + case *ast.UnaryExpr: + switch cursor.Name() { + case "Values", "Rhs", "Value", "Args", "X": + default: + return true // we don't want to obfuscate imports etc. + } + + obfuscateNumberLiteral(cursor, info) + case *ast.Ident: + obj := info.ObjectOf(x) + if obj == nil { + return true + } + + if obj == universalTrue || obj == universalFalse { + cursor.Replace(obfuscateBool(x.Name == "true")) + } } return true } for i := range files { + usesUnsafe = false files[i] = astutil.Apply(files[i], pre, post).(*ast.File) + if usesUnsafe { + astutil.AddImport(fset, files[i], "unsafe") + } } return files } @@ -165,23 +182,17 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli func obfuscateString(data string) *ast.CallExpr { obfuscator := randObfuscator() block := obfuscator.obfuscate([]byte(data)) - block.List = append(block.List, &ast.ReturnStmt{ - Results: []ast.Expr{&ast.CallExpr{ - Fun: &ast.Ident{Name: "string"}, - Args: []ast.Expr{&ast.Ident{Name: "data"}}, - }}, - }) - - return callExpr(&ast.Ident{Name: "string"}, block) + + block.List = append(block.List, returnStmt(callExpr(ident("string"), ident("data")))) + + return lambdaCall(ident("string"), block) } func obfuscateByteSlice(data []byte) *ast.CallExpr { obfuscator := randObfuscator() block := obfuscator.obfuscate(data) - block.List = append(block.List, &ast.ReturnStmt{ - Results: []ast.Expr{&ast.Ident{Name: "data"}}, - }) - return callExpr(&ast.ArrayType{Elt: &ast.Ident{Name: "byte"}}, block) + block.List = append(block.List, returnStmt(ident("data"))) + return lambdaCall(&ast.ArrayType{Elt: ident("byte")}, block) } func obfuscateByteArray(data []byte, length int64) *ast.CallExpr { @@ -189,11 +200,8 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr { block := obfuscator.obfuscate(data) arrayType := &ast.ArrayType{ - Len: &ast.BasicLit{ - Kind: token.INT, - Value: strconv.Itoa(int(length)), - }, - Elt: &ast.Ident{Name: "byte"}, + Len: intLiteral(strconv.Itoa(int(length))), + Elt: ident("byte"), } sliceToArray := []ast.Stmt{ @@ -201,37 +209,44 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr { Decl: &ast.GenDecl{ Tok: token.VAR, Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: "newdata"}}, + Names: []*ast.Ident{ident("newdata")}, Type: arrayType, }}, }, }, &ast.RangeStmt{ - Key: &ast.Ident{Name: "i"}, + Key: ident("i"), Tok: token.DEFINE, - X: &ast.Ident{Name: "newdata"}, + X: ident("newdata"), Body: &ast.BlockStmt{List: []ast.Stmt{ &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.IndexExpr{ - X: &ast.Ident{Name: "newdata"}, - Index: &ast.Ident{Name: "i"}, - }}, + Lhs: []ast.Expr{indexExpr("newdata", ident("i"))}, Tok: token.ASSIGN, - Rhs: []ast.Expr{&ast.IndexExpr{ - X: &ast.Ident{Name: "data"}, - Index: &ast.Ident{Name: "i"}, - }}, + Rhs: []ast.Expr{indexExpr("data", ident("i"))}, }, }}, }, - &ast.ReturnStmt{Results: []ast.Expr{ - &ast.Ident{Name: "newdata"}, - }}, + returnStmt(ident("newdata")), } block.List = append(block.List, sliceToArray...) - return callExpr(arrayType, block) + return lambdaCall(arrayType, block) +} + +func obfuscateBool(data bool) *ast.BinaryExpr { + var dataUint64 uint64 = 0 + if data { + dataUint64 = 1 + } + + intType := intTypes[types.Typ[types.Uint8]] + + return &ast.BinaryExpr{ + X: genObfuscateInt(dataUint64, intType), + Op: token.EQL, + Y: intLiteral("1"), + } } // ConstBlacklist blacklist identifieres used in constant expressions diff --git a/internal/literals/numbers.go b/internal/literals/numbers.go new file mode 100644 index 0000000..ca30b3c --- /dev/null +++ b/internal/literals/numbers.go @@ -0,0 +1,229 @@ +package literals + +import ( + "encoding/binary" + "errors" + "go/ast" + "go/token" + "go/types" + "math" + "reflect" + "strconv" + + "golang.org/x/tools/go/ast/astutil" +) + +var intTypes = map[types.Type]reflect.Type{ + types.Typ[types.UntypedInt]: reflect.TypeOf(int(0)), + types.Typ[types.Int]: reflect.TypeOf(int(0)), + types.Typ[types.Int8]: reflect.TypeOf(int8(0)), + types.Typ[types.Int16]: reflect.TypeOf(int16(0)), + types.Typ[types.Int32]: reflect.TypeOf(int32(0)), + types.Typ[types.Int64]: reflect.TypeOf(int64(0)), + types.Typ[types.Uint]: reflect.TypeOf(uint(0)), + types.Typ[types.Uint8]: reflect.TypeOf(uint8(0)), + types.Typ[types.Uint16]: reflect.TypeOf(uint16(0)), + types.Typ[types.Uint32]: reflect.TypeOf(uint32(0)), + types.Typ[types.Uint64]: reflect.TypeOf(uint64(0)), + types.Typ[types.Uintptr]: reflect.TypeOf(uintptr(0)), +} + +func obfuscateNumberLiteral(cursor *astutil.Cursor, info *types.Info) error { + var ( + call *ast.CallExpr + basic *ast.BasicLit + ok bool + typeInfo types.Type + ) + + sign := "" + node := cursor.Node() + + switch x := node.(type) { + case *ast.UnaryExpr: + basic, ok = x.X.(*ast.BasicLit) + if !ok { + return errors.New("UnaryExpr doesn't contain basic literal") + } + typeInfo = info.TypeOf(x) + + if x.Op != token.SUB { + return errors.New("UnaryExpr has a non SUB token") + } + sign = "-" + + switch y := cursor.Parent().(type) { + case *ast.ValueSpec: + tempInfo := info.TypeOf(y.Type) + if tempInfo != nil { + typeInfo = tempInfo + } + } + + case *ast.BasicLit: + basic = x + typeInfo = info.TypeOf(x) + + switch typeInfo { + case types.Typ[types.UntypedFloat], types.Typ[types.UntypedInt]: + // The post calls from astutil.Apply can be out of order, + // this guards against the case where the ast.BasicLit is inside an ast.UnaryExpr + // and the BasicLit gets evaluated before the UnaryExpr + if _, ok := cursor.Parent().(*ast.UnaryExpr); ok { + return nil + } + } + + default: + return errors.New("Wrong node Type") + } + + strValue := sign + basic.Value + + switch typeInfo { + case types.Typ[types.Float32]: + fV, err := strconv.ParseFloat(strValue, 32) + if err != nil { + return err + } + call = genObfuscateFloat(float32(fV)) + case types.Typ[types.Float64], types.Typ[types.UntypedFloat]: + fV, err := strconv.ParseFloat(strValue, 64) + if err != nil { + return err + } + call = genObfuscateFloat(fV) + } + + if call != nil { + cursor.Replace(call) + return nil + } + + intValue, err := strconv.ParseInt(strValue, 0, 64) + if err != nil { + return err + } + + intType, ok := intTypes[typeInfo] + if !ok { + return errors.New("Wrong type") + } + + call = genObfuscateInt(uint64(intValue), intType) + + cursor.Replace(call) + return nil +} + +func bytesToUint(bits int) ast.Expr { + bytes := bits / 8 + bitsStr := strconv.Itoa(bits) + + var expr ast.Expr + for i := 0; i < bytes; i++ { + posStr := strconv.Itoa(i) + + if i == 0 { + expr = callExpr(ident("uint"+bitsStr), indexExpr("data", intLiteral(posStr))) + continue + } + + shiftValue := strconv.Itoa(i * 8) + expr = &ast.BinaryExpr{ + X: expr, + Op: token.OR, + Y: &ast.BinaryExpr{ + X: callExpr(ident("uint"+bitsStr), indexExpr("data", intLiteral(posStr))), + Op: token.SHL, + Y: intLiteral(shiftValue), + }, + } + } + + return expr +} + +func genObfuscateInt(data uint64, typeInfo reflect.Type) *ast.CallExpr { + obfuscator := randObfuscator() + bitsize := typeInfo.Bits() + + bitSizeStr := strconv.Itoa(bitsize) + byteSize := bitsize / 8 + b := make([]byte, byteSize) + + switch bitsize { + case 8: + b = []byte{uint8(data)} + case 16: + binary.LittleEndian.PutUint16(b, uint16(data)) + case 32: + binary.LittleEndian.PutUint32(b, uint32(data)) + case 64: + binary.LittleEndian.PutUint64(b, uint64(data)) + default: + panic("data has the wrong length " + bitSizeStr) + } + + block := obfuscator.obfuscate(b) + convertExpr := bytesToUint(bitsize) + + block.List = append(block.List, boundsCheckData(byteSize-1), returnStmt(callExpr(ident(typeInfo.Name()), convertExpr))) + + return lambdaCall(ident(typeInfo.Name()), block) +} + +func uintToFloat(uintExpr *ast.CallExpr, typeStr string) *ast.CallExpr { + usesUnsafe = true + convert := &ast.StarExpr{ + X: callExpr( + &ast.ParenExpr{ + X: &ast.StarExpr{X: ident(typeStr)}, + }, + callExpr( + &ast.SelectorExpr{ + X: ident("unsafe"), + Sel: ident("Pointer"), + }, + &ast.UnaryExpr{ + Op: token.AND, + X: ident("result"), + }, + ), + ), + } + + block := &ast.BlockStmt{List: []ast.Stmt{ + &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "result"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{uintExpr}, + }, + returnStmt(convert), + }} + + return lambdaCall(ident(typeStr), block) +} + +func genObfuscateFloat(data interface{}) *ast.CallExpr { + var ( + b uint64 + typeStr string + intType reflect.Type + ) + + switch x := data.(type) { + case float32: + intType = intTypes[types.Typ[types.Uint32]] + typeStr = "float32" + b = uint64(math.Float32bits(x)) + case float64: + intType = intTypes[types.Typ[types.Uint64]] + typeStr = "float64" + b = math.Float64bits(x) + default: + panic("data has the wrong type") + } + + return uintToFloat(genObfuscateInt(b, intType), typeStr) +} diff --git a/internal/literals/xor.go b/internal/literals/xor.go index 312a602..e52054c 100644 --- a/internal/literals/xor.go +++ b/internal/literals/xor.go @@ -20,34 +20,28 @@ func (x xor) obfuscate(data []byte) *ast.BlockStmt { return &ast.BlockStmt{List: []ast.Stmt{ &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "key"}}, + Lhs: []ast.Expr{ident("key")}, Tok: token.DEFINE, Rhs: []ast.Expr{dataToByteSlice(key)}, }, &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "data"}}, + Lhs: []ast.Expr{ident("data")}, Tok: token.DEFINE, Rhs: []ast.Expr{dataToByteSlice(data)}, }, &ast.RangeStmt{ - Key: &ast.Ident{Name: "i"}, - Value: &ast.Ident{Name: "b"}, + Key: ident("i"), + Value: ident("b"), Tok: token.DEFINE, - X: &ast.Ident{Name: "key"}, + X: ident("key"), Body: &ast.BlockStmt{List: []ast.Stmt{ &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.IndexExpr{ - X: &ast.Ident{Name: "data"}, - Index: &ast.Ident{Name: "i"}, - }}, + Lhs: []ast.Expr{indexExpr("data", ident("i"))}, Tok: token.ASSIGN, Rhs: []ast.Expr{&ast.BinaryExpr{ - X: &ast.IndexExpr{ - X: &ast.Ident{Name: "data"}, - Index: &ast.Ident{Name: "i"}, - }, + X: indexExpr("data", ident("i")), Op: token.XOR, - Y: &ast.Ident{Name: "b"}, + Y: ident("b"), }}, }, }}, diff --git a/main_test.go b/main_test.go index 9062f0b..f655a55 100644 --- a/main_test.go +++ b/main_test.go @@ -4,15 +4,19 @@ package main import ( + "encoding/binary" "flag" "fmt" "io" + "math" "os" "os/exec" "path/filepath" "runtime" + "strconv" "strings" "testing" + "time" "github.com/rogpeppe/go-internal/goproxytest" "github.com/rogpeppe/go-internal/gotooltest" @@ -73,8 +77,10 @@ func TestScripts(t *testing.T) { return nil }, Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){ - "binsubstr": binsubstr, - "bincmp": bincmp, + "binsubstr": binsubstr, + "bincmp": bincmp, + "binsubint": binsubint, + "binsubfloat": binsubfloat, }, UpdateScripts: *update, } @@ -101,11 +107,35 @@ func copyFile(from, to string) error { return err } +type binaryCache struct { + name string + modtime time.Time + content string +} + +var cachedBinary binaryCache + +func readFile(ts *testscript.TestScript, file string) string { + file = ts.MkAbs(file) + info, err := os.Stat(file) + if err != nil { + ts.Fatalf("%v", err) + } + + if cachedBinary.modtime == info.ModTime() && cachedBinary.name == file { + return cachedBinary.content + } + + cachedBinary.name = file + cachedBinary.modtime = info.ModTime() + cachedBinary.content = ts.ReadFile(file) + return cachedBinary.content +} func binsubstr(ts *testscript.TestScript, neg bool, args []string) { if len(args) < 2 { ts.Fatalf("usage: binsubstr file substr...") } - data := ts.ReadFile(args[0]) + data := readFile(ts, args[0]) var failed []string for _, substr := range args[1:] { match := strings.Contains(data, substr) @@ -122,6 +152,73 @@ func binsubstr(ts *testscript.TestScript, neg bool, args []string) { } } +func binsubint(ts *testscript.TestScript, neg bool, args []string) { + if len(args) < 2 { + ts.Fatalf("usage: binsubint file subint...") + } + + data := readFile(ts, args[0]) + var failed []string + for _, subIntStr := range args[1:] { + subInt, err := strconv.Atoi(subIntStr) + if err != nil { + ts.Fatalf("%v", err) + } + + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(subInt)) + + match := strings.Contains(data, string(b)) + if !match { + binary.BigEndian.PutUint64(b, uint64(subInt)) + match = strings.Contains(data, string(b)) + } + if match && neg { + failed = append(failed, subIntStr) + } else if !match && !neg { + failed = append(failed, subIntStr) + } + } + if len(failed) > 0 && neg { + ts.Fatalf("unexpected match for %s in %s", failed, args[0]) + } else if len(failed) > 0 { + ts.Fatalf("expected match for %s in %s", failed, args[0]) + } +} + +func binsubfloat(ts *testscript.TestScript, neg bool, args []string) { + if len(args) < 2 { + ts.Fatalf("usage: binsubint file binsubfloat...") + } + data := readFile(ts, args[0]) + var failed []string + for _, subFloatStr := range args[1:] { + subFloat, err := strconv.ParseFloat(subFloatStr, 64) + if err != nil { + ts.Fatalf("%v", err) + } + + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, math.Float64bits(subFloat)) + + match := strings.Contains(data, string(b)) + if !match { + binary.BigEndian.PutUint64(b, math.Float64bits(subFloat)) + match = strings.Contains(data, string(b)) + } + if match && neg { + failed = append(failed, subFloatStr) + } else if !match && !neg { + failed = append(failed, subFloatStr) + } + } + if len(failed) > 0 && neg { + ts.Fatalf("unexpected match for %s in %s", failed, args[0]) + } else if len(failed) > 0 { + ts.Fatalf("expected match for %s in %s", failed, args[0]) + } +} + func bincmp(ts *testscript.TestScript, neg bool, args []string) { if len(args) != 2 { ts.Fatalf("usage: bincmp file1 file2") diff --git a/testdata/scripts/literals.txt b/testdata/scripts/literals.txt index 3b4d2a7..c55b36f 100644 --- a/testdata/scripts/literals.txt +++ b/testdata/scripts/literals.txt @@ -1,13 +1,21 @@ -go run . +go build +exec ./main$exe +binsubstr main$exe 'Lorem' 'dolor' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String' + +binsubint main$exe '-7081390804778629748' '-301627827188279046' '7679634459002713443' +binsubfloat main$exe '3684433217126772357.33' '-9015867427900753906' cmp stderr main.stderr cp stderr normal.stderr garble -literals build exec ./main$exe cmp stderr main.stderr cmp stderr normal.stderr -! binsubstr main$exe 'garbleDecrypt' 'Lorem' 'ipsum' 'dolor' 'first assign' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String' 'stringTypeStruct' +! binsubstr main$exe 'garbleDecrypt' 'Lorem' 'dolor' 'first assign' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String' -binsubstr main$exe 'also skip this' 'skip typed const' 'skip typed var' 'skip typed var assign' 'stringTypeField strType' 'stringType lambda func return' 'testMap1 key' 'testMap2 key' 'testMap3 key' 'testMap1 value' 'testMap3 value' 'testMap1 new value' 'testMap3 new value' 'stringType func param' 'stringType return' 'skip untyped const' +binsubstr main$exe 'Skip this block' 'also skip this' 'skip typed const' 'skip typed var' 'skip typed var assign' 'stringTypeField strType' 'stringType lambda func return' 'testMap1 key' 'testMap2 key' 'testMap3 key' 'testMap1 value' 'testMap3 value' 'testMap1 new value' 'testMap3 new value' 'stringType func param' 'stringType return' 'skip untyped const' + +! binsubint main$exe '-7081390804778629748' '-301627827188279046' '7679634459002713443' +! binsubfloat main$exe '3684433217126772357.33' '-9015867427900753906' [short] stop # checking that the build is reproducible is slow # Also check that the binary is reproducible. @@ -35,6 +43,8 @@ Second Line` const ( i = 1 boolean = true + + skip1 = "Skip this block" ) const ( @@ -82,11 +92,13 @@ func main() { testMap["map key"] = "new value" println(testMap["map key"]) println("another literal") - println(skip2) + println(skip1, skip2) println(i, foo, bar) typedTest() constantTest() byteTest() + numTest() + boolTest() } type stringType string @@ -196,6 +208,80 @@ func stringTypeFunc(s stringType) stringType { return "stringType return" // skip } +func numTest() { + const a = 1 // skip + + const b = a + 2 // skip + + const c = 2824583991413579605 + + d := 4 + + var e = 5 + + var f int + f = 3735714531481032066 + + println(a, b, c, d, e, f) + + var ( + untypedInt = -7081390804778629760 + 12 + intVar int = -301627827188279046 + int8Var int8 = -122.0 + int16Var int16 = 3534 + int32Var int32 = 333453534 + int64Var int64 = 4568766098255857483 + + uintVar uint = 7679634459002713443 + uint8Var uint8 = 34 + uint16Var uint16 = 3534 + uint32Var uint32 = 333453534 + uint64Var uint64 = 5490982829161518439 + uintptrVar uintptr = 7364326871810921708 + + untypedFloat = 3684433217126772357.33 + floatVar float64 = -9015867427900753906 + floatVar32 float32 = 6338507605633 + + complexVar64 complex64 = -435453453534 // skip + complexVar128 complex128 = 1 + 4i // skip + + underscoreInt = 1_3_3_7 + underscoreFloat = 1_3_3_7.0 + + hexInt = 0x1337 // skip + hexFloat = 0x1337p0 // skip + + octalInt = 0o1337 // skip + octalFloat = 0o1337 // skip + ) + + floatShort := -435453453534.0 + println(untypedInt, intVar, int8Var, int16Var, int32Var, int64Var) + println(uintVar, uint8Var, uint16Var, uint32Var, uint64Var, uintptrVar) + println(untypedFloat, floatVar, floatShort, floatVar32) + println(complexVar64, complexVar128) + println(underscoreInt, underscoreFloat, hexInt, hexFloat, octalInt, octalFloat) + +} + +func boolTest() { + const a = true // skip + + const b = false == a // skip + + const c bool = false + + d := true + + var e = true + + var f bool + f = false + + println(a, b, c, d, e, f) +} + -- main.stderr -- Lorem true First Line @@ -207,7 +293,7 @@ second assign to obfuscate also obfuscate new value another literal -also skip this +Skip this block also skip this 1 0 1 skip untyped const skip typed const skip typed var skip typed var assign @@ -222,3 +308,10 @@ foo 12, 13, 12, 13, 12, 13, 0, 0, +1 3 2824583991413579605 4 5 3735714531481032066 +-7081390804778629748 -301627827188279046 -122 3534 333453534 4568766098255857483 +7679634459002713443 34 3534 333453534 5490982829161518439 7364326871810921708 ++3.684433e+018 -9.015867e+018 -4.354535e+011 +6.338508e+012 +(-4.354535e+011+0.000000e+000i) (+1.000000e+000+4.000000e+000i) +1337 +1.337000e+003 4919 +4.919000e+003 735 735 +true false false true true false