garble all possible combinations of private imports, patching reflect data needs fixing

pull/115/head
Andrew LeFevre 5 years ago
parent 1e463d85a4
commit efd6468e80

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
"path"
"sort"
"strings"
@ -28,10 +27,6 @@ const (
namedata
)
func hashImport(pkg string) string {
return hashWith(buildInfo.imports[pkg].buildID, pkg)
}
func obfuscateImports(objPath, importCfgPath string) error {
importCfg, err := goobj2.ParseImportCfg(importCfgPath)
if err != nil {
@ -43,6 +38,7 @@ func obfuscateImports(objPath, importCfgPath string) error {
}
privatePkgs := []pkgInfo{{mainPkg, objPath}}
// build list of imported packages that are private
for pkgPath, info := range importCfg {
if isPrivate(pkgPath) {
pkg, err := goobj2.Parse(info.Path, pkgPath, importCfg)
@ -57,19 +53,24 @@ func obfuscateImports(objPath, importCfgPath string) error {
var sb strings.Builder
var buf bytes.Buffer
for _, p := range privatePkgs {
fmt.Printf("++ Obfuscating object file for %s ++\n", p.pkg.ImportPath)
fmt.Printf("\n\n++ Obfuscating object file for %s ++\n", p.pkg.ImportPath)
for _, am := range p.pkg.ArchiveMembers {
if am.IsCompilerObj() {
continue
}
// add all private import paths to a list to garble
var privateImports []string
privateImports = append(privateImports, p.pkg.ImportPath)
if strings.ContainsRune(p.pkg.ImportPath, '/') {
privateImports = append(privateImports, path.Base(p.pkg.ImportPath))
privateImports = append(privateImports, importPathCombos(p.pkg.ImportPath)...)
}
for i := range am.Imports {
if isPrivate(am.Imports[i].Pkg) {
privateImports = append(privateImports, am.Imports[i].Pkg)
if strings.ContainsRune(am.Imports[i].Pkg, '/') {
privateImports = append(privateImports, importPathCombos(am.Imports[i].Pkg)...)
}
am.Imports[i].Pkg = hashImport(am.Imports[i].Pkg)
}
}
@ -77,23 +78,32 @@ func obfuscateImports(objPath, importCfgPath string) error {
if isPrivate(am.Packages[i]) {
privateImports = append(privateImports, am.Packages[i])
if strings.ContainsRune(am.Packages[i], '/') {
privateImports = append(privateImports, path.Base(am.Packages[i]))
privateImports = append(privateImports, importPathCombos(am.Packages[i])...)
}
am.Packages[i] = hashImport(am.Packages[i])
}
}
// move imports that contain another import as a substring to the front,
// so that the shorter import will not match first and leak part of an
// import path
sort.Slice(privateImports, func(i, j int) bool {
return privateImports[i] > privateImports[j]
iSlashes := strings.Count(privateImports[i], "/")
jSlashes := strings.Count(privateImports[j], "/")
if iSlashes == 0 && jSlashes == 0 {
return privateImports[i] > privateImports[j]
}
return iSlashes > jSlashes
})
privateImports = dedupImportPaths(privateImports)
// no private import paths, nothing to garble
fmt.Printf("== Private imports: %v ==\n", privateImports)
if len(privateImports) == 0 {
continue
}
// garble all private import paths in all symbol names
lists := [][]*goobj2.Sym{am.SymDefs, am.NonPkgSymDefs, am.NonPkgSymRefs}
for _, list := range lists {
for _, s := range list {
@ -158,7 +168,7 @@ func obfuscateImports(objPath, importCfgPath string) error {
buf.WriteRune('\n')
}
//fmt.Print("\n\n")
fmt.Print("\n\n")
if err = ioutil.WriteFile(importCfgPath, buf.Bytes(), 0644); err != nil {
return err
@ -167,6 +177,69 @@ func obfuscateImports(objPath, importCfgPath string) error {
return nil
}
// importPathCombos returns a list of import paths that
// could all potentially be in symbol names of the
// package that imported 'path'.
func importPathCombos(path string) []string {
paths := strings.Split(path, "/")
combos := make([]string, 0, len(paths))
var restPrivate bool
if isPrivate(paths[0]) {
combos = append(combos, paths[0])
restPrivate = true
}
// find first private match
privateIdx := 1
if !restPrivate {
newPath := paths[0]
for i := 1; i < len(paths); i++ {
newPath += "/" + paths[i]
if isPrivate(newPath) {
combos = append(combos, paths[i])
combos = append(combos, newPath)
privateIdx = i + 1
restPrivate = true
break
}
}
if !restPrivate {
return nil
}
}
lastComboIdx := 2
for i := privateIdx; i < len(paths)-1; i++ {
combos = append(combos, paths[i])
combos = append(combos, combos[lastComboIdx-1]+"/"+paths[i])
lastComboIdx += 2
}
combos = append(combos, paths[len(paths)-1])
return combos
}
func dedupImportPaths(paths []string) []string {
seen := make(map[string]struct{}, len(paths))
j := 0
for _, v := range paths {
if _, ok := seen[v]; ok {
continue
}
seen[v] = struct{}{}
paths[j] = v
j++
}
return paths[:j]
}
func hashImport(pkg string) string {
return hashWith(buildInfo.imports[pkg].buildID, pkg)
}
func garbleSymbolName(symName string, privateImports []string, sb *strings.Builder) (s string) {
var off int
for {
@ -203,18 +276,31 @@ func privateImportIndex(symName string, privateImports []string) (int, int) {
// likelihood that the package isn't matched as a
// substring of another ident name.
// ex: privateImport = main, symName = "domainname"
var noSlashes bool
if !strings.ContainsRune(privateImport, '/') {
privateImport += "."
noSlashes = true
}
off := strings.Index(symName, privateImport)
if off == -1 {
continue
// check that we didn't match inside an import path. If the
// byte before the start of the match is not a small set of
// symbols that can make up a symbol name, we must have matched
// inside of an ident name as a substring. Or, if the byte
// before the start of the match is a forward slash, we are
// definitely inside of an input path.
} else if off != 0 && (!isSymbol(symName[off-1]) || symName[off-1] == '/') {
continue
}
if off < firstOff || firstOff == -1 {
firstOff = off
l = len(privateImport)
if noSlashes {
l--
}
}
}
@ -225,6 +311,14 @@ func privateImportIndex(symName string, privateImports []string) (int, int) {
return firstOff, l
}
func isSymbol(c byte) bool {
return c == 32 || // ' '
(c >= 40 && c <= 42) || // '(', ')', '*'
c == 91 || c == 93 || c == 95 || // '[', ']', '_'
c == 123 || c == 125 // '{', '}'
}
func garbleSymData(data []byte, privateImports []string, dataTyp dataType, buf *bytes.Buffer) (b []byte) {
var off int
for {
@ -240,7 +334,9 @@ func garbleSymData(data []byte, privateImports []string, dataTyp dataType, buf *
case importPath:
return createImportPathData(hashImport(string(data[o : o+l])))
case namedata:
return patchReflectData(hashImport(string(data[o:o+l])), o, data)
//fmt.Printf("$$$ Reflectdata: %s\n", string(data[o:o+l]))
//return patchReflectData(hashImport(string(data[o:o+l])), o, data)
return data
default:
buf.Write(data[off : off+o])
buf.WriteString(hashImport(string(data[off+o : off+o+l])))

Loading…
Cancel
Save