mirror of
https://github.com/burrowers/garble.git
synced 2025-12-24 12:58:05 +08:00
Now that we've dropped support for Go 1.15.x, we can finally rely on this environment variable for toolexec calls, present in Go 1.16. Before, we had hacky ways of trying to figure out the current package's import path, mostly from the -p flag. The biggest rough edge there was that, for main packages, that was simply the package name, and not its full import path. To work around that, we had a restriction on a single main package, so we could work around that issue. That restriction is now gone. The new code is simpler, especially because we can set curPkg in a single place for all toolexec transform funcs. Since we can always rely on curPkg not being nil now, we can also start reusing listedPackage.Private and avoid the majority of repeated calls to isPrivate. The function is cheap, but still not free. isPrivate itself can also get simpler. We no longer have to worry about the "main" edge case. Plus, the sanity check for invalid package paths is now unnecessary; we only got malformed paths from goobj2, and we now require exact matches with the ImportPath field from "go list -json". Another effect of clearing up the "main" edge case is that -debugdir now uses the right directory for main packages. We also start using consistent debugdir paths in the tests, for the sake of being easier to read and maintain. Finally, note that commandReverse did not need the extra call to "go list -toolexec", as the "shared" call stored in the cache is enough. We still call toolexecCmd to get said cache, which should probably be simplified in a future PR. While at it, replace the use of the "-std" compiler flag with the Standard field from "go list -json".
271 lines
6.2 KiB
Plaintext
271 lines
6.2 KiB
Plaintext
env GOPRIVATE=test/main
|
|
|
|
garble -literals build
|
|
exec ./main$exe
|
|
cmp stderr main.stderr
|
|
|
|
binsubstr main$exe 'Skip this block' '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'
|
|
! binsubstr main$exe 'garbleDecrypt' 'Lorem' 'dolor' 'first assign' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String'
|
|
|
|
[short] stop # checking that the build is reproducible is slow
|
|
|
|
# Also check that the binary is reproducible.
|
|
cp main$exe main_old$exe
|
|
rm main$exe
|
|
garble -literals build
|
|
bincmp main$exe main_old$exe
|
|
|
|
# Check that the program works as expected without garble.
|
|
go build
|
|
exec ./main$exe
|
|
cmp stderr main.stderr
|
|
binsubstr main$exe 'Lorem' 'dolor' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String'
|
|
|
|
# Generate and write random literals into a separate file.
|
|
# Some of them will be huge; assuming that we don't try to obfuscate them, the
|
|
# test should generally run in under a second. If this test hangs for over ten
|
|
# seconds, it means we're trying to obfuscate them.
|
|
generate-literals extra_literals.go
|
|
|
|
# Also check that the binary is different from previous builds.
|
|
rm main$exe
|
|
garble -literals -debugdir=debug1 -seed=8J+Ri/Cfh6fwn4e+ build
|
|
! bincmp main$exe main_old$exe
|
|
|
|
exec ./main$exe
|
|
cmp stderr main.stderr
|
|
|
|
# Check obfuscators
|
|
|
|
# Xor obfuscator. Detect a[i] = a[i] (^|-|+) b[i]
|
|
grep '^\s+\w+\[\w+\] = \w+\[\w+\] [\^\-+] \w+$' debug1/test/main/extra_literals.go
|
|
|
|
# Swap obfuscator. Detect [...]byte|uint16|uint32|uint64{...}
|
|
grep '^\s+\w+ := \[\.{3}\](byte|uint16|uint32|uint64)\{[0-9\s,]+\}$' debug1/test/main/extra_literals.go
|
|
|
|
# Split obfuscator. Detect decryptKey ^= i * counter
|
|
grep '^\s+\w+ \^= \w+ \* \w+$' debug1/test/main/extra_literals.go
|
|
|
|
# XorShuffle obfuscator. Detect data = append(data, x (^|-|+) y...)
|
|
grep '^\s+\w+ = append\(\w+,(\s+\w+\[\d+\][\^\-+]\w+\[\d+\],?)+\)$' debug1/test/main/extra_literals.go
|
|
|
|
# XorSeed obfuscator. Detect type decFunc func(byte) decFunc
|
|
grep '^\s+type \w+ func\(byte\) \w+$' debug1/test/main/extra_literals.go
|
|
|
|
-- go.mod --
|
|
module test/main
|
|
|
|
go 1.16
|
|
-- main.go --
|
|
package main
|
|
|
|
type strucTest struct {
|
|
field string
|
|
anotherfield string
|
|
}
|
|
|
|
const (
|
|
cnst string = "Lorem"
|
|
multiline string = `First Line
|
|
Second Line`
|
|
)
|
|
|
|
const (
|
|
i = 1
|
|
boolean = true
|
|
|
|
skip1 = "Skip this block"
|
|
)
|
|
|
|
const (
|
|
foo = iota
|
|
bar
|
|
|
|
skip2 = "also skip this"
|
|
)
|
|
|
|
const arrayLen = 4
|
|
|
|
var array [arrayLen]byte
|
|
|
|
type typeAlias [arrayLen]byte
|
|
|
|
func main() {
|
|
empty := ""
|
|
|
|
localVar := "dolor"
|
|
|
|
reassign := "first assign"
|
|
reassign = "second assign"
|
|
|
|
add := "total" + " string"
|
|
|
|
println(cnst, boolean)
|
|
println(multiline, add)
|
|
println(localVar)
|
|
println(reassign)
|
|
println(empty)
|
|
|
|
x := strucTest{
|
|
field: "to obfuscate",
|
|
anotherfield: "also obfuscate",
|
|
}
|
|
|
|
lambda := func() string {
|
|
return "😅 😅"
|
|
}()
|
|
println(lambda)
|
|
|
|
println(x.field, x.anotherfield)
|
|
|
|
testMap := map[string]string{"map key": "map value"}
|
|
testMap["map key"] = "new value"
|
|
println(testMap["map key"])
|
|
println("another literal")
|
|
println(skip1, skip2)
|
|
println(i, foo, bar)
|
|
typedTest()
|
|
constantTest()
|
|
byteTest()
|
|
}
|
|
|
|
type stringType string
|
|
|
|
type stringTypeStruct struct {
|
|
str string
|
|
strType stringType
|
|
}
|
|
|
|
// typedTest types defined from string broke previously
|
|
func typedTest() {
|
|
const skipUntypedConst = "skip untyped const"
|
|
stringTypeFunc(skipUntypedConst)
|
|
|
|
const skipTypedConst stringType = "skip typed const" // skip
|
|
var skipTypedVar stringType = "skip typed var" // skip
|
|
|
|
var skipTypedVarAssign stringType
|
|
skipTypedVarAssign = "skip typed var assign" // skip
|
|
|
|
println(skipTypedConst, skipTypedVar, skipTypedVarAssign)
|
|
|
|
y := stringTypeStruct{
|
|
str: "stringTypeField String", // obfuscate
|
|
strType: "stringTypeField strType", // skip
|
|
}
|
|
println(y.str, y.strType)
|
|
|
|
z := func(s stringType) stringType {
|
|
return "stringType lambda func return" // skip
|
|
}("lambda call") // skip
|
|
println(z)
|
|
|
|
testMap1 := map[string]stringType{"testMap1 key": "testMap1 value"} // skip
|
|
testMap1["testMap1 key"] = "testMap1 new value" // skip
|
|
|
|
testMap2 := map[stringType]string{"testMap2 key": "testMap2 value"} // skip key
|
|
testMap2["testMap2 key"] = "testMap2 new value" // skip key
|
|
|
|
testMap3 := map[stringType]stringType{"testMap3 key": "testMap3 value"} // skip
|
|
testMap3["testMap3 key"] = "testMap3 new value" // skip
|
|
|
|
println(stringTypeFunc("stringType func param")) // skip
|
|
}
|
|
|
|
// constantTest tests that string constants which need to be constant are skipped
|
|
func constantTest() {
|
|
const a = "foo" // skip
|
|
const length = len(a)
|
|
|
|
const b = "bar" // skip
|
|
type T [len(b)]byte
|
|
|
|
const c = "foo" // skip
|
|
var _ [len(c)]byte
|
|
|
|
const d = "foo" // skip
|
|
var arr = [5]string{len(d): "foo"}
|
|
for _, elm := range arr {
|
|
if elm != "" {
|
|
println(elm)
|
|
}
|
|
}
|
|
|
|
const e = "foo" // skip
|
|
var slice = []string{len(e): "foo"}
|
|
for _, elm := range slice {
|
|
if elm != "" {
|
|
println(elm)
|
|
}
|
|
}
|
|
|
|
const f = "foo" // skip
|
|
const i = length + len(f)
|
|
println(length, i)
|
|
}
|
|
|
|
func byteTest() {
|
|
a := []byte{12, 13}
|
|
for _, elm := range a {
|
|
print(elm, ",")
|
|
}
|
|
println()
|
|
var b = []byte{12, 13}
|
|
for _, elm := range b {
|
|
print(elm, ",")
|
|
}
|
|
println()
|
|
|
|
var c = [2]byte{12, 13}
|
|
for _, elm := range c {
|
|
print(elm, ",")
|
|
}
|
|
println()
|
|
|
|
d := func() [4]byte {
|
|
return [4]byte{12, 13}
|
|
}()
|
|
for _, elm := range d {
|
|
print(elm, ",")
|
|
}
|
|
println()
|
|
}
|
|
|
|
func stringTypeFunc(s stringType) stringType {
|
|
println(s)
|
|
return "stringType return" // skip
|
|
}
|
|
|
|
// obfuscating this broke before
|
|
const (
|
|
iota0 uint8 = iota
|
|
iota1
|
|
)
|
|
|
|
-- main.stderr --
|
|
Lorem true
|
|
First Line
|
|
Second Line total string
|
|
dolor
|
|
second assign
|
|
|
|
😅 😅
|
|
to obfuscate also obfuscate
|
|
new value
|
|
another literal
|
|
Skip this block also skip this
|
|
1 0 1
|
|
skip untyped const
|
|
skip typed const skip typed var skip typed var assign
|
|
stringTypeField String stringTypeField strType
|
|
stringType lambda func return
|
|
stringType func param
|
|
stringType return
|
|
foo
|
|
foo
|
|
3 6
|
|
12,13,
|
|
12,13,
|
|
12,13,
|
|
12,13,0,0,
|