mirror of
https://github.com/burrowers/garble.git
synced 2025-10-05 15:56:55 +08:00
remove buggy number literal obfuscation
Also remove boolean literal obfuscation.
This commit is contained in:
@@ -129,8 +129,6 @@ 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] {
|
||||
@@ -147,23 +145,6 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli
|
||||
|
||||
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
|
||||
@@ -234,21 +215,6 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
|
||||
return ah.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: ah.IntLit(1),
|
||||
}
|
||||
}
|
||||
|
||||
// ConstBlacklist blacklist identifieres used in constant expressions
|
||||
func ConstBlacklist(node ast.Node, info *types.Info, blacklist map[types.Object]struct{}) {
|
||||
blacklistObjects := func(node ast.Node) bool {
|
||||
|
@@ -1,228 +0,0 @@
|
||||
package literals
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
ah "mvdan.cc/garble/internal/asthelper"
|
||||
)
|
||||
|
||||
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++ {
|
||||
if i == 0 {
|
||||
expr = ah.CallExpr(ah.Ident("uint"+bitsStr), ah.IndexExpr("data", ah.IntLit(i)))
|
||||
continue
|
||||
}
|
||||
|
||||
shiftValue := i * 8
|
||||
expr = &ast.BinaryExpr{
|
||||
X: expr,
|
||||
Op: token.OR,
|
||||
Y: &ast.BinaryExpr{
|
||||
X: ah.CallExpr(ah.Ident("uint"+bitsStr), ah.IndexExpr("data", ah.IntLit(i))),
|
||||
Op: token.SHL,
|
||||
Y: ah.IntLit(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, ah.BoundsCheck("data", byteSize-1), ah.ReturnStmt(ah.CallExpr(ah.Ident(typeInfo.Name()), convertExpr)))
|
||||
|
||||
return ah.LambdaCall(ah.Ident(typeInfo.Name()), block)
|
||||
}
|
||||
|
||||
func uintToFloat(uintExpr *ast.CallExpr, typeStr string) *ast.CallExpr {
|
||||
usesUnsafe = true
|
||||
convert := &ast.StarExpr{
|
||||
X: ah.CallExpr(
|
||||
&ast.ParenExpr{
|
||||
X: &ast.StarExpr{X: ah.Ident(typeStr)},
|
||||
},
|
||||
ah.CallExpr(
|
||||
&ast.SelectorExpr{
|
||||
X: ah.Ident("unsafe"),
|
||||
Sel: ah.Ident("Pointer"),
|
||||
},
|
||||
&ast.UnaryExpr{
|
||||
Op: token.AND,
|
||||
X: ah.Ident("result"),
|
||||
},
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
block := &ast.BlockStmt{List: []ast.Stmt{
|
||||
&ast.AssignStmt{
|
||||
Lhs: []ast.Expr{ah.Ident("result")},
|
||||
Tok: token.DEFINE,
|
||||
Rhs: []ast.Expr{uintExpr},
|
||||
},
|
||||
ah.ReturnStmt(convert),
|
||||
}}
|
||||
|
||||
return ah.LambdaCall(ah.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)
|
||||
}
|
21
main_test.go
21
main_test.go
@@ -4,7 +4,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -262,26 +261,14 @@ func bincmp(ts *testscript.TestScript, neg bool, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
var literalGenerators = []func() *ast.BasicLit{
|
||||
func() *ast.BasicLit {
|
||||
func generateStringLit() *ast.BasicLit {
|
||||
buffer := make([]byte, 1+mathrand.Intn(255))
|
||||
_, err := mathrand.Read(buffer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
str := base32.StdEncoding.EncodeToString(buffer)
|
||||
return ah.StringLit(str)
|
||||
},
|
||||
func() *ast.BasicLit {
|
||||
i := mathrand.Int()
|
||||
return ah.IntLit(i)
|
||||
},
|
||||
func() *ast.BasicLit {
|
||||
return ah.Float64Lit(mathrand.NormFloat64())
|
||||
},
|
||||
func() *ast.BasicLit {
|
||||
return ah.Float32Lit(mathrand.Float32())
|
||||
},
|
||||
|
||||
return ah.StringLit(string(buffer))
|
||||
}
|
||||
|
||||
func generateLiterals(ts *testscript.TestScript, neg bool, args []string) {
|
||||
@@ -301,7 +288,7 @@ func generateLiterals(ts *testscript.TestScript, neg bool, args []string) {
|
||||
|
||||
var statements []ast.Stmt
|
||||
for i := 0; i < literalCount; i++ {
|
||||
literal := literalGenerators[i%len(literalGenerators)]()
|
||||
literal := generateStringLit()
|
||||
statements = append(statements, ah.ExprStmt(ah.CallExpr(ah.Ident("println"), literal)))
|
||||
}
|
||||
|
||||
|
83
testdata/scripts/literals.txt
vendored
83
testdata/scripts/literals.txt
vendored
@@ -1,14 +1,12 @@
|
||||
env GOPRIVATE=test/main
|
||||
|
||||
# Generate and write random literals into a separate file
|
||||
generate-literals extraLiterals.go 500 printExtraLiterals
|
||||
generate-literals extraLiterals.go 100 printExtraLiterals
|
||||
|
||||
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'
|
||||
|
||||
cp stderr normal.stderr
|
||||
|
||||
@@ -18,8 +16,6 @@ cmp stderr normal.stderr
|
||||
|
||||
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'
|
||||
! binsubstr main$exe 'garbleDecrypt' 'Lorem' 'dolor' 'first assign' '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'
|
||||
[short] stop # checking that the build is reproducible is slow
|
||||
|
||||
# Also check that the binary is reproducible.
|
||||
@@ -127,9 +123,6 @@ func main() {
|
||||
typedTest()
|
||||
constantTest()
|
||||
byteTest()
|
||||
numTest()
|
||||
boolTest()
|
||||
printExtraLiterals()
|
||||
}
|
||||
|
||||
type stringType string
|
||||
@@ -238,77 +231,3 @@ func stringTypeFunc(s stringType) stringType {
|
||||
println(s)
|
||||
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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user