diff --git a/internal/literals/obfuscators.go b/internal/literals/obfuscators.go index 84ac68a..5dc03f0 100644 --- a/internal/literals/obfuscators.go +++ b/internal/literals/obfuscators.go @@ -21,6 +21,7 @@ var ( swap{}, split{}, xorShuffle{}, + xorSeed{}, } envGarbleSeed = os.Getenv("GARBLE_SEED") ) diff --git a/internal/literals/xor_seed.go b/internal/literals/xor_seed.go new file mode 100644 index 0000000..8812ccb --- /dev/null +++ b/internal/literals/xor_seed.go @@ -0,0 +1,117 @@ +package literals + +import ( + "go/ast" + "go/token" + + ah "mvdan.cc/garble/internal/asthelper" +) + +type xorSeed struct{} + +// check that the obfuscator interface is implemented +var _ obfuscator = xorSeed{} + +func (x xorSeed) obfuscate(data []byte) *ast.BlockStmt { + preSeed := make([]byte, 1) + genRandBytes(preSeed) + + seed := preSeed[0] + originalSeed := seed + + var callExpr *ast.CallExpr + for i, b := range data { + encB := b ^ seed + seed += encB + + if i == 0 { + callExpr = ah.CallExpr(ah.Ident("fnc"), ah.IntLit(int(encB))) + continue + } + + callExpr = ah.CallExpr(callExpr, ah.IntLit(int(encB))) + } + + return ah.BlockStmt( + &ast.AssignStmt{ + Lhs: []ast.Expr{ah.Ident("seed")}, + Tok: token.DEFINE, + Rhs: []ast.Expr{ah.CallExpr(ah.Ident("byte"), ah.IntLit(int(originalSeed)))}, + }, + &ast.DeclStmt{ + Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{ah.Ident("data")}, + Type: &ast.ArrayType{Elt: ah.Ident("byte")}, + }}, + }, + }, + &ast.DeclStmt{ + Decl: &ast.GenDecl{ + Tok: token.TYPE, + Specs: []ast.Spec{&ast.TypeSpec{ + Name: ah.Ident("decFunc"), + Type: &ast.FuncType{ + Params: &ast.FieldList{List: []*ast.Field{ + {Type: ah.Ident("byte")}, + }}, + Results: &ast.FieldList{List: []*ast.Field{ + {Type: ah.Ident("decFunc")}, + }}, + }, + }}, + }, + }, + &ast.DeclStmt{ + Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{ah.Ident("fnc")}, + Type: ah.Ident("decFunc"), + }}, + }, + }, + &ast.AssignStmt{ + Lhs: []ast.Expr{ah.Ident("fnc")}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.FuncLit{ + Type: &ast.FuncType{ + Params: &ast.FieldList{ + List: []*ast.Field{{ + Names: []*ast.Ident{ah.Ident("x")}, + Type: ah.Ident("byte"), + }}, + }, + Results: &ast.FieldList{ + List: []*ast.Field{{ + Type: ah.Ident("decFunc"), + }}, + }, + }, + Body: ah.BlockStmt( + &ast.AssignStmt{ + Lhs: []ast.Expr{ah.Ident("data")}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + ah.CallExpr(ah.Ident("append"), ah.Ident("data"), &ast.BinaryExpr{ + X: ah.Ident("x"), + Op: token.XOR, + Y: ah.Ident("seed"), + }), + }, + }, + &ast.AssignStmt{ + Lhs: []ast.Expr{ah.Ident("seed")}, + Tok: token.ADD_ASSIGN, + Rhs: []ast.Expr{ah.Ident("x")}, + }, + ah.ReturnStmt(ah.Ident("fnc")), + ), + }, + }, + }, + ah.ExprStmt(callExpr), + ) +} diff --git a/testdata/scripts/literals.txt b/testdata/scripts/literals.txt index c8533c1..5753122 100644 --- a/testdata/scripts/literals.txt +++ b/testdata/scripts/literals.txt @@ -48,6 +48,9 @@ grep '^\s+\w+ \^= \w+ \* \w+$' .obf-src/main/z0.go # XorShuffle obfuscator. Detect data = append(data, x ^ y...) grep '^\s+\w+ = append\(\w+,(\s+\w+\[\d+\]\^\w+\[\d+\],?)+\)$' .obf-src/main/z0.go +# XorSeed obfuscator. Detect type decFunc func(byte) decFunc +grep '^\s+type \w+ func\(byte\) \w+$' .obf-src/main/z0.go + -- go.mod -- module test/main