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.
garble/testdata/script/literals.txtar

519 lines
13 KiB
Plaintext

exec garble -literals build
exec ./main$exe
cmp stderr main.stderr
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' 'sz<min'
! binsubstr main$exe 'garbleDecrypt' 'Lorem Ipsum' 'dolor sit amet' 'first assign' 'second assign' 'First Line' 'Second Line' 'secret map value' 'obfuscated with shadowed builtins' '1: literal in' 'an secret array' '2: literal in' 'a secret slice' 'to obfuscate' 'also obfuscate' 'stringTypeField String' 'testMap1 key' 'Obfuscate this block' 'also obfuscate this'
[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
exec 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 Ipsum' 'dolor sit amet' 'second assign' 'First Line' 'Second Line' 'secret map value' 'obfuscated with shadowed builtins' '1: literal in' 'an secret array' '2: literal in' 'a secret slice' 'to obfuscate' 'also obfuscate' 'stringTypeField String' 'testMap1 key' 'Obfuscate this block' 'also obfuscate this'
do not try to obfuscate huge literals (#204) It's common for asset bundling code generators to produce huge literals, for example in strings. Our literal obfuscators are meant for relatively small string-like literals that a human would write, such as URLs, file paths, and English text. I ran some quick experiments, and it seems like "garble build -literals" appears to hang trying to obfuscate literals starting at 5-20KiB. It's not really hung; it's just doing a lot of busy work obfuscating those literals. The code it produces is also far from ideal, so it also takes some time to finally compile. The generated code also led to crashes. For example, using "garble build -literals -tiny" on a package containing literals of over a megabyte, our use of asthelper to remove comments and shuffle line numbers could run out of stack memory. This all points in one direction: we never designed "-literals" to deal with large sizes. Set a source-code-size limit of 2KiB. We alter the literals.txt test as well, to include a few 128KiB string literals. Before this fix, "go test" would seemingly hang on that test for over a minute (I did not wait any longer). With the fix, those large literals are not obfuscated, so the test ends in its usual 1-3s. As said in the const comment, I don't believe any of this is a big problem. Come Go 1.16, most developers should stop using asset-bundling code generators and use go:embed instead. If we wanted to somehow obfuscate those, it would be an entirely separate feature. And, if someone wants to work on obfuscating truly large literals for any reason, we need good tests and benchmarks to ensure garble does not consume CPU for minutes or run out of memory. I also simplified the generate-literals test command. The only argument that matters to the script is the filename, since it's used later on. Fixes #178.
3 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
# ensure we find the extra literals in an unobfuscated build
go build
binsubstr main$exe 'a_unique_string_that_is_part_of_all_extra_literals'
# ensure we don't find the extra literals in an obfuscated build
exec garble -literals -debugdir=debug1 build
exec ./main$exe
cmp stderr main.stderr
! binsubstr main$exe 'a_unique_string_that_is_part_of_all_extra_literals'
make -literals succeed on all of std Two bugs were remaining which made the build with -literals of std fail. First, we were ignoring too many objects in constant expressions, including type names. This resulted in type names declared in dependencies which were incorrectly not obfuscated in the current package: # go/constant O1ku7TCe.go:1: undefined: alzLJ5Fd.Word b0ieEGVQ.go:1: undefined: alzLJ5Fd.Word LEpgYKdb.go:4: undefined: alzLJ5Fd.Word FkhHJCfm.go:1: undefined: alzLJ5Fd.Word This edge case is easy to reproduce, so a test case is added to literals.txt. The second issue is trickier; in some packages like os/user, we would get syntax errors because of comments printed out of place: ../tip/os/user/getgrouplist_unix.go:35:130: syntax error: unexpected newline, expecting comma or ) This is a similar kind of error that we tried to fix with e2f06cce94. In particular, it's fixed by also setting CallExpr.Rparen in withPos. We also add many other missing Pos fields for good measure, even though we're not sure they help just yet. Unfortunately, all my attempts to minimize this into a reproducible failure have failed. We can't just copy the failing file from os/user, as it only builds on some OSs. It seems like it was the perfect mix of cgo (which adds line directive comments) plus unlucky positioning of literals. For that last reason, as well as for ensuring that -literals works well with a wide variety of software, we add a build of all of std with -literals when not testing with -short. This is akin to what we do in goprivate.txt, but with the -literals flag. This does make "go test" more expensive, but also more thorough. Fixes #285, hopefully for good this time.
3 years ago
# Check obfuscators.
# Xor obfuscator. Detect a[i] = a[i] (^|-|+) b[i]
refactor "current package" with TOOLEXEC_IMPORTPATH (#266) 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".
3 years ago
grep '^\s+\w+\[\w+\] = \w+\[\w+\] [\^\-+] \w+$' debug1/test/main/extra_literals.go
# Swap obfuscator. Detect [...]byte|uint16|uint32|uint64{...}
refactor "current package" with TOOLEXEC_IMPORTPATH (#266) 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".
3 years ago
grep '^\s+\w+ := \[\.{3}\](byte|uint16|uint32|uint64)\{[0-9\s,]+\}$' debug1/test/main/extra_literals.go
# Split obfuscator. Detect decryptKey ^= i * counter
refactor "current package" with TOOLEXEC_IMPORTPATH (#266) 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".
3 years ago
grep '^\s+\w+ \^= \w+ \* \w+$' debug1/test/main/extra_literals.go
# XorShuffle obfuscator. Detect data = append(data, x[? ^ idxKey[?]] (^|-|+) y[? ^ idxKey[?]]...).
# Note that the line obfuscator adds an inline comment before the call.
grep '^(\s+)?\w+ = .*\bappend\(\w+,(\s+\w+\[\d+\^\s.+\][\^\-+]\w+\[\d+\^\s.+\],?)+\)$' 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
make -literals succeed on all of std Two bugs were remaining which made the build with -literals of std fail. First, we were ignoring too many objects in constant expressions, including type names. This resulted in type names declared in dependencies which were incorrectly not obfuscated in the current package: # go/constant O1ku7TCe.go:1: undefined: alzLJ5Fd.Word b0ieEGVQ.go:1: undefined: alzLJ5Fd.Word LEpgYKdb.go:4: undefined: alzLJ5Fd.Word FkhHJCfm.go:1: undefined: alzLJ5Fd.Word This edge case is easy to reproduce, so a test case is added to literals.txt. The second issue is trickier; in some packages like os/user, we would get syntax errors because of comments printed out of place: ../tip/os/user/getgrouplist_unix.go:35:130: syntax error: unexpected newline, expecting comma or ) This is a similar kind of error that we tried to fix with e2f06cce94. In particular, it's fixed by also setting CallExpr.Rparen in withPos. We also add many other missing Pos fields for good measure, even though we're not sure they help just yet. Unfortunately, all my attempts to minimize this into a reproducible failure have failed. We can't just copy the failing file from os/user, as it only builds on some OSs. It seems like it was the perfect mix of cgo (which adds line directive comments) plus unlucky positioning of literals. For that last reason, as well as for ensuring that -literals works well with a wide variety of software, we add a build of all of std with -literals when not testing with -short. This is akin to what we do in goprivate.txt, but with the -literals flag. This does make "go test" more expensive, but also more thorough. Fixes #285, hopefully for good this time.
3 years ago
# Finally, sanity check that we can build all of std with -literals.
ensure the runtime is built in a reproducible way We went to great lengths to ensure garble builds are reproducible. This includes how the tool itself works, as its behavior should be the same given the same inputs. However, we made one crucial mistake with the runtime package. It has go:linkname directives pointing at other packages, and some of those pointed packages aren't its dependencies. Imagine two scenarios where garble builds the runtime package: 1) We run "garble build runtime". The way we handle linkname directives calls listPackage on the target package, to obfuscate the target's import path and object name. However, since we only obtained build info of runtime and its deps, calls for some linknames such as listPackage("sync/atomic") will fail. The linkname directive will leave its target untouched. 2) We run "garble build std". Unlike the first scenario, all listPackage calls issued by runtime's linkname directives will succeed, so its linkname directive targets will be obfuscated. At best, this can result in inconsistent builds, depending on how the runtime package was built. At worst, the mismatching object names can result in errors at link time, if the target packages are actually used. The modified test reproduces the worst case scenario reliably, when the fix is reverted: > env GOCACHE=${WORK}/gocache-empty > garble build -a runtime > garble build -o=out_rebuild ./stdimporter [stderr] # test/main/stdimporter JZzQivnl.NtQJu0H3: relocation target JZzQivnl.iioHinYT not defined JZzQivnl.NtQJu0H3.func9: relocation target JZzQivnl.yz5z0NaH not defined JZzQivnl.(*ypvqhKiQ).String: relocation target JZzQivnl.eVciBQeI not defined JZzQivnl.(*ypvqhKiQ).PkgPath: relocation target JZzQivnl.eVciBQeI not defined [...] The fix consists of two steps. First, if we're building the runtime and listPackage fails on a package, that means we ran into scenario 1 above. To avoid the inconsistency, we fill ListedPackages with "go list [...] std". This means we'll always build runtime as described in scenario 2 above. Second, when building packages other than the runtime, we only allow listPackage to succeed if we're listing a dependency of the current package. This ensures we won't run into similar reproducibility bugs in the future. Finally, re-enable test-gotip on CI since this was the last test flake.
3 years ago
# Analogous to gogarble.txt.
exec garble -literals build std
-- go.mod --
module test/main
go 1.22
-- main.go --
package main
support GOGARBLE=* with -literals again We recently made an important change when obfuscating the runtime, so that if it's missing any linkname packages in ListedPackages, it does an extra "go list" call to obtain their information. This works very well, but we missed an edge case. In main.go, we disable flagLiterals for the runtime package, but not for other packages like sync/atomic. And, since the runtime's extra "go list" has to compute GarbleActionIDs, it uses the list of garble flags via appendFlags. Unfortunately, it thinks "-literals" isn't set, when it is, and the other packages see it as being set. This discrepancy results in link time errors, as each end of the linkname obfuscates with a different hash: > garble -literals build [stderr] # test/main jccGkbFG.(*yijmzGHo).String: relocation target jccGkbFG.e_77sflf not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.ce66Fmzl not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.e5kPa1qY not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.aQ_3sL3Q not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.zls3wmws not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.g69WgKIS not defined To fix the problem, treat flagLiterals as read-only after flag.Parse, just like we already do with the other flags except flagDebugDir. The code that turned flagLiterals to false is no longer needed, as literals.Obfuscate is only called when ToObfuscate is true, and ToObfuscate is false for runtimeAndDeps already.
2 years ago
import (
_ "runtime/debug"
"test/main/imp"
. "test/main/imp_const"
. "test/main/imp_func"
. "test/main/imp_var"
. "test/main/imp_type"
. "test/main/imp_struct"
support GOGARBLE=* with -literals again We recently made an important change when obfuscating the runtime, so that if it's missing any linkname packages in ListedPackages, it does an extra "go list" call to obtain their information. This works very well, but we missed an edge case. In main.go, we disable flagLiterals for the runtime package, but not for other packages like sync/atomic. And, since the runtime's extra "go list" has to compute GarbleActionIDs, it uses the list of garble flags via appendFlags. Unfortunately, it thinks "-literals" isn't set, when it is, and the other packages see it as being set. This discrepancy results in link time errors, as each end of the linkname obfuscates with a different hash: > garble -literals build [stderr] # test/main jccGkbFG.(*yijmzGHo).String: relocation target jccGkbFG.e_77sflf not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.ce66Fmzl not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.e5kPa1qY not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.aQ_3sL3Q not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.zls3wmws not defined jQg9GEkg.(*NLxfRPAP).pB5p2ZP0: relocation target jQg9GEkg.g69WgKIS not defined To fix the problem, treat flagLiterals as read-only after flag.Parse, just like we already do with the other flags except flagDebugDir. The code that turned flagLiterals to false is no longer needed, as literals.Obfuscate is only called when ToObfuscate is true, and ToObfuscate is false for runtimeAndDeps already.
2 years ago
)
make -literals succeed on all of std Two bugs were remaining which made the build with -literals of std fail. First, we were ignoring too many objects in constant expressions, including type names. This resulted in type names declared in dependencies which were incorrectly not obfuscated in the current package: # go/constant O1ku7TCe.go:1: undefined: alzLJ5Fd.Word b0ieEGVQ.go:1: undefined: alzLJ5Fd.Word LEpgYKdb.go:4: undefined: alzLJ5Fd.Word FkhHJCfm.go:1: undefined: alzLJ5Fd.Word This edge case is easy to reproduce, so a test case is added to literals.txt. The second issue is trickier; in some packages like os/user, we would get syntax errors because of comments printed out of place: ../tip/os/user/getgrouplist_unix.go:35:130: syntax error: unexpected newline, expecting comma or ) This is a similar kind of error that we tried to fix with e2f06cce94. In particular, it's fixed by also setting CallExpr.Rparen in withPos. We also add many other missing Pos fields for good measure, even though we're not sure they help just yet. Unfortunately, all my attempts to minimize this into a reproducible failure have failed. We can't just copy the failing file from os/user, as it only builds on some OSs. It seems like it was the perfect mix of cgo (which adds line directive comments) plus unlucky positioning of literals. For that last reason, as well as for ensuring that -literals works well with a wide variety of software, we add a build of all of std with -literals when not testing with -short. This is akin to what we do in goprivate.txt, but with the -literals flag. This does make "go test" more expensive, but also more thorough. Fixes #285, hopefully for good this time.
3 years ago
type structTest struct {
field string
anotherField string
}
const (
cnst string = "Lorem Ipsum"
multiline string = `First Line
Second Line`
)
const (
i = 1
boolean = true
mixedBlock = "Obfuscate this block"
)
const (
foo = iota
bar
iotaBlock = "also obfuscate this"
)
// 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
const arrayLen = 4
var array [arrayLen]byte
type typeAlias [arrayLen]byte
func main() {
empty := ""
tooSmall := "sz<min"
localVar := "dolor sit amet"
reassign := "first assign"
reassign = "second assign"
add := "totally long" + "unnecessarily added string"
println(cnst, boolean)
println(multiline, add)
println(localVar)
println(reassign)
println(empty)
println(tooSmall)
x := structTest{
field: "to obfuscate",
anotherField: "also obfuscate",
}
lambda := func() string {
return "happy faces 😅 😅"
}()
println(lambda)
println(x.field, x.anotherField)
testMap := map[string]string{"secret map key": "secret map value"}
testMap["secret map key"] = "secret new value"
println(testMap["secret map key"])
println("another literal")
println(mixedBlock, iotaBlock)
println(i, foo, bar)
typedTest()
constantTest()
byteTest()
shadowTest()
dotImportTest()
multipleTimeImportTest()
strArray := [2]string{"1: literal in", "an secret array"}
println(strArray[0], strArray[1])
strSlice := []string{"2: literal in", "a secret slice"}
println(strSlice[0], strSlice[1])
emptyStrSlice := []string{""}
print(emptyStrSlice[0])
}
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 bar bar" // skip
const length = len(a)
const b = "bar foo foo" // skip
type T [len(b)]byte
const c = "foo bar bar" // skip
var _ [len(c)]byte
const d = "foo bar bar" // skip
var arr = [12]string{len(d): "foo bar bar"}
for _, elm := range arr {
if elm != "" {
println(elm)
}
}
const e = "foo bar bar" // skip
var slice = []string{len(e): "foo bar bar"}
for _, elm := range slice {
if elm != "" {
println(elm)
}
}
const f = "foo bar bar" // skip
const i = length + len(f)
println(length, i)
make -literals succeed on all of std Two bugs were remaining which made the build with -literals of std fail. First, we were ignoring too many objects in constant expressions, including type names. This resulted in type names declared in dependencies which were incorrectly not obfuscated in the current package: # go/constant O1ku7TCe.go:1: undefined: alzLJ5Fd.Word b0ieEGVQ.go:1: undefined: alzLJ5Fd.Word LEpgYKdb.go:4: undefined: alzLJ5Fd.Word FkhHJCfm.go:1: undefined: alzLJ5Fd.Word This edge case is easy to reproduce, so a test case is added to literals.txt. The second issue is trickier; in some packages like os/user, we would get syntax errors because of comments printed out of place: ../tip/os/user/getgrouplist_unix.go:35:130: syntax error: unexpected newline, expecting comma or ) This is a similar kind of error that we tried to fix with e2f06cce94. In particular, it's fixed by also setting CallExpr.Rparen in withPos. We also add many other missing Pos fields for good measure, even though we're not sure they help just yet. Unfortunately, all my attempts to minimize this into a reproducible failure have failed. We can't just copy the failing file from os/user, as it only builds on some OSs. It seems like it was the perfect mix of cgo (which adds line directive comments) plus unlucky positioning of literals. For that last reason, as well as for ensuring that -literals works well with a wide variety of software, we add a build of all of std with -literals when not testing with -short. This is akin to what we do in goprivate.txt, but with the -literals flag. This does make "go test" more expensive, but also more thorough. Fixes #285, hopefully for good this time.
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)
}
// 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.
func byteTest() {
a := []byte{12, 13, 12, 13, 12, 13, 12, 13, 12, 13}
for _, elm := range a {
print(elm, ",")
}
println()
var b = []byte{12, 13, 12, 13, 12, 13, 12, 13, 12, 13}
for _, elm := range b {
print(elm, ",")
}
println()
var c = [10]byte{12, 13, 12, 13, 12, 13, 12, 13, 12, 13}
for _, elm := range c {
print(elm, ",")
}
println()
d := func() [12]byte {
return [12]byte{12, 13, 12, 13, 12, 13, 12, 13, 12, 13}
}()
for _, elm := range d {
print(elm, ",")
}
println()
e := []byte{0x43, 11_1, 0b01101101, 'p', 'l', 'e', 'x', ' ', 'l', 'i', 't'}
println(string(e))
// Testing for issue #520.
func(s []byte) {
print(string(s))
}([]byte("big chungus"))
println()
func(s *[]byte) {
print(string(*s))
}(&[]byte{99, 104, 117, 110, 103, 117, 115, '!', '!'})
println()
func(s [9]byte) {
for _, elm := range s {
print(elm, ",")
}
}([9]byte{99, 104, 117, 110, 103, 117, 115, 117, 115})
println()
func(s *[9]byte) {
for _, elm := range s {
print(elm, ",")
}
}(&[9]byte{99, 104, 117, 110, 103, 117, 115, 117, 115})
println()
}
func stringTypeFunc(s stringType) stringType {
println(s)
return "stringType return" // skip
}
// obfuscating this broke before
const (
iota0 uint8 = iota
iota1
)
// 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)")
}
}
func dotImportTest() {
println(DotImportedStr)
println(DotImportedFunc())
println(DotImportedVar)
println(DotImportedType("str as dot imported type"))
println(DotImportedStruct.Str)
}
func multipleTimeImportTest() {
regularAndUnusedRenamed()
regularAndUnusedDotImport()
unusedRegularAndDotImport()
}
func noop(...any) {}
-- regular_and_unused_renamed.go --
package main
import (
"test/main/imp_mult"
imp_mult2 "test/main/imp_mult"
)
func regularAndUnusedRenamed() {
imp_mult.MultDummy()
noop(imp_mult.MultImpStr, imp_mult2.MultImpStr)
}
-- regular_and_unused_dotimport.go --
package main
import (
"test/main/imp_mult"
. "test/main/imp_mult"
)
func regularAndUnusedDotImport() {
imp_mult.MultDummy()
noop(imp_mult.MultImpStr, MultImpStr)
}
-- unused_regular_and_dotimport.go --
package main
import (
"test/main/imp_mult"
. "test/main/imp_mult"
)
func unusedRegularAndDotImport() {
MultDummy()
noop(imp_mult.MultImpStr, MultImpStr)
}
-- imp/imported.go --
make -literals succeed on all of std Two bugs were remaining which made the build with -literals of std fail. First, we were ignoring too many objects in constant expressions, including type names. This resulted in type names declared in dependencies which were incorrectly not obfuscated in the current package: # go/constant O1ku7TCe.go:1: undefined: alzLJ5Fd.Word b0ieEGVQ.go:1: undefined: alzLJ5Fd.Word LEpgYKdb.go:4: undefined: alzLJ5Fd.Word FkhHJCfm.go:1: undefined: alzLJ5Fd.Word This edge case is easy to reproduce, so a test case is added to literals.txt. The second issue is trickier; in some packages like os/user, we would get syntax errors because of comments printed out of place: ../tip/os/user/getgrouplist_unix.go:35:130: syntax error: unexpected newline, expecting comma or ) This is a similar kind of error that we tried to fix with e2f06cce94. In particular, it's fixed by also setting CallExpr.Rparen in withPos. We also add many other missing Pos fields for good measure, even though we're not sure they help just yet. Unfortunately, all my attempts to minimize this into a reproducible failure have failed. We can't just copy the failing file from os/user, as it only builds on some OSs. It seems like it was the perfect mix of cgo (which adds line directive comments) plus unlucky positioning of literals. For that last reason, as well as for ensuring that -literals works well with a wide variety of software, we add a build of all of std with -literals when not testing with -short. This is akin to what we do in goprivate.txt, but with the -literals flag. This does make "go test" more expensive, but also more thorough. Fixes #285, hopefully for good this time.
3 years ago
package imported
type ImportedType int
-- imp_const/imported.go --
package imp_const
const DotImportedStr = "const str from dot imported var"
-- imp_func/imported.go --
package imp_func
func DotImportedFunc() string {
return "str from dot imported func"
}
-- imp_var/imported.go --
package imp_var
var DotImportedVar = "str from dot imported var"
-- imp_type/imported.go --
package imp_type
type DotImportedType string
-- imp_struct/imported.go --
package imp_struct
var DotImportedStruct = struct{ Str string }{Str: "string in dot imported struct"}
-- imp_mult/imported.go --
package imp_mult
const MultImpStr = "str from package imported multiple time"
func MultDummy() {}
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
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 bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str1() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str2() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str3() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str4() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func arr0() { println(len([...]byte{0, 1, 2, 3, 4, 5, 6, 7, 8})) }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func arr1() { println(len([...]byte{0, 1, 2, 3, 4, 5, 6, 7, 8})) }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func slc0() { println([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}) }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func slc1() { println([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}) }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str5() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str6() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str7() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str8() { println("foo bar bar") }
set positions when using cursor.Replace The regular obfuscation process simply modifies some simple nodes, such as identifiers and strings. In those cases, we modify the nodes in-place, meaning that their positions remain the same. This hasn't caused any problems. Literal obfuscation is trickier. Since we replace one expression with an entirely different one, we use cursor.Replace. The new expression is entirely made up on the spot, so it lacks position information. This was causing problems. For example, in the added test input: > garble -literals build [stderr] # test/main dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:4: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:6: misplaced compiler directive dgcm4t6w.go:7: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:9: misplaced compiler directive dgcm4t6w.go:3: misplaced compiler directive dgcm4t6w.go:3: too many errors The build errors are because we'd move the compiler directives, which makes the compiler unhappy as they must be directly followed by a function declaration. The root cause there seems to be that, since the replacement nodes lack position information, go/printer would try to estimate its printing position by adding to the last known position. Since -literals adds code, this would result in the printer position increasing rapidly, and potentially printing directive comments earlier than needed. For now, making the replacement nodes have the same position as the original node seems to stop go/printer from making this mistake. It's possible that this workaround won't be bulletproof forever, but it works well for now, and I don't see a simpler workaround right now. It would be possible to use fancier mechanisms like go/ast.CommentMap or dave/dst, but those are a significant amount of added complexity as well. Fixes #285.
3 years ago
//go:noinline
func str9() { println("foo bar bar") }
-- main.stderr --
Lorem Ipsum true
First Line
Second Line totally longunnecessarily added string
dolor sit amet
second assign
sz<min
happy faces 😅 😅
to obfuscate also obfuscate
secret new value
another literal
Obfuscate this block also obfuscate 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 bar bar
foo bar bar
11 22
12,13,12,13,12,13,12,13,12,13,
12,13,12,13,12,13,12,13,12,13,
12,13,12,13,12,13,12,13,12,13,
12,13,12,13,12,13,12,13,12,13,0,0,
Complex lit
big chungus
chungus!!
99,104,117,110,103,117,115,117,115,
99,104,117,110,103,117,115,117,115,
obfuscated with shadowed builtins (vars)
obfuscated with shadowed builtins (types)
const str from dot imported var
str from dot imported func
str from dot imported var
str as dot imported type
string in dot imported struct
1: literal in an secret array
2: literal in a secret slice