Fix byte array and untyped constant obfuscation.

Byte arrays were previously,
obfuscated as byte slices.

Untyped constants are now skipped,
because they cannot be replaced with typed variables.
pull/71/head
lu4p 4 years ago committed by Daniel Martí
parent d48bdbadae
commit 705f9d3a28

@ -54,15 +54,20 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli
for _, name := range spec.Names { for _, name := range spec.Names {
obj := info.ObjectOf(name) obj := info.ObjectOf(name)
// The object itself is blacklisted, e.g. a value that needs to be constant basic, ok := obj.Type().(*types.Basic)
if _, ok := blacklist[obj]; ok { if !ok {
// skip the block if it contains non basic types
return false
}
if basic.Info()&types.IsUntyped != 0 {
// skip the block if it contains untyped constants
return false return false
} }
}
for _, val := range spec.Values { // The object itself is blacklisted, e.g. a value that needs to be constant
if _, ok := val.(*ast.BasicLit); !ok { if _, ok := blacklist[obj]; ok {
return false // skip the block if it contains non basic literals return false
} }
} }
} }
@ -79,35 +84,53 @@ func Obfuscate(files []*ast.File, info *types.Info, fset *token.FileSet, blackli
case *ast.CompositeLit: case *ast.CompositeLit:
byteType := types.Universe.Lookup("byte").Type() byteType := types.Universe.Lookup("byte").Type()
switch x := info.TypeOf(x.Type).(type) { switch y := info.TypeOf(x.Type).(type) {
case *types.Array: case *types.Array:
if x.Elem() != byteType { if y.Elem() != byteType {
return true return true
} }
case *types.Slice:
if x.Elem() != byteType { data := make([]byte, y.Len())
return true
for i, el := range x.Elts {
lit, ok := el.(*ast.BasicLit)
if !ok {
return true
}
value, err := strconv.Atoi(lit.Value)
if err != nil {
return true
}
data[i] = byte(value)
} }
default: cursor.Replace(obfuscateByteArray(data, y.Len()))
return true
}
var data []byte case *types.Slice:
for _, el := range x.Elts { if y.Elem() != byteType {
lit, ok := el.(*ast.BasicLit)
if !ok {
return true return true
} }
value, err := strconv.Atoi(lit.Value) var data []byte
if err != nil {
return true for _, el := range x.Elts {
lit, ok := el.(*ast.BasicLit)
if !ok {
return true
}
value, err := strconv.Atoi(lit.Value)
if err != nil {
return true
}
data = append(data, byte(value))
} }
cursor.Replace(obfuscateByteSlice(data))
data = append(data, byte(value))
} }
cursor.Replace(obfuscateBytes(data))
case *ast.BasicLit: case *ast.BasicLit:
switch cursor.Name() { switch cursor.Name() {
case "Values", "Rhs", "Value", "Args", "X", "Y", "Results": case "Values", "Rhs", "Value", "Args", "X", "Y", "Results":
@ -152,7 +175,7 @@ func obfuscateString(data string) *ast.CallExpr {
return callExpr(&ast.Ident{Name: "string"}, block) return callExpr(&ast.Ident{Name: "string"}, block)
} }
func obfuscateBytes(data []byte) *ast.CallExpr { func obfuscateByteSlice(data []byte) *ast.CallExpr {
obfuscator := randObfuscator() obfuscator := randObfuscator()
block := obfuscator.obfuscate(data) block := obfuscator.obfuscate(data)
block.List = append(block.List, &ast.ReturnStmt{ block.List = append(block.List, &ast.ReturnStmt{
@ -161,6 +184,56 @@ func obfuscateBytes(data []byte) *ast.CallExpr {
return callExpr(&ast.ArrayType{Elt: &ast.Ident{Name: "byte"}}, block) return callExpr(&ast.ArrayType{Elt: &ast.Ident{Name: "byte"}}, block)
} }
func obfuscateByteArray(data []byte, length int64) *ast.CallExpr {
obfuscator := randObfuscator()
block := obfuscator.obfuscate(data)
arrayType := &ast.ArrayType{
Len: &ast.BasicLit{
Kind: token.INT,
Value: strconv.Itoa(int(length)),
},
Elt: &ast.Ident{Name: "byte"},
}
sliceToArray := []ast.Stmt{
&ast.DeclStmt{
Decl: &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{&ast.ValueSpec{
Names: []*ast.Ident{{Name: "newdata"}},
Type: arrayType,
}},
},
},
&ast.RangeStmt{
Key: &ast.Ident{Name: "i"},
Tok: token.DEFINE,
X: &ast.Ident{Name: "newdata"},
Body: &ast.BlockStmt{List: []ast.Stmt{
&ast.AssignStmt{
Lhs: []ast.Expr{&ast.IndexExpr{
X: &ast.Ident{Name: "newdata"},
Index: &ast.Ident{Name: "i"},
}},
Tok: token.ASSIGN,
Rhs: []ast.Expr{&ast.IndexExpr{
X: &ast.Ident{Name: "data"},
Index: &ast.Ident{Name: "i"},
}},
},
}},
},
&ast.ReturnStmt{Results: []ast.Expr{
&ast.Ident{Name: "newdata"},
}},
}
block.List = append(block.List, sliceToArray...)
return callExpr(arrayType, block)
}
// ConstBlacklist blacklist identifieres used in constant expressions // ConstBlacklist blacklist identifieres used in constant expressions
func ConstBlacklist(node ast.Node, info *types.Info, blacklist map[types.Object]struct{}) { func ConstBlacklist(node ast.Node, info *types.Info, blacklist map[types.Object]struct{}) {
blacklistObjects := func(node ast.Node) bool { blacklistObjects := func(node ast.Node) bool {

@ -7,7 +7,7 @@ cmp stderr main.stderr
cmp stderr normal.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' 'ipsum' 'dolor' 'first assign' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String' 'stringTypeStruct'
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' 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'
[short] stop # checking that the build is reproducible is slow [short] stop # checking that the build is reproducible is slow
# Also check that the binary is reproducible. # Also check that the binary is reproducible.
@ -28,7 +28,7 @@ type strucTest struct {
const ( const (
cnst string = "Lorem" cnst string = "Lorem"
multiline = `First Line multiline string = `First Line
Second Line` Second Line`
) )
@ -70,7 +70,7 @@ func main() {
field: "to obfuscate", field: "to obfuscate",
anotherfield: "also obfuscate", anotherfield: "also obfuscate",
} }
lambda := func() string { lambda := func() string {
return "😅 😅" return "😅 😅"
}() }()
@ -98,6 +98,9 @@ type stringTypeStruct struct {
// typedTest types defined from string broke previously // typedTest types defined from string broke previously
func typedTest() { func typedTest() {
const skipUntypedConst = "skip untyped const"
stringTypeFunc(skipUntypedConst)
const skipTypedConst stringType = "skip typed const" // skip const skipTypedConst stringType = "skip typed const" // skip
var skipTypedVar stringType = "skip typed var" // skip var skipTypedVar stringType = "skip typed var" // skip
@ -158,6 +161,7 @@ func constantTest() {
const f = "foo" // skip const f = "foo" // skip
const i = length + len(f) const i = length + len(f)
println(length, i)
} }
func byteTest() { func byteTest() {
@ -177,6 +181,14 @@ func byteTest() {
print(elm, ", ") print(elm, ", ")
} }
println() println()
d := func() [4]byte {
return [4]byte{12, 13}
}()
for _, elm := range d {
print(elm, ", ")
}
println()
} }
func stringTypeFunc(s stringType) stringType { func stringTypeFunc(s stringType) stringType {
@ -197,6 +209,7 @@ new value
another literal another literal
also skip this also skip this
1 0 1 1 0 1
skip untyped const
skip typed const skip typed var skip typed var assign skip typed const skip typed var skip typed var assign
stringTypeField String stringTypeField strType stringTypeField String stringTypeField strType
stringType lambda func return stringType lambda func return
@ -204,6 +217,8 @@ stringType func param
stringType return stringType return
foo foo
foo foo
3 6
12, 13, 12, 13,
12, 13, 12, 13,
12, 13, 12, 13,
12, 13, 0, 0,

Loading…
Cancel
Save