From ea19e39aa49cbd170768505d7b0b0b17132862f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Mon, 15 Mar 2021 16:07:01 +0100 Subject: [PATCH] use hashWith for obfuscation position information Position information was obfuscated with math/rand manually, which meant that the resulting positions were pretty small like "x.go:34", but they were also very hard to reverse due to their short length and difficulty to reproduce. We now hash them with hashWith and the package's GarbleActionID: "main.go:203" hashed with 933ad1c700755b7c3a9913c55cade1 to "mwu1xuNz.go" The input to the hash is the base filename and the byte offset of the declaration within the file, meaning that it's unique within a package. The output filename is long enough to allow easy reversal. The line number is always 1, since the information needed for reversing is contained entirely within the filename. It doesn't really matter if we encode data in the filename or line number, but it's easier for us to use a string. For #5. --- line_obfuscator.go | 20 +++++------ main.go | 1 + testdata/scripts/position.txt | 68 +++++++++++++++++------------------ testdata/scripts/tiny.txt | 2 +- 4 files changed, 44 insertions(+), 47 deletions(-) diff --git a/line_obfuscator.go b/line_obfuscator.go index 592ff68..027a9cf 100644 --- a/line_obfuscator.go +++ b/line_obfuscator.go @@ -6,7 +6,6 @@ package main import ( "fmt" "go/ast" - mathrand "math/rand" "strings" ) @@ -92,9 +91,9 @@ func clearNodeComments(node ast.Node) { // transformLineInfo removes the comment except go directives and build tags. Converts comments to the node view. // It returns comments not attached to declarations and names of declarations which cannot be renamed. -func (tf *transformer) transformLineInfo(file *ast.File, name string) (detachedComments []string, f *ast.File) { +func (tf *transformer) transformLineInfo(file *ast.File, filename string) (detachedComments []string, f *ast.File) { prefix := "" - if strings.HasPrefix(name, "_cgo_") { + if strings.HasPrefix(filename, "_cgo_") { prefix = "_cgo_" } @@ -114,9 +113,7 @@ func (tf *transformer) transformLineInfo(file *ast.File, name string) (detachedC return true }) - newLines := mathrand.Perm(len(file.Decls)) - - for i, decl := range file.Decls { + for _, decl := range file.Decls { var doc **ast.CommentGroup switch decl := decl.(type) { case *ast.FuncDecl: @@ -124,14 +121,13 @@ func (tf *transformer) transformLineInfo(file *ast.File, name string) (detachedC case *ast.GenDecl: doc = &decl.Doc } - newPos := prefix + ":1" + newName := "" if !opts.Tiny { - newPos = fmt.Sprintf("%s%c.go:%d", - prefix, - nameCharset[mathrand.Intn(len(nameCharset))], - PosMin+newLines[i], - ) + origPos := fmt.Sprintf("%s:%d", filename, fset.Position(decl.Pos()).Offset) + newName = hashWith(curPkg.GarbleActionID, origPos) + ".go" + // log.Printf("%q hashed with %x to %q", origPos, curPkg.GarbleActionID, newName) } + newPos := fmt.Sprintf("%s%s:1", prefix, newName) comment := &ast.Comment{Text: "//line " + newPos} *doc = prependComment(*doc, comment) diff --git a/main.go b/main.go index de31567..69e3fec 100644 --- a/main.go +++ b/main.go @@ -548,6 +548,7 @@ func transformCompile(args []string) ([]string, error) { files = append(files, file) } + // Literal obfuscation uses math/rand, so seed it deterministically. randSeed := opts.Seed if len(randSeed) == 0 { randSeed = curPkg.GarbleActionID diff --git a/testdata/scripts/position.txt b/testdata/scripts/position.txt index 186c26e..38d68f9 100644 --- a/testdata/scripts/position.txt +++ b/testdata/scripts/position.txt @@ -11,8 +11,8 @@ exec ./main stdout 'main.go' stdout 'other_file_name' stdout ':19: main' -stdout 'initLines is sorted' -stdout 'varLines is sorted' +stdout 'initPositions is sorted' +stdout 'varPositions is sorted' -- go.mod -- module test/main @@ -43,17 +43,17 @@ func main() { funcDecl() funcVar() - // initLines is filled by ten consecutive funcs. + // initPositions is filled by ten consecutive funcs. // If we are not shuffling or obfuscating line numbers, // this list will be sorted. // If we are, it's extremely unlikely it would remain sorted. - if sort.IsSorted(sort.IntSlice(initLines)) { - fmt.Println("initLines is sorted") + if sort.IsSorted(sort.StringSlice(initPositions)) { + fmt.Println("initPositions is sorted") } // Same as the above, but with vars. - if sort.IsSorted(sort.IntSlice(varLines)) { - fmt.Println("varLines is sorted") + if sort.IsSorted(sort.StringSlice(varPositions)) { + fmt.Println("varPositions is sorted") } } -- other_file_name.go -- @@ -74,36 +74,36 @@ var funcVar = func() { fmt.Printf("%s:%d: func var\n", file, line) } -var initLines []int +var initPositions []string -func curLine() int { - _, _, line, _ := runtime.Caller(1) - return line +func curPos() string { + _, file, line, _ := runtime.Caller(1) + return fmt.Sprintf("%s:%d", file, line) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } -func init() { initLines = append(initLines, curLine()) } - -var varLine0 = curLine() -var varLine1 = curLine() -var varLine2 = curLine() -var varLine3 = curLine() -var varLine4 = curLine() -var varLine5 = curLine() -var varLine6 = curLine() -var varLine7 = curLine() -var varLine8 = curLine() -var varLine9 = curLine() - -var varLines = []int{ +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } +func init() { initPositions = append(initPositions, curPos()) } + +var varLine0 = curPos() +var varLine1 = curPos() +var varLine2 = curPos() +var varLine3 = curPos() +var varLine4 = curPos() +var varLine5 = curPos() +var varLine6 = curPos() +var varLine7 = curPos() +var varLine8 = curPos() +var varLine9 = curPos() + +var varPositions = []string{ varLine0, varLine1, varLine2, varLine3, varLine4, varLine5, varLine6, varLine7, varLine8, varLine9, } diff --git a/testdata/scripts/tiny.txt b/testdata/scripts/tiny.txt index 5397371..ede34ea 100644 --- a/testdata/scripts/tiny.txt +++ b/testdata/scripts/tiny.txt @@ -20,7 +20,7 @@ stderr '^recovered: ya like jazz?' env GODEBUG= garble build ! exec ./main$exe -stderr '^caller: \w\.go [1-9]' +stderr '^caller: [0-9a-zA-Z_]+\.go [1-9]' stderr '^recovered: ya like jazz?' stderr 'panic: oh noes'