From d679944408cc1f752d10cb1efc409d9e77fca04d Mon Sep 17 00:00:00 2001 From: Andrew LeFevre Date: Mon, 7 Sep 2020 11:24:40 -0400 Subject: [PATCH] Strip all filename and position info when -tiny is passed (#128) Co-authored-by: pagran Co-authored-by: lu4p --- import_obfuscation.go | 63 +++++++++++++++++++++++++++++++++++---- line_obfuscator.go | 5 ---- main.go | 4 ++- testdata/scripts/asm.txt | 5 ++++ testdata/scripts/cgo.txt | 5 ++++ testdata/scripts/tiny.txt | 35 ++++++++-------------- 6 files changed, 82 insertions(+), 35 deletions(-) diff --git a/import_obfuscation.go b/import_obfuscation.go index c839cfa..010d19e 100644 --- a/import_obfuscation.go +++ b/import_obfuscation.go @@ -17,8 +17,9 @@ import ( // pkgInfo stores a parsed go archive/object file, // and the original path to which it was read from. type pkgInfo struct { - pkg *goobj2.Package - path string + pkg *goobj2.Package + path string + private bool } // dataType signifies whether the Data portion of a @@ -52,24 +53,26 @@ func obfuscateImports(objPath, importCfgPath string) (map[string]string, error) if err != nil { return nil, fmt.Errorf("error parsing main objfile: %v", err) } - privatePkgs := []pkgInfo{{mainPkg, objPath}} + pkgs := []pkgInfo{{mainPkg, objPath, true}} // build list of imported packages that are private for pkgPath, info := range importCfg { - if isPrivate(pkgPath) { + // if the '-tiny' flag is passed, we will strip filename + // and position info of every package, but not garble anything + if private := isPrivate(pkgPath); envGarbleTiny || private { pkg, err := goobj2.Parse(info.Path, pkgPath, importCfg) if err != nil { return nil, fmt.Errorf("error parsing objfile %s at %s: %v", pkgPath, info.Path, err) } - privatePkgs = append(privatePkgs, pkgInfo{pkg, info.Path}) + pkgs = append(pkgs, pkgInfo{pkg, info.Path, private}) } } var sb strings.Builder var buf bytes.Buffer garbledImports := make(map[string]string) - for _, p := range privatePkgs { + for _, p := range pkgs { // log.Printf("++ Obfuscating object file for %s ++", p.pkg.ImportPath) for _, am := range p.pkg.ArchiveMembers { // log.Printf("\t## Obfuscating archive member %s ##", am.ArchiveHeader.Name) @@ -80,6 +83,13 @@ func obfuscateImports(objPath, importCfgPath string) (map[string]string, error) continue } + // not part of a private package, so just strip filename + // and position info and move on + if !p.private { + stripPCLinesAndNames(&am) + continue + } + // add all private import paths to a list to garble var privImports privateImports privImports.privatePaths, privImports.privateNames = explodeImportPath(p.pkg.ImportPath) @@ -149,6 +159,37 @@ func obfuscateImports(objPath, importCfgPath string) (map[string]string, error) return garbledImports, nil } +// stripPCLinesAndNames removes all filename and position info +// from an archive member. +func stripPCLinesAndNames(am *goobj2.ArchiveMember) { + lists := [][]*goobj2.Sym{am.SymDefs, am.NonPkgSymDefs, am.NonPkgSymRefs} + for _, list := range lists { + for _, s := range list { + if s.Func == nil { + continue + } + + for _, inl := range s.Func.InlTree { + inl.Line = 1 + } + + s.Func.PCFile = nil + s.Func.PCLine = nil + s.Func.PCInline = nil + + // remove unneeded debug aux symbols + s.Func.DwarfInfo = nil + s.Func.DwarfLoc = nil + s.Func.DwarfRanges = nil + s.Func.DwarfDebugLines = nil + + } + } + + // remove dwarf file list, it isn't needed as we pass "-w, -s" to the linker + am.DWARFFileList = nil +} + // explodeImportPath returns lists of import paths // and package names that could all potentially be // in symbol names of the package that imported 'path'. @@ -246,6 +287,7 @@ func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbled for _, s := range list { // skip debug symbols, and remove the debug symbol's data to save space if s.Kind >= goobj2.SDWARFINFO && s.Kind <= goobj2.SDWARFLINES { + s.Size = 0 s.Data = nil continue } @@ -291,6 +333,15 @@ func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbled } for _, inl := range s.Func.InlTree { inl.Func.Name = garbleSymbolName(inl.Func.Name, privImports, garbledImports, sb) + if envGarbleTiny { + inl.Line = 1 + } + } + + if envGarbleTiny { + s.Func.PCFile = nil + s.Func.PCLine = nil + s.Func.PCInline = nil } // remove unneeded debug aux symbols diff --git a/line_obfuscator.go b/line_obfuscator.go index 72ff29e..e5ff89c 100644 --- a/line_obfuscator.go +++ b/line_obfuscator.go @@ -99,11 +99,6 @@ func transformLineInfo(file *ast.File) ([]string, *ast.File) { return true } - if envGarbleTiny { - funcDecl.Doc = prependComment(funcDecl.Doc, &ast.Comment{Text: "//line :1"}) - return true - } - comment := &ast.Comment{Text: fmt.Sprintf("//line %c.go:%d", nameCharset[mathrand.Intn(len(nameCharset))], 1+newLines[funcCounter])} funcDecl.Doc = prependComment(funcDecl.Doc, comment) funcCounter++ diff --git a/main.go b/main.go index f916104..c878c9e 100644 --- a/main.go +++ b/main.go @@ -548,7 +548,9 @@ func transformCompile(args []string) ([]string, error) { // messy. name = "_cgo_" + name default: - extraComments, file = transformLineInfo(file) + if !envGarbleTiny { + extraComments, file = transformLineInfo(file) + } file = transformGo(file, info, blacklist) // Uncomment for some quick debugging. Do not delete. diff --git a/testdata/scripts/asm.txt b/testdata/scripts/asm.txt index a730581..a92a0bf 100644 --- a/testdata/scripts/asm.txt +++ b/testdata/scripts/asm.txt @@ -7,6 +7,11 @@ binsubstr main$exe 'privateAdd' 'PublicAdd' [short] stop # no need to verify this with -short +garble -tiny build +exec ./main +cmp stderr main.stderr +binsubstr main$exe 'privateAdd' 'PublicAdd' + go build exec ./main cmp stderr main.stderr diff --git a/testdata/scripts/cgo.txt b/testdata/scripts/cgo.txt index c53d5ff..f46a1e1 100644 --- a/testdata/scripts/cgo.txt +++ b/testdata/scripts/cgo.txt @@ -7,6 +7,11 @@ binsubstr main$exe 'privateAdd' [short] stop # no need to verify this with -short +garble -tiny build +exec ./main +cmp stderr main.stderr +binsubstr main$exe 'privateAdd' + go build exec ./main cmp stderr main.stderr diff --git a/testdata/scripts/tiny.txt b/testdata/scripts/tiny.txt index 4ff9784..a54a081 100644 --- a/testdata/scripts/tiny.txt +++ b/testdata/scripts/tiny.txt @@ -1,43 +1,32 @@ env GOPRIVATE=test/main -env TINY_PATTERN='^\/\/line :1$' -env DEFAULT_PATTERN='^\/\/line \w\.go:[1-9][0-9]*$' -env DEFAULT_STACK_PATTERN='^\t\w\.go:[1-9][0-9]*(\s\+0x[0-9a-f]+)?' -env TINY_STACK_PATTERN='^\t\?\?:[0-9][0-9]*(\s\+0x[0-9a-f]+)?$' - # Tiny mode -garble -tiny -debugdir=.obf-src build - -grep $TINY_PATTERN .obf-src/main/main.go -! grep $DEFAULT_PATTERN .obf-src/main/main.go - -! exec ./main$exe -! stderr 'main\.go' -! stderr $DEFAULT_STACK_PATTERN -stderr $TINY_STACK_PATTERN +garble -tiny build +exec ./main$exe +stderr '\? 0' [short] stop # no need to verify this with -short # Default mode - garble -debugdir=.obf-src build # Check for file name leak protection -grep $TINY_PATTERN .obf-src/main/main.go +grep '^\/\/line :1$' .obf-src/main/main.go # Check for default line obfuscation -grep $DEFAULT_PATTERN .obf-src/main/main.go +grep '^\/\/line \w\.go:[1-9][0-9]*$' .obf-src/main/main.go +exec ./main$exe -! exec ./main$exe -! stderr 'main\.go' -! stderr $TINY_STACK_PATTERN -stderr $DEFAULT_STACK_PATTERN +stderr '\w\.go [1-9]' -- go.mod -- module test/main -- main.go -- package main +import "runtime" + func main() { - panic("Test") -} + _, file, line, _ := runtime.Caller(0) + println(file, line) +} \ No newline at end of file