env GARBLE_EXPERIMENTAL_CONTROLFLOW=1 exec garble -literals -debugdir=debug -seed=0002deadbeef build -o=main$exe stderr '"test/main.func1" function has no effect on the resulting binary' exec ./main cmp stderr main.stderr # simple check to ensure that control flow will work. Must be a minimum of 10 goto's grep 'goto _s2a_l10' $WORK/debug/test/main/GARBLE_controlflow.go # obfuscated function must be removed from original file ! grep 'main\(\)' $WORK/debug/test/main/garble_main.go # original file must contains empty function grep '\_\(\)' $WORK/debug/test/main/garble_main.go # obfuscated file must contains interface for unexported interface emulation grep 'GoString\(\) string' $WORK/debug/test/main/GARBLE_controlflow.go grep 'String\(\) string' $WORK/debug/test/main/GARBLE_controlflow.go # control flow obfuscation should work correctly with literals obfuscation ! binsubstr main$exe 'correct name' # check xor hardening grep '\(\w+ \^ \d+\)' $WORK/debug/test/main/GARBLE_controlflow.go # check delegate table hardening grep 'func\(int\) int' $WORK/debug/test/main/GARBLE_controlflow.go -- go.mod -- module test/main go 1.22 -- garble_main.go -- package main import ( "encoding/binary" "encoding/hex" "hash/crc32" ) //garble:controlflow flatten_passes=0 junk_jumps=max block_splits=max func func1() {} //garble:controlflow flatten_passes=1 junk_jumps=max block_splits=max flatten_hardening=xor func xorHardeningTest(i int) int { if i == 0 { return 1 } return i * 2; } //garble:controlflow flatten_passes=1 junk_jumps=max block_splits=max flatten_hardening=delegate_table func delegateHardeningTest(i int) int { if i == 0 { return 1 } return i * 3; } //garble:controlflow flatten_passes=1 junk_jumps=max block_splits=max flatten_hardening=xor,delegate_table // Trigger multiple hardening using multiple anonymous functions func multiHardeningTest(i int) int { notZero := func(i int) bool { return i != 0 } isZero := func(i int) bool { return i == 0 } multiply := func(i int) int { return i * 4 } if !notZero(i) && isZero(i) { return 1 } return multiply(i); } //garble:controlflow flatten_passes=1 junk_jumps=10 block_splits=10 trash_blocks=32 func main() { // Reference to the unexported interface triggers creation of a new interface // with a list of all functions of the private interface endian := binary.LittleEndian println(endian.String()) println(endian.GoString()) println(endian.Uint16([]byte{0, 1})) // Switch statement should be simplified to if statements switch endian.String() { case "LittleEndian": println("correct name") default: panic("unreachable") } // Indirect import "hash" package hash := crc32.New(crc32.IEEETable) hash.Write([]byte("1")) hash.Write([]byte("2")) hash.Write([]byte("3")) println(hex.EncodeToString(hash.Sum(nil))) println(xorHardeningTest(0)) println(delegateHardeningTest(0)) println(multiHardeningTest(0)) } -- main.stderr -- LittleEndian binary.LittleEndian 256 correct name 884863d2 1 1 1