Files
garble/internal/ctrlflow/trash_test.go
pagran e8fe80d627 add trash block generator (#825)
add trash block generator

For making static code analysis even more difficult, added feature for
generating trash blocks that will never be executed. In combination
with control flow flattening makes it hard to separate trash code from
the real one, plus it causes a large number of trash references to
different methods.

Trash blocks contain 2 types of statements:
1. Function/method call with writing the results into local variables
and passing them to other calls
2. Shuffling or assigning random values to local variables
2024-01-16 16:01:53 +01:00

102 lines
2.4 KiB
Go

package ctrlflow
import (
"fmt"
"go/ast"
"go/importer"
"go/printer"
"go/token"
"go/types"
mathrand "math/rand"
"os"
"strconv"
"testing"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
ah "mvdan.cc/garble/internal/asthelper"
)
// Test_generateTrashBlock tests correctness of generated trash code by generating and compiling a large number of statements
func Test_generateTrashBlock(t *testing.T) {
const (
seed = 7777
stmtCount = 1024
)
fset := token.NewFileSet()
buildPkg := func(f *ast.File) *ssa.Package {
ssaPkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset, types.NewPackage("test/main", ""), []*ast.File{f}, 0)
if err != nil {
t.Fatal(err)
}
return ssaPkg
}
body := &ast.BlockStmt{}
file := &ast.File{
Name: ast.NewIdent("main"),
Decls: []ast.Decl{
&ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
&ast.ImportSpec{
Name: ast.NewIdent("_"),
Path: ah.StringLit("os"),
},
&ast.ImportSpec{
Name: ast.NewIdent("_"),
Path: ah.StringLit("math"),
},
&ast.ImportSpec{
Name: ast.NewIdent("_"),
Path: ah.StringLit("fmt"),
},
},
},
&ast.FuncDecl{
Name: ast.NewIdent("main"),
Type: &ast.FuncType{Params: &ast.FieldList{}},
Body: body,
},
},
}
beforeSsaPkg := buildPkg(file)
imports := make(map[string]string)
gen := newTrashGenerator(beforeSsaPkg.Prog, func(pkg *types.Package) *ast.Ident {
if pkg == nil || pkg.Path() == beforeSsaPkg.Pkg.Path() {
return nil
}
name, ok := imports[pkg.Path()]
if !ok {
name = importPrefix + strconv.Itoa(len(imports))
imports[pkg.Path()] = name
astutil.AddNamedImport(fset, file, name, pkg.Path())
}
return ast.NewIdent(name)
}, mathrand.New(mathrand.NewSource(seed)))
predefinedArgs := make(map[string]types.Type)
for i := types.Bool; i < types.UnsafePointer; i++ {
name, typ := fmt.Sprintf("v%d", i), types.Typ[i]
predefinedArgs[name] = typ
body.List = append(body.List,
&ast.DeclStmt{Decl: &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{&ast.ValueSpec{
Names: []*ast.Ident{ast.NewIdent(name)},
Type: ast.NewIdent(typ.Name()),
}},
}},
ah.AssignStmt(ast.NewIdent("_"), ast.NewIdent(name)),
)
}
body.List = append(body.List, gen.Generate(stmtCount, predefinedArgs)...)
printer.Fprint(os.Stdout, fset, file)
buildPkg(file)
}