move asthelper functions to separate package (#78)

pull/79/head
lu4p 5 years ago committed by GitHub
parent 846ddb4097
commit 5cbbac56f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,98 @@
package asthelper
import (
"fmt"
"go/ast"
"go/token"
"strconv"
)
// Ident an identifier
func Ident(name string) *ast.Ident {
return &ast.Ident{Name: name}
}
// StringLit returns an ast.BasicLit of kind STRING
func StringLit(value string) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.STRING,
Value: fmt.Sprintf("%q", value),
}
}
// IntLit returns an ast.BasicLit of kind INT
func IntLit(value int) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.INT,
Value: strconv.Itoa(value),
}
}
// IndexExpr "name[index]"
func IndexExpr(name string, index ast.Expr) *ast.IndexExpr {
return &ast.IndexExpr{
X: Ident(name),
Index: index,
}
}
// CallExpr "fun(arg)"
func CallExpr(fun ast.Expr, args ...ast.Expr) *ast.CallExpr {
return &ast.CallExpr{
Fun: fun,
Args: args,
}
}
// LambdaCall "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)
}
// ReturnStmt "return result"
func ReturnStmt(results ...ast.Expr) *ast.ReturnStmt {
return &ast.ReturnStmt{
Results: results,
}
}
// BoundsCheck "_ = name[pos]"
func BoundsCheck(name string, pos int) *ast.AssignStmt {
return &ast.AssignStmt{
Lhs: []ast.Expr{Ident("_")},
Tok: token.ASSIGN,
Rhs: []ast.Expr{IndexExpr("data", IntLit(pos))},
}
}
// BlockStmt a block of multiple statments e.g. a function body
func BlockStmt(stmts ...ast.Stmt) *ast.BlockStmt {
return &ast.BlockStmt{List: stmts}
}
// ExprStmt convert an ast.Expr to an ast.Stmt
func ExprStmt(expr ast.Expr) *ast.ExprStmt {
return &ast.ExprStmt{X: expr}
}
// DataToByteSlice turns a byte slice like []byte{1, 2, 3} into an AST
// expression
func DataToByteSlice(data []byte) *ast.CallExpr {
return &ast.CallExpr{
Fun: &ast.ArrayType{
Elt: &ast.Ident{Name: "byte"},
},
Args: []ast.Expr{StringLit(string(data))},
}
}

@ -1,71 +0,0 @@
package literals
import (
"go/ast"
"go/token"
"strconv"
)
func ident(name string) *ast.Ident {
return &ast.Ident{Name: name}
}
func intLiteral(value int) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.INT,
Value: strconv.Itoa(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 {
return &ast.AssignStmt{
Lhs: []ast.Expr{ident("_")},
Tok: token.ASSIGN,
Rhs: []ast.Expr{indexExpr("data", intLiteral(pos))},
}
}

@ -9,6 +9,7 @@ import (
"strconv"
"golang.org/x/tools/go/ast/astutil"
ah "mvdan.cc/garble/internal/asthelper"
)
var (
@ -182,16 +183,16 @@ func obfuscateString(data string) *ast.CallExpr {
obfuscator := randObfuscator()
block := obfuscator.obfuscate([]byte(data))
block.List = append(block.List, returnStmt(callExpr(ident("string"), ident("data"))))
block.List = append(block.List, ah.ReturnStmt(ah.CallExpr(ah.Ident("string"), ah.Ident("data"))))
return lambdaCall(ident("string"), block)
return ah.LambdaCall(ah.Ident("string"), block)
}
func obfuscateByteSlice(data []byte) *ast.CallExpr {
obfuscator := randObfuscator()
block := obfuscator.obfuscate(data)
block.List = append(block.List, returnStmt(ident("data")))
return lambdaCall(&ast.ArrayType{Elt: ident("byte")}, block)
block.List = append(block.List, ah.ReturnStmt(ah.Ident("data")))
return ah.LambdaCall(&ast.ArrayType{Elt: ah.Ident("byte")}, block)
}
func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
@ -199,8 +200,8 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
block := obfuscator.obfuscate(data)
arrayType := &ast.ArrayType{
Len: intLiteral(int(length)),
Elt: ident("byte"),
Len: ah.IntLit(int(length)),
Elt: ah.Ident("byte"),
}
sliceToArray := []ast.Stmt{
@ -208,29 +209,29 @@ func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
Decl: &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{&ast.ValueSpec{
Names: []*ast.Ident{ident("newdata")},
Names: []*ast.Ident{ah.Ident("newdata")},
Type: arrayType,
}},
},
},
&ast.RangeStmt{
Key: ident("i"),
Key: ah.Ident("i"),
Tok: token.DEFINE,
X: ident("newdata"),
X: ah.Ident("newdata"),
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{indexExpr("newdata", ident("i"))},
Lhs: []ast.Expr{ah.IndexExpr("newdata", ah.Ident("i"))},
Tok: token.ASSIGN,
Rhs: []ast.Expr{indexExpr("data", ident("i"))},
Rhs: []ast.Expr{ah.IndexExpr("data", ah.Ident("i"))},
},
}},
},
returnStmt(ident("newdata")),
ah.ReturnStmt(ah.Ident("newdata")),
}
block.List = append(block.List, sliceToArray...)
return lambdaCall(arrayType, block)
return ah.LambdaCall(arrayType, block)
}
func obfuscateBool(data bool) *ast.BinaryExpr {
@ -244,7 +245,7 @@ func obfuscateBool(data bool) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: genObfuscateInt(dataUint64, intType),
Op: token.EQL,
Y: intLiteral(1),
Y: ah.IntLit(1),
}
}

