Storing obfuscated sources in an object file has been implemented

pull/158/head
Pagran 5 years ago
parent 29378787e2
commit 3889fcdaab

@ -4,13 +4,18 @@
package main
import (
"archive/tar"
"bufio"
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/Binject/debug/goobj2"
@ -62,6 +67,62 @@ func appendPrivateNameMap(pkg *goobj2.Package, nameMap map[string]string) error
return nil
}
func extractDebugObfSrc(pkgPath string, pkg *goobj2.Package) error {
if envGarbleDebugDir == "" {
return nil
}
for _, member := range pkg.ArchiveMembers {
if member.ArchiveHeader.Name != garbleSrcHeaderName {
continue
}
osPkgPath := filepath.FromSlash(pkgPath)
pkgDebugDir := filepath.Join(envGarbleDebugDir, osPkgPath)
if err := os.MkdirAll(pkgDebugDir, 0o755); err != nil {
return err
}
archiveSize, err := strconv.Atoi(member.ArchiveHeader.Date)
if err != nil {
return err
}
archiveBytes := member.ArchiveHeader.Data[:archiveSize]
archive := bytes.NewBuffer(archiveBytes)
gzipReader, err := gzip.NewReader(archive)
if err != nil {
return err
}
defer gzipReader.Close()
tarReader := tar.NewReader(gzipReader)
for {
header, err := tarReader.Next()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
debugFilePath := filepath.Join(pkgDebugDir, header.Name)
debugFile, err := os.Create(debugFilePath)
if err != nil {
return err
}
if _, err := io.Copy(debugFile, tarReader); err != nil {
return err
}
debugFile.Close()
obfuscationTime := header.ModTime.Local()
os.Chtimes(debugFilePath, obfuscationTime, obfuscationTime) // Restore obfuscation time
}
}
return nil
}
// obfuscateImports does all the necessary work to replace the import paths of
// obfuscated packages with hashes. It takes the single object file and import
// config passed to the linker, as well as a temporary directory to store
@ -87,6 +148,9 @@ func obfuscateImports(objPath, tempDir, importCfgPath string) (garbledObj string
if err != nil {
return "", nil, nil, fmt.Errorf("error parsing main objfile: %v", err)
}
if err := extractDebugObfSrc("main", mainPkg); err != nil {
return "", nil, nil, err
}
pkgs := []pkgInfo{{mainPkg, objPath, true}}
privateNameMap = make(map[string]string)
@ -105,6 +169,12 @@ func obfuscateImports(objPath, tempDir, importCfgPath string) (garbledObj string
if err := appendPrivateNameMap(pkg, privateNameMap); err != nil {
return "", nil, nil, fmt.Errorf("error parsing name map %s at %s: %v", pkgPath, info.Path, err)
}
// Avoiding double extraction from main object file
if objPath != info.Path {
if err := extractDebugObfSrc(pkgPath, pkg); err != nil {
return "", nil, nil, err
}
}
}
}

