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