Update filename and add line number obfuscation (#94)
Fixes #2. Line numbers are now obfuscated, via `//line` comments. Filenames are now obfuscated via `//line` comments, instead of changing the actual filename. New flag `-tiny` to reduce the binary size, at the cost of reversibility.pull/99/head
parent
7df14ad860
commit
2735555ab2
@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
mathrand "math/rand"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// PosMax is the largest line or column value that can be represented without loss.
|
||||
// Source: https://go.googlesource.com/go/+/refs/heads/master/src/cmd/compile/internal/syntax/pos.go#11
|
||||
PosMax = 1 << 30
|
||||
|
||||
// PosMin is the smallest correct value for the line number.
|
||||
// Source: https://go.googlesource.com/go/+/refs/heads/master/src/cmd/compile/internal/syntax/parser_test.go#229
|
||||
PosMin = 1
|
||||
)
|
||||
|
||||
func prependComment(group *ast.CommentGroup, comment *ast.Comment) *ast.CommentGroup {
|
||||
if group == nil {
|
||||
return &ast.CommentGroup{List: []*ast.Comment{comment}}
|
||||
}
|
||||
|
||||
group.List = append([]*ast.Comment{comment}, group.List...)
|
||||
return group
|
||||
}
|
||||
|
||||
// Remove all comments from CommentGroup except //go: directives.
|
||||
func clearCommentGroup(group *ast.CommentGroup) *ast.CommentGroup {
|
||||
if group == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var comments []*ast.Comment
|
||||
|
||||
for _, comment := range group.List {
|
||||
if strings.HasPrefix(comment.Text, "//go:") {
|
||||
comments = append(comments, &ast.Comment{Text: comment.Text})
|
||||
}
|
||||
}
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &ast.CommentGroup{List: comments}
|
||||
}
|
||||
|
||||
// Remove all comments from Doc (if any) except //go: directives.
|
||||
func clearNodeComments(node ast.Node) {
|
||||
switch n := node.(type) {
|
||||
case *ast.Field:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.ImportSpec:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.ValueSpec:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.TypeSpec:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.GenDecl:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.FuncDecl:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
case *ast.File:
|
||||
n.Doc = clearCommentGroup(n.Doc)
|
||||
}
|
||||
}
|
||||
|
||||
func findBuildTags(commentGroups []*ast.CommentGroup) (buildTags []string) {
|
||||
for _, group := range commentGroups {
|
||||
for _, comment := range group.List {
|
||||
if !strings.Contains(comment.Text, "+build") {
|
||||
continue
|
||||
}
|
||||
buildTags = append(buildTags, comment.Text)
|
||||
}
|
||||
}
|
||||
return buildTags
|
||||
}
|
||||
|
||||
func transformLineInfo(fileIndex int, file *ast.File) ([]string, *ast.File) {
|
||||
// Save build tags and add file name leak protection
|
||||
extraComments := append(findBuildTags(file.Comments), "", "//line :1")
|
||||
|
||||
file.Comments = nil
|
||||
pre := func(cursor *astutil.Cursor) bool {
|
||||
node := cursor.Node()
|
||||
clearNodeComments(node)
|
||||
|
||||
funcDecl, ok := node.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
if envGarbleTiny {
|
||||
funcDecl.Doc = prependComment(funcDecl.Doc, &ast.Comment{Text: "//line :1"})
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Optimize the generated values of line numbers to reduce space usage.
|
||||
linePos := hashWithAsUint64(buildInfo.buildID, fmt.Sprintf("%d:%s", fileIndex, funcDecl.Name), PosMin, PosMax)
|
||||
comment := &ast.Comment{Text: fmt.Sprintf("//line %c.go:%d", nameCharset[mathrand.Intn(len(nameCharset))], linePos)}
|
||||
funcDecl.Doc = prependComment(funcDecl.Doc, comment)
|
||||
return true
|
||||
}
|
||||
|
||||
return extraComments, astutil.Apply(file, pre, nil).(*ast.File)
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
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
|
||||
|
||||
[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
|
||||
|
||||
# Check for default line obfuscation
|
||||
grep $DEFAULT_PATTERN .obf-src/main/main.go
|
||||
|
||||
! exec ./main$exe
|
||||
! stderr 'main\.go'
|
||||
! stderr $TINY_STACK_PATTERN
|
||||
stderr $DEFAULT_STACK_PATTERN
|
||||
|
||||
-- go.mod --
|
||||
module main
|
||||
-- main.go --
|
||||
package main
|
||||
|
||||
func main() {
|
||||
panic("Test")
|
||||
}
|
Loading…
Reference in New Issue