From 67d2e06f5f3a7b6803bb18620e891a776a69515b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Sun, 1 Dec 2024 00:40:10 +0000 Subject: [PATCH] clarify internal/abi name code a bit Use the term "original name" rather than "real name" for the code as it is clearer that we mean the unobfuscated name. Update the comments at the top of the file to be clearer with the explanation of what kinds of inputs we can expect. While here, use fmt.Appendf to simplify the generation code a bit. --- bench_test.go | 14 +++++++------- reflect_abi_code.go | 29 ++++++++++++++--------------- reflect_abi_patch.go | 22 +++++++++++----------- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/bench_test.go b/bench_test.go index 83ae9b42..af5005b3 100644 --- a/bench_test.go +++ b/bench_test.go @@ -168,23 +168,23 @@ func BenchmarkBuild(b *testing.B) { b.ReportMetric(float64(info.Size()), "bin-B") } -func BenchmarkAbiRealName(b *testing.B) { - // Benchmark two thousand obfuscated names in _realNamePairs +func BenchmarkAbiOriginalNames(b *testing.B) { + // Benchmark two thousand obfuscated names in _originalNamePairs // and a variety of input strings to reverse. // As an example, the cmd/go binary ends up with about 2200 entries - // in _realNamePairs as of November 2024, so it's a realistic figure. + // in _originalNamePairs as of November 2024, so it's a realistic figure. // Structs with tens of fields are also relatively normal. salt := []byte("some salt bytes") for n := range 2000 { name := fmt.Sprintf("name_%d", n) garbled := hashWithCustomSalt(salt, name) - _realNamePairs = append(_realNamePairs, [2]string{garbled, name}) + _originalNamePairs = append(_originalNamePairs, [2]string{garbled, name}) } // Pick twenty names at random to use as inputs below. // Use a deterministic random source so it's stable between benchmark runs. rnd := rand.New(rand.NewPCG(1, 2)) var chosen []string - for _, pair := range _realNamePairs { + for _, pair := range _originalNamePairs { chosen = append(chosen, pair[0]) } rnd.Shuffle(len(chosen), func(i, j int) { @@ -219,9 +219,9 @@ func BenchmarkAbiRealName(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { for _, input := range inputs { - _realName(input) + _originalNames(input) } } }) - _realNamePairs = [][2]string{} + _originalNamePairs = [][2]string{} } diff --git a/reflect_abi_code.go b/reflect_abi_code.go index 53b8dfe4..5b04a91c 100644 --- a/reflect_abi_code.go +++ b/reflect_abi_code.go @@ -1,21 +1,20 @@ package main // The "name" internal/abi passes to this function doesn't have to be a simple "someName" -// it can also be for function names: -// "*pkgName.FuncName" (obfuscated) -// or for structs the entire struct definition: -// "*struct { AQ45rr68K string; ipq5aQSIqN string; hNfiW5O5LVq struct { gPTbGR00hu string } }" + +// it can also be for function names like "*pkgName.FuncName" (obfuscated) +// or for structs the entire struct definition, like // -// Therefore all obfuscated names which occur within name need to be replaced with their "real" equivalents. +// *struct { AQ45rr68K string; ipq5aQSIqN string; hNfiW5O5LVq struct { gPTbGR00hu string } } // +// Therefore all obfuscated names which occur within name need to be replaced with their original equivalents. // The code below does a more efficient version of: // -// func _realName(name string) string { -// for obfName, real := range _nameMap { -// name = strings.ReplaceAll(name, obfName, real) -// } -// -// return name +// func _originalNames(name string) string { +// for _, pair := range _originalNamePairs { +// name = strings.ReplaceAll(name, pair[0], pair[1]) +// } +// return name // } // // The linknames below are only turned on when the code is injected, @@ -23,8 +22,8 @@ package main // Injected code below this line. -//disabledgo:linkname _realName internal/abi._realName -func _realName(name string) string { +//disabledgo:linkname _originalNames internal/abi._originalNames +func _originalNames(name string) string { if len(name) < minHashLength { // The name is too short to be obfuscated. return name @@ -39,7 +38,7 @@ func _realName(name string) string { } remLen := len(name[i:]) found := false - for _, pair := range _realNamePairs { + for _, pair := range _originalNamePairs { obfName := pair[0] real := pair[1] keyLen := len(obfName) @@ -64,4 +63,4 @@ func _realName(name string) string { // Each pair is the obfuscated and then the real name. // The slice is sorted from shortest to longest obfuscated name. -var _realNamePairs = [][2]string{} +var _originalNamePairs = [][2]string{} diff --git a/reflect_abi_patch.go b/reflect_abi_patch.go index f1203b5e..37ca8ffb 100644 --- a/reflect_abi_patch.go +++ b/reflect_abi_patch.go @@ -19,21 +19,21 @@ func abiNamePatch(path string) (string, error) { } find := `return unsafe.String(n.DataChecked(1+i, "non-empty string"), l)` - replace := `return _realName(unsafe.String(n.DataChecked(1+i, "non-empty string"), l))` + replace := `return _originalNames(unsafe.String(n.DataChecked(1+i, "non-empty string"), l))` str := strings.Replace(string(data), find, replace, 1) - realname := ` -//go:linkname _realName -func _realName(name string) string + originalNames := ` +//go:linkname _originalNames +func _originalNames(name string) string ` - return str + realname, nil + return str + originalNames, nil } var reflectPatchFile = "" -// reflectMainPrePatch adds the initial empty name mapping and _realName implementation +// reflectMainPrePatch adds the initial empty name mapping and _originalNames implementation // to a file in the main package. The name mapping will be populated later after // analyzing the main package, since we need to know all obfuscated names that need mapping. // We split this into pre/post steps so that all variable names in the generated code @@ -59,18 +59,18 @@ func reflectMainPrePatch(path string) ([]byte, error) { // reflectMainPostPatch populates the name mapping with the final obfuscated->real name // mappings after all packages have been analyzed. func reflectMainPostPatch(file []byte, lpkg *listedPackage, pkg pkgCache) []byte { - obfVarName := hashWithPackage(lpkg, "_realNamePairs") - nameMap := fmt.Sprintf("%s = [][2]string{", obfVarName) + obfVarName := hashWithPackage(lpkg, "_originalNamePairs") + namePairs := fmt.Appendf(nil, "%s = [][2]string{", obfVarName) - var b strings.Builder keys := slices.SortedFunc(maps.Keys(pkg.ReflectObjectNames), func(a, b string) int { return cmp.Compare(len(a), len(b)) }) + namePairsFilled := bytes.Clone(namePairs) for _, obf := range keys { - b.WriteString(fmt.Sprintf("{%q, %q},", obf, pkg.ReflectObjectNames[obf])) + namePairsFilled = fmt.Appendf(namePairsFilled, "{%q, %q},", obf, pkg.ReflectObjectNames[obf]) } - return bytes.Replace(file, []byte(nameMap), []byte(nameMap+b.String()), 1) + return bytes.Replace(file, namePairs, namePairsFilled, 1) } //go:embed reflect_abi_code.go