Files
go-obfuscation/cmd/packer/packer_test.go
T
lukaszraczylo 0cbba3a8ce Anti-RE depth: 10 new features, transformer bug fixes, Frida integration
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.
2026-06-02 00:43:08 +01:00

97 lines
2.4 KiB
Go

package main
import (
"bytes"
"encoding/hex"
"os"
"os/exec"
"path/filepath"
"testing"
)
func pack(t *testing.T, args ...string) (stdout, stderr string, exit int) {
t.Helper()
cmd := exec.Command("go", append([]string{"run", "."}, args...)...)
cmd.Dir = "."
var so, se bytes.Buffer
cmd.Stdout = &so
cmd.Stderr = &se
err := cmd.Run()
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
return so.String(), se.String(), ee.ExitCode()
}
return so.String(), se.String(), -1
}
return so.String(), se.String(), 0
}
func TestPackUnpackRoundtrip(t *testing.T) {
dir := t.TempDir()
inPath := filepath.Join(dir, "input.bin")
outPath := filepath.Join(dir, "packed.go")
stubOut := filepath.Join(dir, "decoded.bin")
payload := []byte("packer-mvp-roundtrip-\x00\x01\x02binary\xff")
if err := os.WriteFile(inPath, payload, 0o600); err != nil {
t.Fatal(err)
}
// Use a fixed key so the test is deterministic.
key := make([]byte, 32)
for i := range key {
key[i] = byte(i)
}
stdout, stderr, code := pack(t, "-in", inPath, "-out", outPath, "-key", hex.EncodeToString(key))
if code != 0 {
t.Fatalf("packer exit %d\nstdout: %s\nstderr: %s", code, stdout, stderr)
}
// Run the generated stub with go run, capturing stdout.
run := exec.Command("go", "run", outPath)
var runOut, runErr bytes.Buffer
run.Stdout = &runOut
run.Stderr = &runErr
if err := run.Run(); err != nil {
t.Fatalf("stub run failed: %v\nstderr: %s", err, runErr.String())
}
_ = stubOut
if !bytes.Equal(runOut.Bytes(), payload) {
t.Fatalf("decoded mismatch:\n got %x\nwant %x", runOut.Bytes(), payload)
}
}
func TestPackInvalidKey(t *testing.T) {
dir := t.TempDir()
inPath := filepath.Join(dir, "input.bin")
outPath := filepath.Join(dir, "packed.go")
if err := os.WriteFile(inPath, []byte("x"), 0o600); err != nil {
t.Fatal(err)
}
// Non-hex string.
_, _, code := pack(t, "-in", inPath, "-out", outPath, "-key", "zzznothex")
if code == 0 {
t.Fatal("expected non-zero exit for invalid hex key")
}
// Valid hex, wrong length.
_, _, code = pack(t, "-in", inPath, "-out", outPath, "-key", "deadbeef")
if code == 0 {
t.Fatal("expected non-zero exit for wrong-length key")
}
}
func TestPackMissingFlags(t *testing.T) {
_, _, code := pack(t)
if code == 0 {
t.Fatal("expected non-zero exit when -in/-out missing")
}
_, _, code = pack(t, "-in", "x")
if code == 0 {
t.Fatal("expected non-zero exit when -out missing")
}
}