@ -4,7 +4,9 @@
package main
import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
@ -27,6 +29,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"unicode"
@ -126,7 +129,10 @@ var (
seed []byte
)
const garbleMapHeaderName = "garble/nameMap"
const (
garbleMapHeaderName = "garble/nameMap"
garbleSrcHeaderName = "garble/src"
)
func saveListedPackages(w io.Writer, flags, patterns []string) error {
args := []string{"list", "-json", "-deps", "-export"}
@ -427,10 +433,6 @@ func mainErr(args []string) error {
"-trimpath",
"-toolexec=" + execPath,
}
if flagDebugDir != "" {
// TODO: don't make -debugdir force rebuilding all packages
goArgs = append(goArgs, "-a")
}
if cmd == "test" {
// vet is generally not useful on garbled code; keep it
// disabled by default.
@ -648,15 +650,6 @@ func transformCompile(args []string) ([]string, error) {
flags = flagSetValue(flags, "-trimpath", tempDir+"=>;"+trimpath)
// log.Println(flags)
pkgDebugDir := ""
if envGarbleDebugDir != "" {
osPkgPath := filepath.FromSlash(pkgPath)
pkgDebugDir = filepath.Join(envGarbleDebugDir, osPkgPath)
if err := os.MkdirAll(pkgDebugDir, 0o755); err != nil {
return nil, err
}
}
privateNameMap := make(map[string]string)
existingNames := collectNames(files)
packageCounter := 0
@ -676,6 +669,13 @@ func transformCompile(args []string) ([]string, error) {
files[i] = file
}
obfSrcArchive := &bytes.Buffer{}
obfSrcGzipWriter := gzip.NewWriter(obfSrcArchive)
defer obfSrcGzipWriter.Close()
obfSrcTarWriter := tar.NewWriter(obfSrcGzipWriter)
defer obfSrcTarWriter.Close()
// TODO: randomize the order and names of the files
newPaths := make([]string, 0, len(files))
for i, file := range files {
@ -719,17 +719,8 @@ func transformCompile(args []string) ([]string, error) {
}
defer tempFile.Close()
var printWriter io.Writer = tempFile
var debugFile *os.File
if pkgDebugDir != "" {
debugFile, err = os.Create(filepath.Join(pkgDebugDir, name))
if err != nil {
return nil, err
}
defer debugFile.Close()
printWriter = io.MultiWriter(tempFile, debugFile)
}
obfSrc := &bytes.Buffer{}
printWriter := io.MultiWriter(tempFile, obfSrc)
fileDetachedComments := detachedComments[i]
if len(fileDetachedComments) > 0 {
@ -745,42 +736,58 @@ func transformCompile(args []string) ([]string, error) {
if err := tempFile.Close(); err != nil {
return nil, err
}
debugFile.Close() // this is ok to error if no file is supplied
if err := obfSrcTarWriter.WriteHeader(&tar.Header{
Name: name,
Mode: 0o755,
ModTime: time.Now(), // Need for restore obfuscation time
Size: int64(obfSrc.Len()),
}); err != nil {
return nil, err
}
if _, err := obfSrcTarWriter.Write(obfSrc.Bytes()); err != nil {
return nil, err
}
newPaths = append(newPaths, tempFile.Name())
}
if len(privateNameMap) > 0 {
objPath := flagValue(flags, "-o")
deferred = append(deferred, func() error {
importCfg, err := goobj2.ParseImportCfg(buildInfo.importCfg)
if err != nil {
return err
}
objPath := flagValue(flags, "-o")
deferred = append(deferred, func() error {
importCfg, err := goobj2.ParseImportCfg(buildInfo.importCfg)
if err != nil {
return err
}
pkg, err := goobj2.Parse(objPath, pkgPath, importCfg)
if err != nil {
return err
}
pkg, err := goobj2.Parse(objPath, pkgPath, importCfg)
if err != nil {
return err
}
data, err := json.Marshal(privateNameMap)
if err != nil {
return err
}
data, err := json.Marshal(privateNameMap)
if err != nil {
return err
}
// Adding an extra archive header is safe,
// and shouldn't break other tools like the linker since our header name is unique
pkg.ArchiveMembers = append(pkg.ArchiveMembers, goobj2.ArchiveMember{
ArchiveHeader: goobj2.ArchiveHeader{
Name: garbleMapHeaderName,
Size: int64(len(data)),
Data: data,
},
})
return pkg.Write(objPath)
// Adding an extra archive header is safe,
// and shouldn't break other tools like the linker since our header name is unique
pkg.ArchiveMembers = append(pkg.ArchiveMembers, goobj2.ArchiveMember{
ArchiveHeader: goobj2.ArchiveHeader{
Name: garbleMapHeaderName,
Size: int64(len(data)),
Data: data,
},
}, goobj2.ArchiveMember{
ArchiveHeader: goobj2.ArchiveHeader{
Name: garbleSrcHeaderName,
Size: int64(obfSrcArchive.Len()),
Date: strconv.Itoa(obfSrcArchive.Len()), // Zero byte bug bypass
Data: obfSrcArchive.Bytes(),
},
})
}
return pkg.Write(objPath)
})
return append(flags, newPaths...), nil
}

Loading…
Cancel
Save