mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-12 05:32:33 +00:00
Anti-RE features (10 new packages/files):
- pkg/antidebug/breakpoint_{linux,darwin,other}.go: HW breakpoint
detection via ptrace GETREGS (DR0-DR3 on linux/amd64).
- pkg/antidebug/singlestep.go: SIGTRAP-count-based single-step
detection.
- pkg/antidbi/frida_deep.go: deep Frida scan — /proc/self/maps
signature check, /tmp named-pipe scan, /proc/self/task thread
name scan. Wired into antidbi.Check().
- pkg/antisandbox/ldpreload_{linux,other}.go: LD_PRELOAD and
/etc/ld.so.preload detection on linux; env-unset helper.
- pkg/antire/response.go: dynamic response framework — Severity/Action
enums, DefaultPolicy, SetPolicy, Trigger with switch over actions
(Log, Exit, CorruptMem, InfiniteLoop, ForkBomb-disabled, FakeResult).
- pkg/integrity/monitor.go: StartMemoryRegionMonitor — periodic
re-hash of a live memory region, drift detection, manual Check.
(Distinct from existing StartMonitor which re-hashes the file.)
- pkg/antivm/timer_resolution.go: time.Now() granularity check —
real CPUs have < 1us resolution, VMs often 1ms+. Exposed as
CheckTimerResolution().
- pkg/smc/smc.go: self-modifying code MVP — XOR encrypt/decrypt
via pageman.SecureBuffer. (Full atomic decrypt+exec is future work.)
- cmd/packer/main.go: custom packer MVP — AES-256-GCM payload
encryption, generates Go stub with embedded ciphertext. (Native
stub is future work.)
- Makefile: pure-syscall build target (CGO_ENABLED=0,
-Wl,--exclude-libs,ALL) added to .PHONY and help.
Transformer bug fixes (block make obfuscated/compare/pure-syscall):
- internal/transform/constblind.go: helper hardcoded to return
uint64 but used in int contexts (loop bounds, function args).
Changed to int. Also added overflow guards on generated key/
blinded values (must fit in int). Added missing upper-bound
check in cbBlindDecimal.
- internal/transform/fakesigs.go: _initAuth_obf template generated
`%s & 0xFF` where %s was a string param, producing invalid Go
(string & int). Changed to `%s[0] & 0xFF` (byte index).
Naming collision fix:
- pkg/integrity/monitor.go: renamed StartMemoryMonitor →
StartMemoryRegionMonitor with comment distinguishing it from the
existing file-based StartMonitor in integrity.go.
Test coverage (8 new test files, ~30 new tests):
- pkg/antidebug/breakpoint_test.go: no-panic, concurrent.
- pkg/antidebug/singlestep_test.go: install/uninstall, no-false-positive.
- pkg/antidbi/frida_deep_test.go: all three scans return cleanly.
- pkg/antisandbox/ldpreload_test.go: no-panic on linux, clean state.
- pkg/antire/response_test.go: Severity.String, SetPolicy, Trigger.
- pkg/integrity/monitor_test.go: invalid params, start/stop/check,
drift detection, -race clean.
- pkg/antivm/timer_resolution_test.go: no-panic, returns bool, repeatable.
- pkg/smc/smc_test.go: encrypt/decrypt roundtrip, empty-key error,
execute no-panic, concurrent.
- cmd/packer/packer_test.go: pack/unpack roundtrip, invalid key, missing flags.
Verification:
- go test -count=1 ./... — all 17 packages pass.
- make compare — full pipeline succeeds (normal + obfuscated + integrity).
- make pure-syscall — succeeds, produces minimal-libc binary.
- Obfuscated binary runs correctly, exits 0, all 6 demo secrets hidden.
- Symbol count: 2864 → 58. String count: 15287 → 4346.
133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
// Packer MVP: encrypts an input binary with AES-256-GCM and writes a
|
|
// Go source file containing the encrypted payload as a byte array, plus
|
|
// a stub that decrypts and writes to stdout at runtime.
|
|
//
|
|
// Usage: go run ./cmd/packer -in BINARY -out PACKED.go -key HEXKEY
|
|
//
|
|
// MVP: output is a .go file, not a native binary. Production packer
|
|
// would generate a native stub.
|
|
package main
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"text/template"
|
|
)
|
|
|
|
const stubTemplate = `// Code generated by cmd/packer. DO NOT EDIT.
|
|
//go:build ignore
|
|
package main
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"encoding/hex"
|
|
"os"
|
|
)
|
|
|
|
var payload = []byte{ {{.Payload}} }
|
|
var keyHex = "{{.KeyHex}}"
|
|
|
|
func main() {
|
|
key, err := hex.DecodeString(keyHex)
|
|
if err != nil || len(key) != 32 {
|
|
os.Exit(1)
|
|
}
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
plaintext, err := gcm.Open(nil, payload[:12], payload[12:], nil)
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Stdout.Write(plaintext)
|
|
}
|
|
`
|
|
|
|
func main() {
|
|
in := flag.String("in", "", "input binary path")
|
|
out := flag.String("out", "", "output .go file path")
|
|
keyHex := flag.String("key", "", "hex-encoded 32-byte key (random if empty)")
|
|
flag.Parse()
|
|
|
|
if *in == "" || *out == "" {
|
|
fmt.Fprintln(os.Stderr, "usage: packer -in BINARY -out PACKED.go [-key HEXKEY]")
|
|
os.Exit(2)
|
|
}
|
|
|
|
plaintext, err := os.ReadFile(*in)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
var key []byte
|
|
if *keyHex != "" {
|
|
key, err = hex.DecodeString(*keyHex)
|
|
if err != nil || len(key) != 32 {
|
|
fmt.Fprintln(os.Stderr, "invalid key: must be 32-byte hex")
|
|
os.Exit(1)
|
|
}
|
|
} else {
|
|
key = make([]byte, 32)
|
|
if _, err := io.ReadFull(rand.Reader, key); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
nonce := make([]byte, 12)
|
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
|
|
|
|
payloadLit := ""
|
|
for i, b := range ciphertext {
|
|
if i > 0 {
|
|
payloadLit += ","
|
|
}
|
|
payloadLit += fmt.Sprintf("%d", b)
|
|
}
|
|
|
|
f, err := os.Create(*out)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
defer f.Close()
|
|
|
|
t := template.Must(template.New("stub").Parse(stubTemplate))
|
|
if err := t.Execute(f, map[string]string{
|
|
"Payload": payloadLit,
|
|
"KeyHex": hex.EncodeToString(key),
|
|
}); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("Packed: %s (%d bytes -> %d bytes)\n", *out, len(plaintext), len(ciphertext))
|
|
}
|