You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
9.7 KiB
Plaintext
413 lines
9.7 KiB
Plaintext
2 years ago
|
env GOGARBLE=*
|
||
4 years ago
|
|
||
4 years ago
|
garble -literals build
|
||
|
exec ./main$exe
|
||
4 years ago
|
cmp stderr main.stderr
|
||
4 years ago
|
|
||
3 years ago
|
binsubstr main$exe 'skip typed const' 'skip typed var' 'skip typed var assign' 'stringTypeField strType' 'stringType lambda func return' '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' 'obfuscated with shadowed builtins' '1: literal in' 'an array' '2: literal in' 'a slice' 'to obfuscate' 'also obfuscate' 'stringTypeField String' 'testMap1 key' 'Obfuscate this block' 'also obfuscate this'
|
||
4 years ago
|
|
||
4 years ago
|
[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
|
||
4 years ago
|
garble -literals build
|
||
4 years ago
|
bincmp main$exe main_old$exe
|
||
|
|
||
4 years ago
|
# 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'
|
||
|
|
||
4 years ago
|
# 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
|
||
4 years ago
|
|
||
3 years ago
|
garble -literals -debugdir=debug1 build
|
||
4 years ago
|
exec ./main$exe
|
||
4 years ago
|
cmp stderr main.stderr
|
||
4 years ago
|
|
||
3 years ago
|
# Check obfuscators.
|
||
4 years ago
|
|
||
4 years ago
|
# Xor obfuscator. Detect a[i] = a[i] (^|-|+) b[i]
|
||
3 years ago
|
grep '^\s+\w+\[\w+\] = \w+\[\w+\] [\^\-+] \w+$' debug1/test/main/extra_literals.go
|
||
4 years ago
|
|
||
|
# Swap obfuscator. Detect [...]byte|uint16|uint32|uint64{...}
|
||
3 years ago
|
grep '^\s+\w+ := \[\.{3}\](byte|uint16|uint32|uint64)\{[0-9\s,]+\}$' debug1/test/main/extra_literals.go
|
||
4 years ago
|
|
||
4 years ago
|
# Split obfuscator. Detect decryptKey ^= i * counter
|
||
3 years ago
|
grep '^\s+\w+ \^= \w+ \* \w+$' debug1/test/main/extra_literals.go
|
||
4 years ago
|
|
||
3 years ago
|
# XorShuffle obfuscator. Detect data = append(data, x (^|-|+) y...).
|
||
|
# Note that the line obfuscator adds an inline comment before the call.
|
||
|
grep '^\s+\w+ = .*\bappend\(\w+,(\s+\w+\[\d+\][\^\-+]\w+\[\d+\],?)+\)$' debug1/test/main/extra_literals.go
|
||
4 years ago
|
|
||
2 years ago
|
# TODO: re-enable once https://github.com/golang/go/issues/47631 is fixed
|
||
4 years ago
|
# XorSeed obfuscator. Detect type decFunc func(byte) decFunc
|
||
2 years ago
|
# grep '^\s+type \w+ func\(byte\) \w+$' debug1/test/main/extra_literals.go
|
||
4 years ago
|
|
||
3 years ago
|
# Finally, sanity check that we can build all of std with -literals.
|
||
3 years ago
|
# Analogous to gogarble.txt.
|
||
3 years ago
|
env GOGARBLE='*'
|
||
3 years ago
|
garble -literals build std
|
||
|
|
||
4 years ago
|
-- go.mod --
|
||
|
module test/main
|
||
4 years ago
|
|
||
2 years ago
|
go 1.18
|
||
4 years ago
|
-- main.go --
|
||
|
package main
|
||
|
|
||
2 years ago
|
import (
|
||
|
_ "runtime/debug"
|
||
|
|
||
2 years ago
|
"test/main/imp"
|
||
2 years ago
|
)
|
||
3 years ago
|
|
||
3 years ago
|
type structTest struct {
|
||
4 years ago
|
field string
|
||
3 years ago
|
anotherField string
|
||
4 years ago
|
}
|
||
|
|
||
|
const (
|
||
4 years ago
|
cnst string = "Lorem"
|
||
4 years ago
|
multiline string = `First Line
|
||
4 years ago
|
Second Line`
|
||
|
)
|
||
|
|
||
4 years ago
|
const (
|
||
4 years ago
|
i = 1
|
||
|
boolean = true
|
||
4 years ago
|
|
||
3 years ago
|
mixedBlock = "Obfuscate this block"
|
||
4 years ago
|
)
|
||
|
|
||
|
const (
|
||
|
foo = iota
|
||
|
bar
|
||
|
|
||
3 years ago
|
iotaBlock = "also obfuscate this"
|
||
4 years ago
|
)
|
||
|
|
||
3 years ago
|
// We used to conver this to a var in an attempt of obfuscating the literal.
|
||
|
// That would break the iota, which only works inside const declarations.
|
||
|
// We only obfuscate constant declarations with string values, anyway.
|
||
|
const fooTyped uint64 = 1 << iota
|
||
|
|
||
4 years ago
|
const arrayLen = 4
|
||
|
|
||
|
var array [arrayLen]byte
|
||
|
|
||
|
type typeAlias [arrayLen]byte
|
||
|
|
||
4 years ago
|
func main() {
|
||
|
empty := ""
|
||
|
|
||
|
localVar := "dolor"
|
||
|
|
||
|
reassign := "first assign"
|
||
|
reassign = "second assign"
|
||
|
|
||
4 years ago
|
add := "total" + " string"
|
||
|
|
||
|
println(cnst, boolean)
|
||
|
println(multiline, add)
|
||
4 years ago
|
println(localVar)
|
||
|
println(reassign)
|
||
|
println(empty)
|
||
4 years ago
|
|
||
3 years ago
|
x := structTest{
|
||
4 years ago
|
field: "to obfuscate",
|
||
3 years ago
|
anotherField: "also obfuscate",
|
||
4 years ago
|
}
|
||
4 years ago
|
|
||
4 years ago
|
lambda := func() string {
|
||
|
return "😅 😅"
|
||
|
}()
|
||
|
println(lambda)
|
||
4 years ago
|
|
||
3 years ago
|
println(x.field, x.anotherField)
|
||
4 years ago
|
|
||
|
testMap := map[string]string{"map key": "map value"}
|
||
4 years ago
|
testMap["map key"] = "new value"
|
||
4 years ago
|
println(testMap["map key"])
|
||
|
println("another literal")
|
||
3 years ago
|
println(mixedBlock, iotaBlock)
|
||
4 years ago
|
println(i, foo, bar)
|
||
4 years ago
|
typedTest()
|
||
4 years ago
|
constantTest()
|
||
4 years ago
|
byteTest()
|
||
3 years ago
|
shadowTest()
|
||
3 years ago
|
|
||
|
strArray := [2]string{"1: literal in", "an array"}
|
||
|
println(strArray[0], strArray[1])
|
||
|
strSlice := []string{"2: literal in", "a slice"}
|
||
|
println(strSlice[0], strSlice[1])
|
||
|
emptyStrSlice := []string{""}
|
||
|
print(emptyStrSlice[0])
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
type stringType string
|
||
4 years ago
|
|
||
4 years ago
|
type stringTypeStruct struct {
|
||
|
str string
|
||
|
strType stringType
|
||
|
}
|
||
|
|
||
|
// typedTest types defined from string broke previously
|
||
|
func typedTest() {
|
||
4 years ago
|
const skipUntypedConst = "skip untyped const"
|
||
|
stringTypeFunc(skipUntypedConst)
|
||
|
|
||
4 years ago
|
const skipTypedConst stringType = "skip typed const" // skip
|
||
|
var skipTypedVar stringType = "skip typed var" // skip
|
||
4 years ago
|
|
||
4 years ago
|
var skipTypedVarAssign stringType
|
||
|
skipTypedVarAssign = "skip typed var assign" // skip
|
||
|
|
||
|
println(skipTypedConst, skipTypedVar, skipTypedVarAssign)
|
||
|
|
||
|
y := stringTypeStruct{
|
||
4 years ago
|
str: "stringTypeField String", // obfuscate
|
||
4 years ago
|
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
|
||
|
|
||
4 years ago
|
testMap2 := map[stringType]string{"testMap2 key": "testMap2 value"} // skip key
|
||
|
testMap2["testMap2 key"] = "testMap2 new value" // skip key
|
||
4 years ago
|
|
||
|
testMap3 := map[stringType]stringType{"testMap3 key": "testMap3 value"} // skip
|
||
|
testMap3["testMap3 key"] = "testMap3 new value" // skip
|
||
|
|
||
|
println(stringTypeFunc("stringType func param")) // skip
|
||
|
}
|
||
|
|
||
4 years ago
|
// 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)
|
||
4 years ago
|
println(length, i)
|
||
3 years ago
|
|
||
|
// We should still obfuscate ImportedType here.
|
||
|
// Otherwise, the build will fail,
|
||
|
// as the name was obfuscated in the original package.
|
||
|
const impType = imported.ImportedType(3)
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// TODO: This only tests that we don't break byte slices.
|
||
|
// It was manually verified that they do get obfuscated,
|
||
|
// The original bytes don't seem to show up in the binary,
|
||
|
// meaning that we can't test for them via binsubstr.
|
||
|
// We should figure out a way to test for the byte sequences.
|
||
|
// For now, we manually tested these when they got added.
|
||
4 years ago
|
func byteTest() {
|
||
|
a := []byte{12, 13}
|
||
|
for _, elm := range a {
|
||
4 years ago
|
print(elm, ",")
|
||
4 years ago
|
}
|
||
|
println()
|
||
|
var b = []byte{12, 13}
|
||
|
for _, elm := range b {
|
||
4 years ago
|
print(elm, ",")
|
||
4 years ago
|
}
|
||
|
println()
|
||
|
|
||
|
var c = [2]byte{12, 13}
|
||
|
for _, elm := range c {
|
||
4 years ago
|
print(elm, ",")
|
||
4 years ago
|
}
|
||
|
println()
|
||
4 years ago
|
|
||
|
d := func() [4]byte {
|
||
|
return [4]byte{12, 13}
|
||
|
}()
|
||
|
for _, elm := range d {
|
||
4 years ago
|
print(elm, ",")
|
||
4 years ago
|
}
|
||
|
println()
|
||
3 years ago
|
|
||
|
e := []byte{0x43, 11_1, 0b01101101, 'p', 'l', 'e', 'x'}
|
||
|
println(string(e))
|
||
2 years ago
|
|
||
|
// Testing for issue #520.
|
||
|
func(s []byte) {
|
||
|
print(string(s))
|
||
|
}([]byte("chungus"))
|
||
|
println()
|
||
|
|
||
|
func(s *[]byte) {
|
||
|
print(string(*s))
|
||
|
}(&[]byte{99, 104, 117, 110, 103, 117, 115})
|
||
|
println()
|
||
|
|
||
|
func(s [7]byte) {
|
||
|
for _, elm := range s {
|
||
|
print(elm, ",")
|
||
|
}
|
||
|
}([7]byte{99, 104, 117, 110, 103, 117, 115})
|
||
|
println()
|
||
|
|
||
|
func(s *[7]byte) {
|
||
|
for _, elm := range s {
|
||
|
print(elm, ",")
|
||
|
}
|
||
|
}(&[7]byte{99, 104, 117, 110, 103, 117, 115})
|
||
|
println()
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
func stringTypeFunc(s stringType) stringType {
|
||
|
println(s)
|
||
|
return "stringType return" // skip
|
||
|
}
|
||
3 years ago
|
|
||
|
// obfuscating this broke before
|
||
|
const (
|
||
|
iota0 uint8 = iota
|
||
|
iota1
|
||
|
)
|
||
3 years ago
|
|
||
|
// Our inserted code used to break due to the shadowed builtins.
|
||
|
// The name "fnc" is used as a func var name in garble's inserted code.
|
||
|
func shadowTest() {
|
||
|
{
|
||
|
var append, bool, string, fnc int
|
||
|
_, _, _, _ = append, bool, string, fnc
|
||
|
|
||
|
println("obfuscated with shadowed builtins (vars)")
|
||
|
}
|
||
|
{
|
||
|
type append int
|
||
|
type bool int
|
||
|
type string int
|
||
|
type fnc int
|
||
|
|
||
|
println("obfuscated with shadowed builtins (types)")
|
||
|
}
|
||
|
}
|
||
2 years ago
|
-- imp/imported.go --
|
||
3 years ago
|
package imported
|
||
|
|
||
|
type ImportedType int
|
||
3 years ago
|
-- directives.go --
|
||
|
// If we misplace any of the directives below,
|
||
|
// cmd/compile will complain with "misplaced compiler directive".
|
||
|
//
|
||
|
// We use many literals and functions, mixing different types,
|
||
|
// so that it's more likely that bugs will be caught.
|
||
|
package main
|
||
|
|
||
|
//go:noinline
|
||
|
func str0() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str1() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str2() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str3() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str4() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func arr0() { println(len([...]byte{0, 1, 2})) }
|
||
|
|
||
|
//go:noinline
|
||
|
func arr1() { println(len([...]byte{0, 1, 2})) }
|
||
|
|
||
|
//go:noinline
|
||
|
func slc0() { println([]byte{0, 1, 2}) }
|
||
|
|
||
|
//go:noinline
|
||
|
func slc1() { println([]byte{0, 1, 2}) }
|
||
|
|
||
|
//go:noinline
|
||
|
func str5() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str6() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str7() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str8() { println("foo") }
|
||
|
|
||
|
//go:noinline
|
||
|
func str9() { println("foo") }
|
||
3 years ago
|
|
||
4 years ago
|
-- main.stderr --
|
||
|
Lorem true
|
||
|
First Line
|
||
|
Second Line total string
|
||
|
dolor
|
||
|
second assign
|
||
|
|
||
|
😅 😅
|
||
|
to obfuscate also obfuscate
|
||
|
new value
|
||
|
another literal
|
||
3 years ago
|
Obfuscate this block also obfuscate this
|
||
4 years ago
|
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,
|
||
3 years ago
|
Complex
|
||
2 years ago
|
chungus
|
||
|
chungus
|
||
|
99,104,117,110,103,117,115,
|
||
|
99,104,117,110,103,117,115,
|
||
3 years ago
|
obfuscated with shadowed builtins (vars)
|
||
|
obfuscated with shadowed builtins (types)
|
||
3 years ago
|
1: literal in an array
|
||
|
2: literal in a slice
|