@ -11,6 +11,7 @@ import (
"strconv"
"golang.org/x/tools/go/ast/astutil"
ah "mvdan.cc/garble/internal/asthelper"
)
var intTypes = map[types.Type]reflect.Type{
@ -123,7 +124,7 @@ func bytesToUint(bits int) ast.Expr {
var expr ast.Expr
for i := 0; i < bytes; i++ {
if i == 0 {
expr = callExpr(ident("uint"+bitsStr), indexExpr("data", intLiteral(i)))
expr = ah.CallExpr(ah.Ident("uint"+bitsStr), ah.IndexExpr("data", ah.IntLit(i)))
continue
}
@ -132,9 +133,9 @@ func bytesToUint(bits int) ast.Expr {
X: expr,
Op: token.OR,
Y: &ast.BinaryExpr{
X: callExpr(ident("uint"+bitsStr), indexExpr("data", intLiteral(i))),
X: ah.CallExpr(ah.Ident("uint"+bitsStr), ah.IndexExpr("data", ah.IntLit(i))),
Op: token.SHL,
Y: intLiteral(shiftValue),
Y: ah.IntLit(shiftValue),
},
}
}
@ -166,26 +167,26 @@ func genObfuscateInt(data uint64, typeInfo reflect.Type) *ast.CallExpr {
block := obfuscator.obfuscate(b)
convertExpr := bytesToUint(bitsize)
block.List = append(block.List, boundsCheckData(byteSize-1), returnStmt(callExpr(ident(typeInfo.Name()), convertExpr)))
block.List = append(block.List, ah.BoundsCheck("data", byteSize-1), ah.ReturnStmt(ah.CallExpr(ah.Ident(typeInfo.Name()), convertExpr)))
return lambdaCall(ident(typeInfo.Name()), block)
return ah.LambdaCall(ah.Ident(typeInfo.Name()), block)
}
func uintToFloat(uintExpr *ast.CallExpr, typeStr string) *ast.CallExpr {
usesUnsafe = true
convert := &ast.StarExpr{
X: callExpr(
X: ah.CallExpr(
&ast.ParenExpr{
X: &ast.StarExpr{X: ident(typeStr)},
X: &ast.StarExpr{X: ah.Ident(typeStr)},
},
callExpr(
ah.CallExpr(
&ast.SelectorExpr{
X: ident("unsafe"),
Sel: ident("Pointer"),
X: ah.Ident("unsafe"),
Sel: ah.Ident("Pointer"),
},
&ast.UnaryExpr{
Op: token.AND,
X: ident("result"),
X: ah.Ident("result"),
},
),
),
@ -193,14 +194,14 @@ func uintToFloat(uintExpr *ast.CallExpr, typeStr string) *ast.CallExpr {
block := &ast.BlockStmt{List: []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{&ast.Ident{Name: "result"}},
Lhs: []ast.Expr{ah.Ident("result")},
Tok: token.DEFINE,
Rhs: []ast.Expr{uintExpr},
},
returnStmt(convert),
ah.ReturnStmt(convert),
}}
return lambdaCall(ident(typeStr), block)
return ah.LambdaCall(ah.Ident(typeStr), block)
}
func genObfuscateFloat(data interface{}) *ast.CallExpr {

@ -4,7 +4,6 @@ import (
cryptrand "crypto/rand"
"fmt"
"go/ast"
"go/token"
mathrand "math/rand"
"os"
"strings"
@ -24,20 +23,6 @@ var (
envGarbleSeed = os.Getenv("GARBLE_SEED")
)
// dataToByteSlice turns a byte slice like []byte{1, 2, 3} into an AST
// expression
func dataToByteSlice(data []byte) *ast.CallExpr {
return &ast.CallExpr{
Fun: &ast.ArrayType{
Elt: &ast.Ident{Name: "byte"},
},
Args: []ast.Expr{&ast.BasicLit{
Kind: token.STRING,
Value: fmt.Sprintf("%q", data),
}},
}
}
// If math/rand.Seed() is not called, the generator behaves as if seeded by rand.Seed(1),
// so the generator is deterministic.

@ -5,6 +5,8 @@ import (
"go/token"
"math"
mathrand "math/rand"
ah "mvdan.cc/garble/internal/asthelper"
)
type swap struct{}
@ -29,12 +31,12 @@ func positionsToSlice(data []int) *ast.CompositeLit {
arr := &ast.CompositeLit{
Type: &ast.ArrayType{
Len: &ast.Ellipsis{}, // Performance optimization
Elt: ident(getIndexType(len(data))),
Elt: ah.Ident(getIndexType(len(data))),
},
Elts: []ast.Expr{},
}
for _, data := range data {
arr.Elts = append(arr.Elts, intLiteral(data))
arr.Elts = append(arr.Elts, ah.IntLit(data))
}
return arr
}
@ -65,83 +67,83 @@ func (x swap) obfuscate(data []byte) *ast.BlockStmt {
data[positions[i]], data[positions[i+1]] = data[positions[i+1]]^localKey, data[positions[i]]^localKey
}
return &ast.BlockStmt{List: []ast.Stmt{
return ah.BlockStmt(
&ast.AssignStmt{
Lhs: []ast.Expr{ident("data")},
Lhs: []ast.Expr{ah.Ident("data")},
Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSlice(data)},
Rhs: []ast.Expr{ah.DataToByteSlice(data)},
},
&ast.AssignStmt{
Lhs: []ast.Expr{ident("positions")},
Lhs: []ast.Expr{ah.Ident("positions")},
Tok: token.DEFINE,
Rhs: []ast.Expr{positionsToSlice(positions)},
},
&ast.ForStmt{
Init: &ast.AssignStmt{
Lhs: []ast.Expr{ident("i")},
Lhs: []ast.Expr{ah.Ident("i")},
Tok: token.DEFINE,
Rhs: []ast.Expr{intLiteral(0)},
Rhs: []ast.Expr{ah.IntLit(0)},
},
Cond: &ast.BinaryExpr{
X: ident("i"),
X: ah.Ident("i"),
Op: token.LSS,
Y: intLiteral(len(positions)),
Y: ah.IntLit(len(positions)),
},
Post: &ast.AssignStmt{
Lhs: []ast.Expr{ident("i")},
Lhs: []ast.Expr{ah.Ident("i")},
Tok: token.ADD_ASSIGN,
Rhs: []ast.Expr{intLiteral(2)},
Rhs: []ast.Expr{ah.IntLit(2)},
},
Body: &ast.BlockStmt{List: []ast.Stmt{
Body: ah.BlockStmt(
&ast.AssignStmt{
Lhs: []ast.Expr{ident("localKey")},
Lhs: []ast.Expr{ah.Ident("localKey")},
Tok: token.DEFINE,
Rhs: []ast.Expr{&ast.BinaryExpr{
X: &ast.BinaryExpr{
X: callExpr(ident("byte"), ident("i")),
X: ah.CallExpr(ah.Ident("byte"), ah.Ident("i")),
Op: token.ADD,
Y: callExpr(ident("byte"), &ast.BinaryExpr{
X: indexExpr("positions", ident("i")),
Y: ah.CallExpr(ah.Ident("byte"), &ast.BinaryExpr{
X: ah.IndexExpr("positions", ah.Ident("i")),
Op: token.XOR,
Y: indexExpr("positions", &ast.BinaryExpr{
X: ident("i"),
Y: ah.IndexExpr("positions", &ast.BinaryExpr{
X: ah.Ident("i"),
Op: token.ADD,
Y: intLiteral(1),
Y: ah.IntLit(1),
}),
}),
},
Op: token.ADD,
Y: intLiteral(int(shiftKey)),
Y: ah.IntLit(int(shiftKey)),
}},
},
&ast.AssignStmt{
Lhs: []ast.Expr{
indexExpr("data", indexExpr("positions", ident("i"))),
indexExpr("data", indexExpr("positions", &ast.BinaryExpr{
X: ident("i"),
ah.IndexExpr("data", ah.IndexExpr("positions", ah.Ident("i"))),
ah.IndexExpr("data", ah.IndexExpr("positions", &ast.BinaryExpr{
X: ah.Ident("i"),
Op: token.ADD,
Y: intLiteral(1),
Y: ah.IntLit(1),
})),
},
Tok: token.ASSIGN,
Rhs: []ast.Expr{
&ast.BinaryExpr{
X: indexExpr("data", indexExpr("positions", &ast.BinaryExpr{
X: ident("i"),
X: ah.IndexExpr("data", ah.IndexExpr("positions", &ast.BinaryExpr{
X: ah.Ident("i"),
Op: token.ADD,
Y: intLiteral(1),
Y: ah.IntLit(1),
})),
Op: token.XOR,
Y: ident("localKey"),
Y: ah.Ident("localKey"),
},
&ast.BinaryExpr{
X: indexExpr("data", indexExpr("positions", ident("i"))),
X: ah.IndexExpr("data", ah.IndexExpr("positions", ah.Ident("i"))),
Op: token.XOR,
Y: ident("localKey"),
Y: ah.Ident("localKey"),
},
},
},
}},
),
},
}}
)
}

@ -3,6 +3,8 @@ package literals
import (
"go/ast"
"go/token"
ah "mvdan.cc/garble/internal/asthelper"
)
type xor struct{}
@ -20,28 +22,28 @@ func (x xor) obfuscate(data []byte) *ast.BlockStmt {
return &ast.BlockStmt{List: []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{ident("key")},
Lhs: []ast.Expr{ah.Ident("key")},
Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSlice(key)},
Rhs: []ast.Expr{ah.DataToByteSlice(key)},
},
&ast.AssignStmt{
Lhs: []ast.Expr{ident("data")},
Lhs: []ast.Expr{ah.Ident("data")},
Tok: token.DEFINE,
Rhs: []ast.Expr{dataToByteSlice(data)},
Rhs: []ast.Expr{ah.DataToByteSlice(data)},
},
&ast.RangeStmt{
Key: ident("i"),
Value: ident("b"),
Key: ah.Ident("i"),
Value: ah.Ident("b"),
Tok: token.DEFINE,
X: ident("key"),
X: ah.Ident("key"),
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{indexExpr("data", ident("i"))},
Lhs: []ast.Expr{ah.IndexExpr("data", ah.Ident("i"))},
Tok: token.ASSIGN,
Rhs: []ast.Expr{&ast.BinaryExpr{
X: indexExpr("data", ident("i")),
X: ah.IndexExpr("data", ah.Ident("i")),
Op: token.XOR,
Y: ident("b"),
Y: ah.Ident("b"),
}},
},
}},

@ -3,6 +3,8 @@ package main
import (
"go/ast"
"go/token"
ah "mvdan.cc/garble/internal/asthelper"
)
// addRuntimeAPI exposes additional functions in the runtime
@ -71,50 +73,45 @@ func addRuntimeAPI(filename string, file *ast.File) {
}
var fatalErrorsHiddenCheckStmt = &ast.IfStmt{
Cond: &ast.Ident{Name: "fatalErrorsHidden"},
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.ReturnStmt{},
}},
Cond: ah.Ident("fatalErrorsHidden"),
Body: ah.BlockStmt(ah.ReturnStmt()),
}
var hideFatalErrorsDecls = []ast.Decl{
&ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{&ast.ValueSpec{
Names: []*ast.Ident{{Name: "fatalErrorsHidden"}},
Type: &ast.Ident{Name: "bool"},
Names: []*ast.Ident{ah.Ident("fatalErrorsHidden")},
Type: ah.Ident("bool"),
}},
},
&ast.FuncDecl{
Name: &ast.Ident{Name: "hideFatalErrors"},
Name: ah.Ident("hideFatalErrors"),
Type: &ast.FuncType{Params: &ast.FieldList{
List: []*ast.Field{{
Names: []*ast.Ident{{Name: "hide"}},
Type: &ast.Ident{Name: "bool"},
Names: []*ast.Ident{ah.Ident("hide")},
Type: ah.Ident("bool"),
}},
}},
Body: &ast.BlockStmt{List: []ast.Stmt{
Body: ah.BlockStmt(
&ast.AssignStmt{
Lhs: []ast.Expr{&ast.Ident{Name: "fatalErrorsHidden"}},
Lhs: []ast.Expr{ah.Ident("fatalErrorsHidden")},
Tok: token.ASSIGN,
Rhs: []ast.Expr{&ast.Ident{Name: "hide"}},
Rhs: []ast.Expr{ah.Ident("hide")},
},
}},
),
},
}
var printanyHexCase = &ast.CaseClause{
List: []ast.Expr{&ast.Ident{Name: "hex"}},
List: []ast.Expr{ah.Ident("hex")},
Body: []ast.Stmt{
&ast.ExprStmt{X: &ast.CallExpr{
Fun: &ast.Ident{Name: "print"},
Args: []ast.Expr{&ast.Ident{Name: "v"}},
}},
ah.ExprStmt(ah.CallExpr(ah.Ident("print"), ah.Ident("v"))),
},
}
var panicprintDecl = &ast.FuncDecl{
Name: &ast.Ident{Name: "panicprint"},
Name: ah.Ident("panicprint"),
Type: &ast.FuncType{Params: &ast.FieldList{
List: []*ast.Field{{
Names: []*ast.Ident{{Name: "args"}},
@ -123,24 +120,19 @@ var panicprintDecl = &ast.FuncDecl{
}},
}},
}},
Body: &ast.BlockStmt{List: []ast.Stmt{
Body: ah.BlockStmt(
&ast.IfStmt{
Cond: &ast.Ident{Name: "fatalErrorsHidden"},
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.ReturnStmt{},
}},
Cond: ah.Ident("fatalErrorsHidden"),
Body: ah.BlockStmt(ah.ReturnStmt()),
},
&ast.RangeStmt{
Key: &ast.Ident{Name: "_"},
Value: &ast.Ident{Name: "arg"},
Key: ah.Ident("_"),
Value: ah.Ident("arg"),
Tok: token.DEFINE,
X: &ast.Ident{Name: "args"},
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.ExprStmt{X: &ast.CallExpr{
Fun: &ast.Ident{Name: "printany"},
Args: []ast.Expr{&ast.Ident{Name: "arg"}},
}},
}},
X: ah.Ident("args"),
Body: ah.BlockStmt(
ah.ExprStmt(ah.CallExpr(ah.Ident("printany"), ah.Ident("arg"))),
),
},
}},
),
}

Loading…
Cancel
Save