env GOPRIVATE=test/main # Generate and write random literals into a separate file generate-literals extraLiterals.go 500 printExtraLiterals go build exec ./main$exe binsubstr main$exe 'Lorem' 'dolor' 'second assign' 'First Line' 'Second Line' 'map value' 'to obfuscate' 'also obfuscate' 'stringTypeField String' binsubint main$exe '-7081390804778629748' '-301627827188279046' '7679634459002713443' binsubfloat main$exe '3684433217126772357.33' '-9015867427900753906' cp stderr normal.stderr garble -literals build exec ./main$exe cmp stderr normal.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' ! binsubint main$exe '-7081390804778629748' '-301627827188279046' '7679634459002713443' ! binsubfloat main$exe '3684433217126772357.33' '-9015867427900753906' [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 # Also check that the binary is different from previous builds. rm main$exe garble -literals -debugdir=.obf-src -seed=8J+Ri/Cfh6fwn4e+ build ! bincmp main$exe main_old$exe exec ./main$exe cmp stderr normal.stderr # Check obfuscators # Xor obfuscator. Detect a[i] = a[i] (^|-|+) b[i] grep '^\s+\w+\[\w+\] = \w+\[\w+\] [\^\-+] \w+$' .obf-src/main/extraLiterals.go # Swap obfuscator. Detect [...]byte|uint16|uint32|uint64{...} grep '^\s+\w+ := \[\.{3}\](byte|uint16|uint32|uint64)\{[0-9\s,]+\}$' .obf-src/main/extraLiterals.go # Split obfuscator. Detect decryptKey ^= i * counter grep '^\s+\w+ \^= \w+ \* \w+$' .obf-src/main/extraLiterals.go # XorShuffle obfuscator. Detect data = append(data, x (^|-|+) y...) grep '^\s+\w+ = append\(\w+,(\s+\w+\[\d+\][\^\-+]\w+\[\d+\],?)+\)$' .obf-src/main/extraLiterals.go # XorSeed obfuscator. Detect type decFunc func(byte) decFunc grep '^\s+type \w+ func\(byte\) \w+$' .obf-src/main/extraLiterals.go -- go.mod -- module test/main -- 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() numTest() boolTest() printExtraLiterals() } 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 } func numTest() { const a = 1 // skip const b = a + 2 // skip const c = 2824583991413579605 d := 4 var e = 5 var f int f = 3735714531481032066 println(a, b, c, d, e, f) var ( untypedInt = -7081390804778629760 + 12 intVar int = -301627827188279046 int8Var int8 = -122.0 int16Var int16 = 3534 int32Var int32 = 333453534 int64Var int64 = 4568766098255857483 uintVar uint = 7679634459002713443 uint8Var uint8 = 34 uint16Var uint16 = 3534 uint32Var uint32 = 333453534 uint64Var uint64 = 5490982829161518439 uintptrVar uintptr = 7364326871810921708 untypedFloat = 3684433217126772357.33 floatVar float64 = -9015867427900753906 floatVar32 float32 = 6338507605633 complexVar64 complex64 = -435453453534 // skip complexVar128 complex128 = 1 + 4i // skip underscoreInt = 1_3_3_7 underscoreFloat = 1_3_3_7.0 hexInt = 0x1337 // skip hexFloat = 0x1337p0 // skip octalInt = 0o1337 // skip octalFloat = 0o1337 // skip ) floatShort := -435453453534.0 println(untypedInt, intVar, int8Var, int16Var, int32Var, int64Var) println(uintVar, uint8Var, uint16Var, uint32Var, uint64Var, uintptrVar) println(untypedFloat, floatVar, floatShort, floatVar32) println(complexVar64, complexVar128) println(underscoreInt, underscoreFloat, hexInt, hexFloat, octalInt, octalFloat) } func boolTest() { const a = true // skip const b = false == a // skip const c bool = false d := true var e = true var f bool f = false println(a, b, c, d, e, f) }