|
@@ -77,59 +77,102 @@ func Obfuscate(file *ast.File, info *types.Info, fset *token.FileSet, linkString
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
- if node, ok := node.(*ast.CompositeLit); ok {
|
|
|
- if len(node.Elts) == 0 || len(node.Elts) > maxSizeBytes {
|
|
|
+ switch node := node.(type) {
|
|
|
+ case *ast.UnaryExpr:
|
|
|
+ // Account for the possibility of address operators like
|
|
|
+ // &[]byte used inline with function arguments.
|
|
|
+ //
|
|
|
+ // See issue #520.
|
|
|
+
|
|
|
+ if node.Op != token.AND {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
- byteType := types.Universe.Lookup("byte").Type()
|
|
|
-
|
|
|
- var arrayLen int64
|
|
|
- switch y := info.TypeOf(node.Type).(type) {
|
|
|
- case *types.Array:
|
|
|
- if y.Elem() != byteType {
|
|
|
- return true
|
|
|
- }
|
|
|
-
|
|
|
- arrayLen = y.Len()
|
|
|
-
|
|
|
- case *types.Slice:
|
|
|
- if y.Elem() != byteType {
|
|
|
- return true
|
|
|
+ if child, ok := node.X.(*ast.CompositeLit); ok {
|
|
|
+ newnode := handleCompositeLiteral(true, child, info)
|
|
|
+ if newnode != nil {
|
|
|
+ cursor.Replace(newnode)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
+ case *ast.CompositeLit:
|
|
|
+ // We replaced the &[]byte{...} case above. Here we account for the
|
|
|
+ // standard []byte{...} or [4]byte{...} value form.
|
|
|
+ //
|
|
|
+ // We need two separate calls to cursor.Replace, as it only supports
|
|
|
+ // replacing the node we're currently visiting, and the pointer variant
|
|
|
+ // requires us to move the ampersand operator.
|
|
|
+
|
|
|
+ parent, ok := cursor.Parent().(*ast.UnaryExpr)
|
|
|
+ if ok && parent.Op == token.AND {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
- data := make([]byte, 0, len(node.Elts))
|
|
|
+ newnode := handleCompositeLiteral(false, node, info)
|
|
|
+ if newnode != nil {
|
|
|
+ cursor.Replace(newnode)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- for _, el := range node.Elts {
|
|
|
- elType := info.Types[el]
|
|
|
+ return true
|
|
|
+ }
|
|
|
|
|
|
- if elType.Value == nil || elType.Value.Kind() != constant.Int {
|
|
|
- return true
|
|
|
- }
|
|
|
+ return astutil.Apply(file, pre, post).(*ast.File)
|
|
|
+}
|
|
|
|
|
|
- value, ok := constant.Uint64Val(elType.Value)
|
|
|
- if !ok {
|
|
|
- panic(fmt.Sprintf("cannot parse byte value: %v", elType.Value))
|
|
|
- }
|
|
|
+// handleCompositeLiteral checks if the input node is []byte or [...]byte and
|
|
|
+// calls the appropriate obfuscation method, returning a new node that should
|
|
|
+// be used to replace it.
|
|
|
+//
|
|
|
+// If the input is not a byte slice or array, the node is returned as-is and
|
|
|
+// the second return value will be false.
|
|
|
+func handleCompositeLiteral(isPointer bool, node *ast.CompositeLit, info *types.Info) ast.Node {
|
|
|
+ if len(node.Elts) == 0 || len(node.Elts) > maxSizeBytes {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
|
|
|
- data = append(data, byte(value))
|
|
|
- }
|
|
|
+ byteType := types.Universe.Lookup("byte").Type()
|
|
|
|
|
|
- if arrayLen > 0 {
|
|
|
- cursor.Replace(withPos(obfuscateByteArray(data, arrayLen), node.Pos()))
|
|
|
- } else {
|
|
|
- cursor.Replace(withPos(obfuscateByteSlice(data), node.Pos()))
|
|
|
- }
|
|
|
+ var arrayLen int64
|
|
|
+ switch y := info.TypeOf(node.Type).(type) {
|
|
|
+ case *types.Array:
|
|
|
+ if y.Elem() != byteType {
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
- return true
|
|
|
+ arrayLen = y.Len()
|
|
|
+
|
|
|
+ case *types.Slice:
|
|
|
+ if y.Elem() != byteType {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
- return astutil.Apply(file, pre, post).(*ast.File)
|
|
|
+ data := make([]byte, 0, len(node.Elts))
|
|
|
+
|
|
|
+ for _, el := range node.Elts {
|
|
|
+ elType := info.Types[el]
|
|
|
+
|
|
|
+ if elType.Value == nil || elType.Value.Kind() != constant.Int {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ value, ok := constant.Uint64Val(elType.Value)
|
|
|
+ if !ok {
|
|
|
+ panic(fmt.Sprintf("cannot parse byte value: %v", elType.Value))
|
|
|
+ }
|
|
|
+
|
|
|
+ data = append(data, byte(value))
|
|
|
+ }
|
|
|
+
|
|
|
+ if arrayLen > 0 {
|
|
|
+ return withPos(obfuscateByteArray(isPointer, data, arrayLen), node.Pos())
|
|
|
+ }
|
|
|
+
|
|
|
+ return withPos(obfuscateByteSlice(isPointer, data), node.Pos())
|
|
|
}
|
|
|
|
|
|
// withPos sets any token.Pos fields under node which affect printing to pos.
|
|
@@ -186,14 +229,25 @@ func obfuscateString(data string) *ast.CallExpr {
|
|
|
return ah.LambdaCall(ast.NewIdent("string"), block)
|
|
|
}
|
|
|
|
|
|
-func obfuscateByteSlice(data []byte) *ast.CallExpr {
|
|
|
+func obfuscateByteSlice(isPointer bool, data []byte) *ast.CallExpr {
|
|
|
obfuscator := randObfuscator()
|
|
|
block := obfuscator.obfuscate(data)
|
|
|
+
|
|
|
+ if isPointer {
|
|
|
+ block.List = append(block.List, ah.ReturnStmt(&ast.UnaryExpr{
|
|
|
+ Op: token.AND,
|
|
|
+ X: ast.NewIdent("data"),
|
|
|
+ }))
|
|
|
+ return ah.LambdaCall(&ast.StarExpr{
|
|
|
+ X: &ast.ArrayType{Elt: ast.NewIdent("byte")},
|
|
|
+ }, block)
|
|
|
+ }
|
|
|
+
|
|
|
block.List = append(block.List, ah.ReturnStmt(ast.NewIdent("data")))
|
|
|
return ah.LambdaCall(&ast.ArrayType{Elt: ast.NewIdent("byte")}, block)
|
|
|
}
|
|
|
|
|
|
-func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
|
|
|
+func obfuscateByteArray(isPointer bool, data []byte, length int64) *ast.CallExpr {
|
|
|
obfuscator := randObfuscator()
|
|
|
block := obfuscator.obfuscate(data)
|
|
|
|
|
@@ -224,10 +278,19 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
|
|
|
},
|
|
|
}},
|
|
|
},
|
|
|
- ah.ReturnStmt(ast.NewIdent("newdata")),
|
|
|
}
|
|
|
|
|
|
+ var retexpr ast.Expr = ast.NewIdent("newdata")
|
|
|
+ if isPointer {
|
|
|
+ retexpr = &ast.UnaryExpr{X: retexpr, Op: token.AND}
|
|
|
+ }
|
|
|
+
|
|
|
+ sliceToArray = append(sliceToArray, ah.ReturnStmt(retexpr))
|
|
|
block.List = append(block.List, sliceToArray...)
|
|
|
|
|
|
+ if isPointer {
|
|
|
+ return ah.LambdaCall(&ast.StarExpr{X: arrayType}, block)
|
|
|
+ }
|
|
|
+
|
|
|
return ah.LambdaCall(arrayType, block)
|
|
|
}
|