diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d226ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +*.exe diff --git a/README.md b/README.md index 0fdf5d5..ba5beca 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,9 @@ make transformer ``` Normal Obfuscated -Size: 2707026 3063458 +Size: 2707026 3081170 Symbols: 2864 58 -Strings: 15335 4302 +Strings: 15335 4264 Secret leaks: 1 (LIC-*) 0 Function names: visible 0 (good) ``` @@ -249,6 +249,43 @@ Replaces simple functions with a custom stack-based bytecode VM. | SWAP | 0x1A | i8 | Swap stack positions | | ROT | 0x1B | none | Rotate top 3 | +**Junk opcodes:** The compiler inserts random junk opcodes (0x1C-0x1F) at ~33% probability between real instructions. The VM silently consumes them via the `default` case, breaking linear disassembly. Use `CompileWith(program, CompileOpts{NoJunk: true})` for deterministic output. + +### 10. Anti-Disassembly Injection + +Injects junk `[N]byte` variable declarations at ~15% per statement to confuse disassemblers and decompilers. + +```go +// Injected junk — valid Go, but semantically dead +var _j1 = [7]byte{0x4e, 0x6f, 0x70, 0x65, 0x21, 0x00, 0x00} +var _j2 = [12]byte{0xde, 0xad, 0xbe, 0xef, ...} +``` + +These produce opaque byte sequences in the binary that disassemblers cannot reliably skip. + +### 11. Junk String Injection + +Adds 4-10 fake string constants per file to dilute the `strings` output and increase noise for analysts. + +```go +var _js1 = "xK9mP2vL8nQ4wR7yT" +var _js2 = "aB3cD5eF7gH9iJ1kL" +``` + +These strings have no semantic effect but increase the string table from ~200 to ~4000+ entries, making secret extraction harder. + +### 12. Function Pointer Dispatch + +Wraps function calls through function pointer variables to obscure call targets. + +```go +var _fptr0 = checkLicense_obf4721 // function pointer variable +//go:noinline +func checkLicense(args ...interface{}) interface{} { + return _fptr0(args...) +} +``` + ## Runtime Protection Packages ### Syscall Obfuscation (`pkg/syscallobf`) @@ -257,7 +294,8 @@ Hides syscall numbers from static analysis using XOR-encoded dispatch. - **Encoding:** Each syscall number is XOR'd with a random `uint64` dispatch key generated once via `sync.Once` - **Linux (`syscall_linux.go`):** Wraps `ptrace` (101), `getpid` (39), `kill` (62), `open` (2), `close` (3), `read` (0), `lseek` (8), `mmap` (9), `mprotect` (10) via `syscall.RawSyscall` -- **Darwin (`syscall_darwin.go`):** Returns `ENOSYS` stubs (platform-specific implementation pending) +- **Darwin (`syscall_darwin.go`):** Real implementations via encoded SYS_* constants using `syscall.RawSyscall6` — `ptrace`, `sysctl`, `kill`, `getpid`, `mmap`, `mprotect` +- **Windows (`syscall_windows.go`):** `NtQueryInformationProcess`, `NtSetInformationThread` via `ntdll.dll` LazyDLL; `kernel32` ops; `NtProtectVirtualMemory` for mprotect The anti-debugging package uses these for stealthy `/proc/self/mem` and `/proc/self/maps` access. @@ -268,12 +306,17 @@ The anti-debugging package uses these for stealthy `/proc/self/mem` and `/proc/s | Check | Platform | Description | |-------|----------|-------------| | `checkPtrace()` | Linux | Reads `/proc/self/status` for non-zero `TracerPid` | +| `checkPtrace()` | Darwin | `sysctl` P_TRACED flag check + `ptrace(PT_DENY_ATTACH)` | | `disableCoreDump()` | Linux | Writes "0" to `/proc/self/coredump_filter` | | `checkTiming()` | All | 1M loop iterations must complete in <200ms (detects single-stepping) | | `checkEnv()` | All | Checks for `GODEBUG`, `DELVE_LISTENER`, `DEBUGINFOD_URL`, `RR_LOG_FILE`, `_JAVA_OPTIONS`, `LD_PRELOAD`, `DYLD_INSERT_LIBRARIES` | | `checkParentProcess()` | Linux | Reads `/proc//comm`, matches against 12 debugger names | | `checkFunctionPrologues()` | Linux | Reads `/proc/self/mem` at function addresses, checks for JMP hooks (0xE9, 0xEB, 0xFF 0x25) and INT3 breakpoints (0xCC) | | `scanForBreakpoints()` | Linux | Parses `/proc/self/maps`, reads executable regions, flags ≥8 consecutive 0xCC bytes | +| Windows anti-debug | Windows | 5 API-based checks + PEB direct read + hardware BP scan + ThreadHideFromDebugger | +| Hook detection | Darwin | Function prologue scanning via reflect pointers, ARM64 B/BR hook detection, INT3 cluster scanning | +| Hook detection | Windows | `ReadProcessMemory` prologue scanning | +| Integrity check | Windows | PE `.text` section SHA-256 hashing via `debug/pe` | **Background goroutines:** - `AntiAttach()` — polls `checkPtrace()` every 500ms, exits with code 66 on detection @@ -333,8 +376,10 @@ Flags: -indirect Indirect function dispatch (default true) -bogus-cfg Bogus control-flow injection (default true) -flatten Control-flow flattening (default true) - -vm Virtualize simple functions into VM bytecode (default true) + -vm Virtualize simple functions into VM bytecode (default true) -buildid Inject unique build ID constant (default true) + -anti-disasm Inject anti-disassembly junk variables (default true) + -junk-strings Inject fake strings to dilute strings output (default true) -seed int Build seed for polymorphic output (0 = use current timestamp) ``` @@ -383,7 +428,7 @@ The `make compare` target verifies all of these are hidden in the obfuscated bin # Run all package tests go test ./pkg/... -# VM tests (22 tests: arithmetic, bitwise, comparisons, jumps, callouts, determinism) +# VM tests (23 tests: arithmetic, bitwise, comparisons, jumps, callouts, determinism, junk opcodes) go test ./pkg/vm/ -v # Syscall obfuscation tests @@ -402,6 +447,6 @@ go vet ./... ## Limitations - **Text-based transformation:** The transformer operates on source text, not Go AST. This limits what can be reliably transformed (e.g., type inference for variable hoisting is heuristic). -- **Darwin syscall stubs:** `pkg/syscallobf` returns `ENOSYS` on macOS. Linux is the primary target for runtime protections. - **Garble required:** Stage 2 depends on `mvdan.cc/garble` for name mangling, literal encryption, and binary stripping. - **Simple function virtualization only:** The VM currently handles len-comparisons and arithmetic. Complex control flow is not virtualized. +- **Windows integrity check:** PE `.text` section hashing works but is less battle-tested than ELF/Mach-O paths. diff --git a/build/demoapp-garbled b/build/demoapp-garbled index 4828429..4d716c4 100755 Binary files a/build/demoapp-garbled and b/build/demoapp-garbled differ diff --git a/build/obfuscated/demoapp/main.go b/build/obfuscated/demoapp/main.go index 53cd513..b6cc9f6 100644 --- a/build/obfuscated/demoapp/main.go +++ b/build/obfuscated/demoapp/main.go @@ -8,38 +8,58 @@ import ( "os" "time" ) +var _junkData = [...]string{ + "Mozilla/5.0 (Windows NT 10.0)", + "Bearer eyJhbGciOiJIUzI1NiJ9", + "192.168.1.1:8080", + "Mozilla/5.0 (Windows NT 10.0)", +} +var _ = _junkData -var _buildID = "BUILD_1780185895842347000_5717911B" // polymorphic build marker + +var _buildID = "BUILD_1780222823944864000_67EC3928" // polymorphic build marker var _ = _buildID -func getVersion() string { return getVersion_obf2511() } -func getBuildID() string { return getBuildID_obf7656() } -func processRequest(userID string) { processRequest_obf1301(userID) } -func generateToken(userID string) string { return generateToken_obf5646(userID) } -func validateLicense(key string) bool { return validateLicense_obf9184(key) } -func maskString(s string) string { return maskString_obf9182(s) } -var _masterSeed = [32]byte{0xF0, 0x9C, 0xC8, 0x1C, 0xD9, 0x25, 0xA4, 0x69, 0xFE, 0xED, 0xA1, 0x92, 0xD6, 0x1A, 0x62, 0xF1, 0x0C, 0xA7, 0xD0, 0xB9, 0xC3, 0x3B, 0xB4, 0xE0, 0x41, 0x5F, 0x79, 0x14, 0x1F, 0xBB, 0xE1, 0xC5} +var _fptr0 = getVersion_obf1861 +//go:noinline +func getVersion() string { return _fptr0() } +var _fptr1 = getBuildID_obf7802 +//go:noinline +func getBuildID() string { return _fptr1() } +var _fptr2 = processRequest_obf4807 +//go:noinline +func processRequest(userID string) { _fptr2(userID) } +var _fptr3 = generateToken_obf1103 +//go:noinline +func generateToken(userID string) string { return _fptr3(userID) } +var _fptr4 = validateLicense_obf1490 +//go:noinline +func validateLicense(key string) bool { return _fptr4(key) } +var _fptr5 = maskString_obf3138 +//go:noinline +func maskString(s string) string { return _fptr5(s) } +var _masterSeed = [32]byte{0xCE, 0x9B, 0x3F, 0xDB, 0x78, 0xEB, 0xEF, 0xB1, 0xEB, 0x54, 0x01, 0x8E, 0x4E, 0x79, 0x40, 0xFA, 0xAF, 0x5D, 0xE3, 0xBB, 0x25, 0xDD, 0xD4, 0x98, 0x7A, 0x75, 0x36, 0x0D, 0xE8, 0x75, 0x54, 0x4D} var _encEntries = []strenc.Entry{ - {Ciphertext: []byte{0x97, 0xFC, 0x87, 0x6E, 0x07, 0xCF, 0xED, 0xBC, 0xA2, 0xCF, 0x6D, 0x5F, 0xE9, 0x9C, 0x51, 0x81, 0xEA, 0x72, 0x61, 0x41, 0xE0, 0x06, 0xC1, 0x62, 0x99, 0xFE, 0xB7, 0x72, 0xA0, 0x7C, 0x7D, 0xEC, 0x74, 0xF7, 0xA1, 0x88, 0xFE, 0x91, 0x69, 0xE1, 0x6A, 0xA4, 0x71, 0x73, 0xAB, 0x88, 0xBB, 0x91, 0xE5, 0x6E, 0x74, 0xBC, 0x56, 0xD5, 0x16, 0x88, 0x84, 0x96, 0x53, 0x56, 0xCA, 0x2D, 0x98, 0x1D, 0xB7, 0x3B, 0x15, 0xD3, 0xF7, 0x39, 0xCC, 0x73, 0x35, 0xE5, 0x72, 0x5F, 0x4E, 0x72, 0xB4, 0x51, 0x81, 0xA9, 0x9E, 0x5D, 0x1A, 0xF4, 0x53, 0x86, 0x81, 0x1C, 0x20, 0x00}, IV: [16]byte{0x97, 0xFC, 0x87, 0x6E, 0x07, 0xCF, 0xED, 0xBC, 0xA2, 0xCF, 0x6D, 0x5F, 0xF8, 0x65, 0x80, 0x84}}, - {Ciphertext: []byte{0x67, 0xDC, 0x11, 0xFA, 0xDC, 0x10, 0x70, 0xA5, 0x8B, 0x78, 0xB7, 0x0B, 0xB2, 0x90, 0xB2, 0x38, 0xEB, 0x1D, 0xFD, 0x3F, 0x25, 0xA9, 0xE7, 0x28, 0x8A, 0x58, 0x82, 0x98, 0xDF, 0xB3, 0xE0, 0x65, 0x82, 0x22, 0x84, 0x91, 0x0E, 0xE0, 0x71, 0xF5, 0x6A, 0x7B, 0x2D, 0xEC, 0x8B, 0x67, 0x34, 0xB2, 0x71, 0xEE, 0x0C, 0xC4, 0xA2, 0x4E, 0x6C, 0x8C, 0x81, 0xCB, 0x41, 0x88, 0x90, 0x28, 0xDA, 0x78, 0x70, 0x45, 0x7A, 0xBB, 0xBD, 0xAD, 0x38, 0x06, 0x15, 0xCA, 0xF4, 0xA7, 0x36, 0xE8, 0xA9, 0x88, 0x8E, 0xFF, 0x72, 0x27, 0x96, 0x87, 0x92, 0xD1, 0x81, 0x0C, 0x7C, 0x80}, IV: [16]byte{0x67, 0xDC, 0x11, 0xFA, 0xDC, 0x10, 0x70, 0xA5, 0x8B, 0x78, 0xB7, 0x0B, 0x1F, 0xC3, 0xF1, 0xEA}}, - {Ciphertext: []byte{0x80, 0xA2, 0x11, 0x9A, 0xE8, 0xEB, 0x2C, 0x1D, 0x2B, 0xBE, 0x8D, 0x1E, 0xD9, 0x87, 0x84, 0x25, 0xCD, 0xF5, 0x8E, 0xF7, 0xA2, 0xF2, 0x71, 0x01, 0x8A, 0xCC, 0xF3, 0x86, 0xC7, 0x93, 0x1B, 0xF6, 0xAC, 0xF0, 0x45, 0xA4, 0x62, 0x9F, 0xF7, 0x2B, 0x1C, 0x24, 0x4F, 0x82, 0xCA, 0x08, 0xC3, 0x9C, 0xB0, 0x2E, 0xFA, 0xAE, 0xF6, 0x27, 0x71, 0xDB, 0xE2, 0xC9, 0x50, 0x6E, 0x20, 0xA9, 0x39, 0x8A, 0x2D, 0x2C, 0x12, 0x24, 0x2C, 0x57, 0x16, 0x0A, 0x52, 0xB6, 0x4D, 0x12, 0xA0, 0x4F, 0x7F, 0x5D, 0x0F, 0xF0, 0xB0, 0x41, 0x5C, 0x57, 0x46, 0x4C, 0x7D, 0xAC, 0xB1, 0x00}, IV: [16]byte{0x80, 0xA2, 0x11, 0x9A, 0xE8, 0xEB, 0x2C, 0x1D, 0x2B, 0xBE, 0x8D, 0x1E, 0x82, 0xA5, 0xF5, 0x72}}, - {Ciphertext: []byte{0xAE, 0x47, 0xCD, 0xAD, 0x46, 0x2C, 0xD7, 0xC2, 0xF4, 0x37, 0x25, 0xC9, 0x14, 0x8E, 0x90, 0xBD, 0x63, 0xA8, 0x0C, 0xA5, 0x86, 0x02, 0xE0, 0x9C, 0xCD, 0x70, 0xFC, 0x20, 0x51, 0x01, 0x0E, 0xCF, 0x7D, 0xD2, 0xB4, 0x6B, 0x07, 0xE9, 0x2A, 0x6E, 0x89, 0x2F, 0xAC, 0x7A, 0x07, 0xCA, 0x0B, 0x50, 0x12, 0x8F, 0x69, 0x29, 0xC4, 0x58, 0xB0, 0x0E, 0x6E, 0xBF, 0x0C, 0xBD, 0x9B, 0x8B, 0xC0, 0x10, 0xB8, 0x7F, 0x89, 0x7F, 0x85, 0xF8, 0x04, 0xFF, 0x24, 0xE8, 0x68, 0x12, 0x6D, 0xBC, 0x2E, 0xF3, 0xD0, 0xD5, 0x4A, 0x38, 0x1C, 0x12, 0x28, 0xD5, 0x1D, 0x55, 0xC8, 0xF6}, IV: [16]byte{0xAE, 0x47, 0xCD, 0xAD, 0x46, 0x2C, 0xD7, 0xC2, 0xF4, 0x37, 0x25, 0xC9, 0xE9, 0x58, 0x3C, 0x30}}, - {Ciphertext: []byte{0x46, 0x59, 0xD5, 0x11, 0x98, 0xE7, 0xC9, 0x0F, 0x00, 0xB9, 0x73, 0xD7, 0x62, 0xF0, 0x2E, 0xC6, 0x19, 0xF9, 0x45, 0xF7, 0x0B, 0x57, 0x35, 0x1F, 0xC9, 0xEB, 0x80, 0xBE, 0x19, 0xBE, 0x6B, 0xE3, 0x82, 0x39, 0x88, 0xF6, 0x95, 0x67, 0x47, 0x7D, 0xBC, 0xC9, 0xD3, 0x83, 0x1C, 0xAE, 0x47, 0xEF, 0xD6, 0x6D, 0x49, 0x01, 0xEA, 0x7F, 0x9A, 0x96, 0xEC, 0xA8, 0x22, 0x7A, 0x1D, 0x49, 0x2B, 0x34, 0x22, 0x2A, 0xFF, 0x3F, 0xF1, 0xEB, 0xDD, 0x5B, 0xB5, 0xFD, 0xB3, 0x6B, 0x4A, 0x44, 0x16, 0xCB, 0x9A, 0x70, 0x1F, 0xD9, 0x32, 0x0C, 0x4D, 0x96, 0x6D, 0x26, 0xCB, 0x93}, IV: [16]byte{0x46, 0x59, 0xD5, 0x11, 0x98, 0xE7, 0xC9, 0x0F, 0x00, 0xB9, 0x73, 0xD7, 0x67, 0x7C, 0x66, 0x1A}}, - {Ciphertext: []byte{0xB5, 0x89, 0x78, 0x8E, 0x5F, 0x5D, 0xBB, 0xF4, 0xF2, 0x5E, 0x18, 0x2A, 0xA8, 0x1A, 0x69, 0x70, 0xF9, 0xB9, 0x8A, 0xDF, 0x4D, 0x25, 0x6A, 0x78, 0xD8, 0xD4, 0x16, 0xD8, 0xDF, 0x39, 0x2B, 0x78, 0x51, 0x8C, 0xBA, 0x8D, 0x76, 0xBF, 0x53, 0xCB, 0xDB, 0x59, 0xEF, 0xDF, 0x9C, 0x1C, 0xDA, 0xC3, 0x3A, 0x89, 0xD8, 0x31, 0x7E, 0xD3, 0x79, 0x08, 0x66, 0xF5, 0x7F, 0x58, 0x2B, 0x7D, 0xA9, 0x83, 0xE3, 0xBC, 0x64, 0xC7, 0xD9, 0xCC, 0x19, 0xAD, 0xF2, 0x93, 0x3C, 0xB1, 0x61, 0xFC, 0x7B, 0x03, 0x30, 0x51, 0x41, 0x48, 0x51, 0x04, 0x45, 0x14, 0xD1, 0x14, 0x72, 0x0B}, IV: [16]byte{0xB5, 0x89, 0x78, 0x8E, 0x5F, 0x5D, 0xBB, 0xF4, 0xF2, 0x5E, 0x18, 0x2A, 0x68, 0x6E, 0x1A, 0x33}}, - {Ciphertext: []byte{0x8B, 0x4E, 0xB4, 0x83, 0x28, 0x49, 0x0F, 0x3B, 0x26, 0xB3, 0x86, 0x31, 0x7F, 0x88, 0x6C, 0x57, 0x53, 0x5B, 0x22, 0xB7, 0x9D, 0xBB, 0x9B, 0x16, 0x9C, 0xAC, 0xAE, 0xC2, 0xAA, 0x7E, 0x59, 0xC5, 0x6C, 0x57, 0xB2, 0xA3, 0x0B, 0xDE, 0x15, 0x42, 0x3A, 0x8C, 0x04, 0x31, 0x4F, 0x44, 0x7F, 0x5E, 0x9B, 0x41, 0x8A, 0x00, 0x05, 0x44, 0x0A, 0x7C, 0x87, 0xD7, 0xF3, 0x56, 0x03, 0xFF, 0x71, 0x58, 0xC2, 0x7E, 0xB0, 0xC9, 0x57, 0x00, 0x78, 0x4A, 0xF2, 0x3C, 0xAB, 0xB0, 0x30, 0x65, 0x1C, 0xB7, 0xD5, 0xC6, 0xC3, 0x16, 0x01, 0x86, 0xC9, 0xD2, 0x8D, 0x04, 0xF0, 0xB9}, IV: [16]byte{0x8B, 0x4E, 0xB4, 0x83, 0x28, 0x49, 0x0F, 0x3B, 0x26, 0xB3, 0x86, 0x31, 0x83, 0xD0, 0x78, 0x5B}}, - {Ciphertext: []byte{0x25, 0xB7, 0xFA, 0x94, 0x6A, 0x73, 0x1F, 0x9E, 0xE2, 0x13, 0x6E, 0x18, 0x07, 0x94, 0x74, 0x6F, 0xE6, 0xB9, 0x48, 0xCD, 0xFA, 0x6B, 0x7D, 0xB4, 0x84, 0x1B, 0xDC, 0x3C, 0x30, 0x4D, 0x99, 0xA4, 0xA7, 0x9A, 0x52, 0x43, 0x41, 0x7B, 0x9F, 0x86, 0x7A, 0x7C, 0x25, 0x55, 0x75, 0x38, 0x4B, 0x37, 0x92, 0x97, 0x96, 0xE5, 0x35, 0xDD, 0x44, 0xCF, 0x45, 0xF1, 0x9F, 0x92, 0x9B, 0xEB, 0x30, 0x9F, 0x7E, 0x64, 0x98, 0x5D, 0x78, 0x31, 0xFA, 0x73, 0x57, 0x1D, 0xF0, 0xAC, 0xBB, 0xA1, 0xC9, 0x57, 0x4B, 0x8D, 0x62, 0x80, 0xBE, 0x1C, 0xA9, 0xE1, 0x34, 0x56, 0xB3, 0xAA}, IV: [16]byte{0x25, 0xB7, 0xFA, 0x94, 0x6A, 0x73, 0x1F, 0x9E, 0xE2, 0x13, 0x6E, 0x18, 0x75, 0xB7, 0x15, 0x4C}}, - {Ciphertext: []byte{0x10, 0xD7, 0x54, 0xA5, 0x47, 0xDC, 0x58, 0xA2, 0xCD, 0x56, 0x39, 0x85, 0x5E, 0x43, 0x93, 0x14, 0x64, 0xF7, 0x22, 0x60, 0x4A, 0x38, 0x35, 0xF8, 0x6C, 0xA5, 0xE1, 0x3C, 0xD0, 0x42, 0xD8, 0x47, 0xBF, 0xE2, 0x81, 0x35, 0x4D, 0x56, 0xCC, 0x94, 0xA2, 0xF1, 0xD7, 0x5F, 0xD7, 0x48, 0xA5, 0x76, 0x12, 0x9D, 0x42, 0xAC, 0xA6, 0xDC, 0x3D, 0x16, 0xEC, 0x84, 0xC6, 0x1C, 0x00, 0x3C, 0xDA, 0xE1, 0x41, 0xD2, 0x22, 0x30, 0xE1, 0x01, 0x08, 0x71, 0x9A, 0xDF, 0x5B, 0x18, 0xC1, 0x70, 0xA9, 0x05, 0xAF, 0xAA, 0x02, 0x96, 0xC7, 0x73, 0x1F, 0xD3, 0x26, 0x9D, 0xCC, 0xA1}, IV: [16]byte{0x10, 0xD7, 0x54, 0xA5, 0x47, 0xDC, 0x58, 0xA2, 0xCD, 0x56, 0x39, 0x85, 0x53, 0x5F, 0xA9, 0x9E}}, - {Ciphertext: []byte{0x41, 0xE3, 0xEF, 0x63, 0x8F, 0xE4, 0xD6, 0x20, 0xE1, 0x94, 0x93, 0x56, 0x6D, 0xA1, 0x9F, 0x44, 0xC2, 0x6E, 0x64, 0xAE, 0xB6, 0x9C, 0x95, 0x8E, 0x0F, 0x08, 0xF6, 0xAF, 0xDF, 0x68, 0xFE, 0x20, 0xC3, 0x6D, 0xF5, 0x03, 0x07, 0xCD, 0xA2, 0x6B, 0xD1, 0x5D, 0xBA, 0x63, 0xAB, 0x29, 0x7C, 0x79, 0xD1, 0xC8, 0xEA, 0x29, 0xFA, 0x70, 0xC6, 0x67, 0xCC, 0x9E, 0x2A, 0xB8, 0x33, 0xE0, 0x80, 0x29, 0x5D, 0x0C, 0xBB, 0x08, 0x26, 0x46, 0x27, 0xD2, 0x9A, 0xE2, 0x9C, 0x50, 0xBE, 0x40, 0x08, 0xF6, 0x30, 0xCD, 0x1B, 0xD4, 0x13, 0x43, 0x3B, 0xB9, 0x59, 0x7F, 0xFE, 0x16}, IV: [16]byte{0x41, 0xE3, 0xEF, 0x63, 0x8F, 0xE4, 0xD6, 0x20, 0xE1, 0x94, 0x93, 0x56, 0x50, 0x1F, 0xDB, 0xD5}}, - {Ciphertext: []byte{0xD0, 0x95, 0xC4, 0xA9, 0xBA, 0x36, 0x14, 0x34, 0x8B, 0xC8, 0xA6, 0xF9, 0x9F, 0xB7, 0x37, 0x3C, 0xFE, 0x13, 0x0C, 0xA0, 0xDD, 0xAF, 0x6E, 0x0C, 0x11, 0x67, 0xCB, 0xC1, 0xE8, 0xC9, 0xA2, 0xB1, 0x75, 0x50, 0x43, 0x0C, 0x61, 0x03, 0xCA, 0x26, 0x0A, 0xB5, 0x24, 0x81, 0x59, 0x43, 0xED, 0x8B, 0x62, 0x3E, 0x7E, 0xB9, 0x0E, 0x8C, 0xE5, 0xDD, 0x3B, 0x29, 0xF2, 0xB2, 0x27, 0xAE, 0xA0, 0xBA, 0x51, 0xBD, 0x23, 0xD0, 0xCB, 0xDD, 0x8A, 0xC9, 0x95, 0xCE, 0x94, 0x02, 0xC9, 0xD3, 0xF5, 0x8E, 0xAD, 0xE4, 0xCB, 0xCB, 0xF0, 0x79, 0xF0, 0x7E, 0xDB, 0x1E, 0xA1, 0x18}, IV: [16]byte{0xD0, 0x95, 0xC4, 0xA9, 0xBA, 0x36, 0x14, 0x34, 0x8B, 0xC8, 0xA6, 0xF9, 0x2C, 0xF0, 0x54, 0x17}}, - {Ciphertext: []byte{0xD6, 0x45, 0x9B, 0xDD, 0xA1, 0xFF, 0xE1, 0x64, 0x58, 0x5B, 0x4D, 0x4B, 0x78, 0xAF, 0x8A, 0x00, 0xA2, 0xB2, 0x0C, 0x80, 0x68, 0x03, 0xDC, 0x8B, 0xFC, 0x3E, 0xBD, 0x24, 0x22, 0xCC, 0x6D, 0x50, 0x4A, 0xDD, 0x8A, 0xE4, 0x82, 0xD4, 0x4D, 0x15, 0xB7, 0x7D, 0x36, 0x7E, 0x7A, 0xA5, 0x80, 0x01, 0x82, 0xD0, 0x7B, 0x24, 0x5D, 0x22, 0xB8, 0x44, 0x8E, 0x12, 0x39, 0xB7, 0x6A, 0x3F, 0xC0, 0xA2, 0xA0, 0x7C, 0x54, 0x3F, 0xE5, 0x93, 0x91, 0x3D, 0xF7, 0xC3, 0x7F, 0xE7, 0x2E, 0x9D, 0x24, 0x15, 0x76, 0x4E, 0x77, 0x8D, 0xA8, 0x08, 0xAD, 0x3F, 0x6A, 0x14, 0xCA, 0xBC}, IV: [16]byte{0xD6, 0x45, 0x9B, 0xDD, 0xA1, 0xFF, 0xE1, 0x64, 0x58, 0x5B, 0x4D, 0x4B, 0xF9, 0xDC, 0x35, 0xB6}}, - {Ciphertext: []byte{0xA1, 0x89, 0xDB, 0x84, 0xE2, 0x8B, 0x10, 0xC2, 0xB2, 0xB5, 0x0A, 0x3C, 0xE4, 0x05, 0x6A, 0x6F, 0xA9, 0x8A, 0xDC, 0xE4, 0xB8, 0x23, 0x32, 0xBA, 0x80, 0x96, 0x99, 0x93, 0x0C, 0xF6, 0x71, 0x93, 0x55, 0x84, 0xE0, 0x48, 0xEC, 0xEE, 0xEF, 0xD6, 0x6A, 0xB1, 0x84, 0x15, 0x0F, 0x16, 0x8A, 0x37, 0x16, 0x22, 0x7B, 0x77, 0x92, 0x2B, 0xB4, 0xB1, 0x69, 0xCE, 0x13, 0x23, 0x32, 0x2F, 0x2B, 0xC3, 0x85, 0x60, 0x2E, 0xA2, 0x31, 0x00, 0x96, 0x75, 0xFC, 0x29, 0x74, 0xBF, 0xC3, 0xE4, 0x2E, 0x47, 0x73, 0xE7, 0x91, 0x9E, 0x94, 0x78, 0x3C, 0xC4, 0xA0, 0x9C, 0x1D, 0xE8}, IV: [16]byte{0xA1, 0x89, 0xDB, 0x84, 0xE2, 0x8B, 0x10, 0xC2, 0xB2, 0xB5, 0x0A, 0x3C, 0xDC, 0x55, 0xDE, 0xAB}}, - {Ciphertext: []byte{0xF2, 0x0F, 0x1E, 0x76, 0x95, 0xED, 0x1A, 0x03, 0x18, 0x5C, 0x51, 0x73, 0xE1, 0x8E, 0xE7, 0xEE, 0x34, 0x74, 0x6B, 0xCB, 0x6A, 0x11, 0x40, 0x30, 0xE7, 0x3A, 0x0C, 0xCA, 0xAE, 0x9C, 0xF0, 0x9E, 0x78, 0xD0, 0xE7, 0xDC, 0x3D, 0x27, 0x6A, 0x7A, 0x78, 0x77, 0xD4, 0xAA, 0x4F, 0xC9, 0xAC, 0x27, 0x68, 0x8C, 0x48, 0x1C, 0x52, 0xD1, 0x22, 0xC6, 0x9A, 0x66, 0x01, 0x3F, 0x86, 0xC7, 0xF5, 0xC9, 0x13, 0xDD, 0x70, 0xB3, 0xF9, 0x62, 0xF6, 0x7E, 0x3D, 0xB5, 0x60, 0x91, 0x35, 0x60, 0x4E, 0x99, 0x3B, 0xAB, 0x5B, 0x4F, 0xBD, 0x54, 0x05, 0xA7, 0x9C, 0xF8, 0x69, 0xDD}, IV: [16]byte{0xF2, 0x0F, 0x1E, 0x76, 0x95, 0xED, 0x1A, 0x03, 0x18, 0x5C, 0x51, 0x73, 0xBE, 0x4C, 0x12, 0x5F}}, - {Ciphertext: []byte{0xCB, 0x41, 0x34, 0x92, 0xAF, 0xF4, 0xF1, 0xD0, 0x80, 0x48, 0x53, 0x79, 0x7C, 0xE0, 0x28, 0xD9, 0x71, 0xB1, 0xB4, 0xA4, 0xB1, 0x97, 0x5B, 0xE2, 0x29, 0x73, 0xDF, 0x0B, 0x3D, 0x79, 0x82, 0xA3, 0x53, 0xC2, 0x73, 0x4B, 0x09, 0x3F, 0x4B, 0xA1, 0x9B, 0xB2, 0xB9, 0xA9, 0x59, 0xEF, 0xF8, 0x2D, 0xCB, 0x71, 0xE9, 0x94, 0x6A, 0x0B, 0xF8, 0xE5, 0x5D, 0x7A, 0x55, 0xE4, 0x7E, 0x55, 0x4B, 0x04, 0x97, 0x3D, 0xBF, 0x24, 0x99, 0xE7, 0x58, 0x2D, 0xFC, 0x38, 0x57, 0xBB, 0x34, 0x2B, 0x68, 0xA5, 0x88, 0x7C, 0x59, 0xD8, 0x0A, 0x1C, 0x41, 0x3E, 0xBB, 0x1E, 0x07, 0x12}, IV: [16]byte{0xCB, 0x41, 0x34, 0x92, 0xAF, 0xF4, 0xF1, 0xD0, 0x80, 0x48, 0x53, 0x79, 0x59, 0x6B, 0xCD, 0x66}}, - {Ciphertext: []byte{0x3E, 0x17, 0x48, 0x61, 0x49, 0x4E, 0xBA, 0xF6, 0x00, 0xB9, 0x7D, 0x78, 0x55, 0xC7, 0xA1, 0x0D, 0xAD, 0xB4, 0x10, 0x16, 0x25, 0x24, 0xC3, 0xE5, 0x95, 0xF8, 0x42, 0xF5, 0xC4, 0xF9, 0x01, 0x4E, 0x9E, 0x1A, 0x05, 0x26, 0x2B, 0xF9, 0x7B, 0x83, 0x6B, 0xBC, 0xEB, 0xFB, 0x7B, 0x2C, 0xDD, 0x59, 0x9D, 0x94, 0x07, 0xA3, 0x8B, 0x44, 0x2B, 0x55, 0x55, 0x46, 0xA2, 0x14, 0xA8, 0x9A, 0xE7, 0x60, 0x7F, 0xA9, 0xE8, 0xD4, 0xB5, 0xB1, 0x7A, 0x4A, 0x8F, 0xCF, 0xB0, 0xB2, 0x99, 0xC6, 0x57, 0x1E, 0xF2, 0x3A, 0x00, 0x09, 0xD3, 0xD4, 0x69, 0xD7, 0x5D, 0x3D, 0x69, 0x87}, IV: [16]byte{0x3E, 0x17, 0x48, 0x61, 0x49, 0x4E, 0xBA, 0xF6, 0x00, 0xB9, 0x7D, 0x78, 0xB6, 0x9D, 0x3E, 0x6C}}, - {Ciphertext: []byte{0x8E, 0xCC, 0x97, 0x83, 0x7F, 0xDC, 0x5C, 0x7E, 0x8C, 0xEB, 0x7A, 0x9D, 0xC9, 0x2F, 0x76, 0xE5, 0x04, 0x06, 0xD3, 0xEE, 0xB1, 0xCB, 0x65, 0xC2, 0x8D, 0x90, 0x28, 0xE9, 0x6A, 0x9F, 0xD2, 0xEB, 0x47, 0x04, 0xA2, 0xE4, 0x99, 0x19, 0x2F, 0xAC, 0xF3, 0x8A, 0x3F, 0xFA, 0x89, 0x99, 0xFF, 0xE4, 0xE1, 0xC4, 0xFE, 0xB8, 0x0C, 0x25, 0xC3, 0xEA, 0x64, 0x05, 0x81, 0x7F, 0x72, 0x8E, 0x33, 0x74, 0xCF, 0xA6, 0x7B, 0x70, 0x48, 0x59, 0x92, 0x3B, 0x3C, 0x5D, 0xC8, 0x62, 0x29, 0x60, 0x2C, 0x18, 0x05, 0x80, 0x87, 0xD1, 0xF7, 0xB5, 0x98, 0x99, 0xC1, 0x4A, 0xF1, 0xDF}, IV: [16]byte{0x8E, 0xCC, 0x97, 0x83, 0x7F, 0xDC, 0x5C, 0x7E, 0x8C, 0xEB, 0x7A, 0x9D, 0xA0, 0xD3, 0x7E, 0xE3}}, - {Ciphertext: []byte{0x56, 0x60, 0xCA, 0xCB, 0xB4, 0xA4, 0x62, 0xE0, 0x38, 0x67, 0xD8, 0xE3, 0xC7, 0x8F, 0x2B, 0x8E, 0x8F, 0xF9, 0x2F, 0x00, 0xD5, 0xDC, 0x0A, 0xAA, 0x1F, 0xBC, 0x1C, 0x62, 0x90, 0x3B, 0x38, 0xD7, 0x82, 0xB6, 0xDF, 0x7B, 0xD3, 0xEF, 0x4D, 0x39, 0x84, 0xE6, 0x2F, 0x57, 0x4B, 0x21, 0xFC, 0x1F, 0x46, 0xBF, 0x4A, 0xAF, 0x0C, 0x34, 0x01, 0x0C, 0xFB, 0xC3, 0x49, 0xC8, 0xEA, 0x8B, 0x62, 0xF2, 0x0C, 0x47, 0x6F, 0x19, 0x0F, 0x9E, 0x49, 0x97, 0x93, 0xE6, 0x35, 0xC0, 0xD6, 0x3C, 0xA4, 0x7D, 0x9C, 0x01, 0xB4, 0x03, 0xC8, 0x21, 0x2B, 0xE2, 0x1A, 0x4C, 0xD1, 0x24}, IV: [16]byte{0x56, 0x60, 0xCA, 0xCB, 0xB4, 0xA4, 0x62, 0xE0, 0x38, 0x67, 0xD8, 0xE3, 0x5F, 0xD3, 0xA1, 0x49}}, - {Ciphertext: []byte{0x49, 0xDC, 0x73, 0x9A, 0x26, 0x63, 0xD2, 0xBB, 0xC3, 0x6E, 0x6D, 0xCB, 0xEE, 0x48, 0xA6, 0x54, 0xB4, 0xF2, 0x82, 0x99, 0x79, 0x1E, 0xDA, 0x9E, 0x83, 0x19, 0xFA, 0x8D, 0x3B, 0x95, 0xC3, 0xDA, 0x4B, 0xA0, 0x71, 0x30, 0xC8, 0xA7, 0x00, 0x56, 0x71, 0xF0, 0x32, 0x32, 0x6E, 0x41, 0x01, 0xF6, 0xF8, 0xF0, 0xB3, 0xF4, 0x00, 0x62, 0x87, 0xAD, 0xCD, 0x75, 0x64, 0x04, 0x9A, 0xB7, 0x3F, 0x02, 0x2E, 0x4C, 0x14, 0x24, 0x53, 0x59, 0x8B, 0xBA, 0xA7, 0x4D, 0x44, 0xFE, 0xB4, 0x34, 0x99, 0x19, 0x13, 0x5D, 0xD0, 0xD7, 0x0B, 0xA9, 0xF7, 0xD0, 0x65, 0xD5, 0xC6, 0x99}, IV: [16]byte{0x49, 0xDC, 0x73, 0x9A, 0x26, 0x63, 0xD2, 0xBB, 0xC3, 0x6E, 0x6D, 0xCB, 0x99, 0x39, 0x48, 0x8D}}, - {Ciphertext: []byte{0xFA, 0x46, 0xAF, 0x91, 0xDD, 0xF7, 0xCD, 0x4D, 0x25, 0x4A, 0xDA, 0x4C, 0xE2, 0x88, 0x5C, 0x04, 0xD2, 0xDC, 0x65, 0xE0, 0x7A, 0x19, 0x8A, 0x04, 0x7E, 0x42, 0xAC, 0xA6, 0x1E, 0x86, 0xE6, 0xA4, 0x51, 0xE2, 0x2A, 0x81, 0x0D, 0x36, 0xFA, 0x67, 0x74, 0x59, 0xFD, 0x29, 0xC3, 0x4A, 0x63, 0xF2, 0x5D, 0x2F, 0x48, 0xE6, 0x3A, 0x42, 0x92, 0xFE, 0x2A, 0xCD, 0xE1, 0x22, 0x2E, 0x80, 0x7A, 0x9B, 0x82, 0x83, 0x1A, 0x33, 0x19, 0x78, 0x13, 0x0E, 0xC2, 0x0A, 0x1B, 0x53, 0xF8, 0xCA, 0x64, 0x24, 0x37, 0xD5, 0x00, 0x16, 0x03, 0x69, 0x90, 0xFA, 0x92, 0x7B, 0x92, 0x55}, IV: [16]byte{0xFA, 0x46, 0xAF, 0x91, 0xDD, 0xF7, 0xCD, 0x4D, 0x25, 0x4A, 0xDA, 0x4C, 0x2A, 0x28, 0x86, 0xD4}}, + {Ciphertext: []byte{0xD6, 0x41, 0xFB, 0xEB, 0xC1, 0xCC, 0x4D, 0xA9, 0xC5, 0x02, 0xCF, 0xD6, 0x0E, 0x24, 0x8D, 0xA8, 0x38, 0xA3, 0xF4, 0x70, 0xBB, 0x7D, 0xF3, 0xC2, 0xBA, 0xEA, 0xFA, 0x7E, 0x47, 0xB4, 0x9B, 0x55, 0xDB, 0x00, 0xB2, 0xBA, 0x81, 0xAF, 0x3C, 0xB0, 0xFE, 0x5B, 0x5B, 0xAB, 0xFF, 0x54, 0x43, 0x47, 0xB1, 0x36, 0x8E, 0xF2, 0xCC, 0x22, 0x5B, 0x25, 0x84, 0x74, 0xED, 0xC7, 0xCB, 0xC0, 0x02, 0x0B, 0xE9, 0x53, 0x63, 0xC8, 0x0A, 0xE9, 0x13, 0x1F, 0x6F, 0x90, 0x79, 0x7C, 0xCC, 0x89, 0xDE, 0x9E, 0xC6, 0xFB, 0xFA, 0x3B, 0x3A, 0x59, 0x6F, 0xC8, 0x9C, 0x9C, 0x6F, 0x77}, IV: [16]byte{0xD6, 0x41, 0xFB, 0xEB, 0xC1, 0xCC, 0x4D, 0xA9, 0xC5, 0x02, 0xCF, 0xD6, 0x0C, 0x65, 0xE0, 0x32}}, + {Ciphertext: []byte{0x3B, 0x4C, 0x29, 0xDE, 0x96, 0x06, 0xE2, 0xA0, 0xFD, 0x10, 0x94, 0x59, 0x3F, 0x1A, 0xC9, 0xF9, 0xF3, 0x86, 0xD9, 0xA7, 0xDB, 0xB1, 0x2B, 0x0D, 0x2E, 0x65, 0x53, 0x45, 0xCB, 0xA9, 0x89, 0x2E, 0x10, 0x1C, 0x5C, 0x6A, 0x50, 0x47, 0xC4, 0xEB, 0x8C, 0xE7, 0x89, 0x62, 0xEE, 0x5B, 0xA1, 0x7E, 0x52, 0xC5, 0xF6, 0x58, 0xA1, 0x70, 0x60, 0xAA, 0x8C, 0xAA, 0xBF, 0xA0, 0x06, 0xC0, 0xA7, 0x5B, 0x0E, 0xE8, 0x42, 0xA6, 0x40, 0xC8, 0xDD, 0x52, 0x39, 0x73, 0x9D, 0x97, 0xE0, 0x36, 0x03, 0x65, 0x4B, 0x26, 0x9A, 0x7A, 0x10, 0x99, 0x35, 0x71, 0xFF, 0xF9, 0xE1, 0x06}, IV: [16]byte{0x3B, 0x4C, 0x29, 0xDE, 0x96, 0x06, 0xE2, 0xA0, 0xFD, 0x10, 0x94, 0x59, 0x26, 0x50, 0x2C, 0x68}}, + {Ciphertext: []byte{0x5B, 0xC1, 0xE8, 0x85, 0xEC, 0x06, 0xFA, 0x30, 0x76, 0xFC, 0xAD, 0xDE, 0x3D, 0x59, 0x79, 0x0B, 0x74, 0x1F, 0xAB, 0xCA, 0xAA, 0xA2, 0x38, 0x8A, 0xC5, 0x89, 0x36, 0xBC, 0x69, 0x6D, 0x86, 0xF2, 0x85, 0xB0, 0x7C, 0x65, 0x95, 0xF4, 0xE3, 0x72, 0x36, 0xD3, 0xC7, 0xC0, 0x7A, 0xF1, 0x1D, 0xA8, 0xDA, 0x80, 0xD7, 0xC9, 0x1B, 0xA5, 0x0B, 0x6C, 0xFB, 0xC9, 0xCF, 0x46, 0x19, 0xB9, 0x40, 0xB0, 0x20, 0x26, 0x74, 0xAE, 0x89, 0x52, 0x92, 0x42, 0x3F, 0x2B, 0x7C, 0xAF, 0x9C, 0x7F, 0x6F, 0x65, 0x1B, 0x28, 0xFB, 0x8D, 0x20, 0xB0, 0x47, 0xD5, 0xB4, 0xB4, 0x4B, 0x65}, IV: [16]byte{0x5B, 0xC1, 0xE8, 0x85, 0xEC, 0x06, 0xFA, 0x30, 0x76, 0xFC, 0xAD, 0xDE, 0x8D, 0xAA, 0x77, 0x1E}}, + {Ciphertext: []byte{0x31, 0x75, 0x43, 0xA2, 0x25, 0x22, 0xFC, 0x95, 0xDC, 0xBF, 0x29, 0xFA, 0x05, 0x45, 0xB4, 0x0A, 0xD5, 0xE9, 0xAD, 0xA4, 0x0F, 0x64, 0x08, 0xA9, 0x91, 0x8D, 0x72, 0x01, 0x8B, 0xD6, 0x45, 0x20, 0x4A, 0x08, 0x75, 0x53, 0x0C, 0xBD, 0xED, 0x88, 0x2A, 0x16, 0x18, 0x8F, 0x90, 0xD9, 0x07, 0xDE, 0xDD, 0xFF, 0x34, 0x32, 0x66, 0x62, 0xDE, 0x04, 0x61, 0xF9, 0x42, 0xCE, 0xC1, 0x61, 0xC5, 0x4D, 0x31, 0x53, 0x40, 0x79, 0x4A, 0xC7, 0xF7, 0x17, 0x28, 0x7C, 0xD9, 0x10, 0x7E, 0xCC, 0x52, 0xDC, 0x52, 0xD1, 0x7E, 0x39, 0xE0, 0x01, 0x65, 0x7A, 0xB8, 0xEA, 0xA3, 0x4F}, IV: [16]byte{0x31, 0x75, 0x43, 0xA2, 0x25, 0x22, 0xFC, 0x95, 0xDC, 0xBF, 0x29, 0xFA, 0x20, 0xFD, 0x70, 0x86}}, + {Ciphertext: []byte{0x5B, 0xD6, 0x4E, 0xC9, 0x35, 0x81, 0x52, 0x5D, 0x3B, 0x1B, 0xCF, 0xBD, 0xB4, 0xF4, 0x36, 0x26, 0xFB, 0x60, 0x51, 0x9D, 0x71, 0xBB, 0x1F, 0x0E, 0x57, 0xE5, 0xED, 0x5A, 0xC7, 0x64, 0xFE, 0x3E, 0x9A, 0x1D, 0xAB, 0x61, 0x40, 0x44, 0x6F, 0xE1, 0xC2, 0xB9, 0xAB, 0xB9, 0xD8, 0x4A, 0xB4, 0xF7, 0x45, 0xC4, 0xEE, 0x73, 0x6B, 0x09, 0x17, 0x16, 0x21, 0x99, 0x14, 0xEE, 0x36, 0x96, 0x89, 0xB3, 0x3D, 0xD3, 0x5C, 0x4F, 0x86, 0xBA, 0x6F, 0xEB, 0x62, 0x40, 0x86, 0x8E, 0x5C, 0xF6, 0x07, 0x43, 0x3C, 0x02, 0x77, 0xCB, 0xD9, 0x5B, 0xB8, 0x34, 0x1C, 0x21, 0x60, 0xA7}, IV: [16]byte{0x5B, 0xD6, 0x4E, 0xC9, 0x35, 0x81, 0x52, 0x5D, 0x3B, 0x1B, 0xCF, 0xBD, 0x01, 0x03, 0xDB, 0xB8}}, + {Ciphertext: []byte{0xA9, 0x7E, 0xDF, 0x65, 0xF7, 0xCD, 0xB4, 0xD1, 0x54, 0xDC, 0x11, 0xCF, 0xF8, 0xD1, 0x8D, 0x89, 0xB5, 0xA2, 0x8C, 0xB0, 0xCD, 0x8A, 0x80, 0x75, 0x65, 0xF3, 0x7D, 0x9B, 0x68, 0x79, 0x07, 0x3E, 0x47, 0xA2, 0x89, 0x8C, 0x57, 0x2E, 0xFB, 0xBC, 0x7B, 0x49, 0x81, 0x33, 0x2A, 0xBB, 0xB3, 0x69, 0x7B, 0xEB, 0x15, 0xDE, 0xC6, 0x65, 0x57, 0x6D, 0xD5, 0x35, 0x57, 0x9F, 0x4C, 0x77, 0x1A, 0x83, 0xE8, 0x04, 0x3A, 0x65, 0x53, 0x61, 0x51, 0xE4, 0x2E, 0x48, 0x0F, 0xD0, 0xD1, 0x7F, 0x18, 0x7A, 0x69, 0xC1, 0x14, 0x9F, 0x79, 0x0A, 0x8B, 0x6D, 0xAF, 0x0E, 0x40, 0xE7}, IV: [16]byte{0xA9, 0x7E, 0xDF, 0x65, 0xF7, 0xCD, 0xB4, 0xD1, 0x54, 0xDC, 0x11, 0xCF, 0x6A, 0x6A, 0xA6, 0x35}}, + {Ciphertext: []byte{0x2B, 0x52, 0x89, 0x10, 0x1F, 0x72, 0xCC, 0xDF, 0xD3, 0x8E, 0x1B, 0xC0, 0x16, 0x36, 0x97, 0x2B, 0x00, 0x17, 0x7F, 0x1D, 0x3E, 0x4C, 0x20, 0x5F, 0x48, 0x08, 0x41, 0xBC, 0x32, 0xE3, 0xFA, 0x10, 0x03, 0x0B, 0x6E, 0x3E, 0x67, 0x36, 0x90, 0x31, 0xFE, 0x55, 0xFD, 0x5E, 0x7A, 0xDD, 0xF8, 0x3B, 0xA8, 0x0B, 0x98, 0xDB, 0x22, 0x7D, 0xE5, 0xF9, 0xE8, 0xEF, 0x17, 0x68, 0x2A, 0x17, 0xA8, 0x2B, 0x93, 0x62, 0x28, 0x76, 0xC7, 0x48, 0xC2, 0xBD, 0xEF, 0xE5, 0x58, 0x0C, 0x13, 0x4B, 0x68, 0x93, 0x7F, 0x51, 0xD3, 0x49, 0xE4, 0xBA, 0xE8, 0xDB, 0xCA, 0x61, 0x04, 0xA2}, IV: [16]byte{0x2B, 0x52, 0x89, 0x10, 0x1F, 0x72, 0xCC, 0xDF, 0xD3, 0x8E, 0x1B, 0xC0, 0x22, 0x3D, 0x46, 0x43}}, + {Ciphertext: []byte{0xE1, 0xAB, 0xA0, 0x53, 0xEB, 0x0E, 0xB0, 0x77, 0x9D, 0xFA, 0xB0, 0x6A, 0x97, 0xAF, 0x78, 0x2F, 0x40, 0x6A, 0x52, 0xC4, 0xBF, 0x89, 0xBF, 0x96, 0x7D, 0xE5, 0x5F, 0x73, 0xA7, 0x94, 0xA8, 0xA0, 0xAA, 0x47, 0xBD, 0xE4, 0xAF, 0xEE, 0x9B, 0x07, 0xAB, 0x31, 0xD6, 0x72, 0xE2, 0x75, 0x8C, 0x3C, 0x34, 0x4E, 0xC8, 0xA8, 0x05, 0x6F, 0xCB, 0x80, 0xD8, 0x2D, 0x48, 0xD2, 0xA0, 0xB5, 0x5C, 0x87, 0x4A, 0x5A, 0x72, 0x7D, 0xEB, 0x4A, 0x26, 0x68, 0x20, 0x72, 0x1C, 0x64, 0x9C, 0xDB, 0x28, 0xF0, 0x8C, 0x09, 0xF6, 0x74, 0x71, 0xC9, 0x72, 0xE3, 0x2E, 0x51, 0x49, 0xDC}, IV: [16]byte{0xE1, 0xAB, 0xA0, 0x53, 0xEB, 0x0E, 0xB0, 0x77, 0x9D, 0xFA, 0xB0, 0x6A, 0x59, 0x10, 0xB0, 0xD0}}, + {Ciphertext: []byte{0xB4, 0x98, 0x9A, 0x4D, 0x06, 0xF6, 0x80, 0x02, 0x50, 0xCF, 0x7B, 0x13, 0xE4, 0x82, 0x0A, 0xC7, 0x59, 0xD7, 0x3E, 0x96, 0xBB, 0x57, 0x55, 0x1E, 0xFD, 0xE7, 0x9E, 0x28, 0x2D, 0xEE, 0x40, 0x03, 0x42, 0x9E, 0x78, 0x06, 0x89, 0x48, 0x78, 0x98, 0xA2, 0x12, 0x3E, 0x16, 0x31, 0x0C, 0x2B, 0x09, 0x44, 0xA2, 0x69, 0x31, 0xBD, 0x8A, 0x70, 0x7A, 0x1F, 0x9D, 0x92, 0xE7, 0x3B, 0xE7, 0xDC, 0xCF, 0x95, 0x9B, 0x58, 0xB3, 0xEF, 0xD9, 0xB5, 0x0F, 0x3E, 0xA1, 0xDF, 0x05, 0x9C, 0x3F, 0x91, 0x24, 0x1F, 0x24, 0x7D, 0x54, 0x50, 0x69, 0xAC, 0x0A, 0x10, 0x01, 0x3D, 0xBF}, IV: [16]byte{0xB4, 0x98, 0x9A, 0x4D, 0x06, 0xF6, 0x80, 0x02, 0x50, 0xCF, 0x7B, 0x13, 0xEE, 0x94, 0x07, 0xC6}}, + {Ciphertext: []byte{0xCF, 0xE1, 0xD2, 0x93, 0x18, 0xD2, 0x0F, 0x36, 0x27, 0x87, 0x27, 0x57, 0x4D, 0x82, 0x33, 0xDE, 0xCC, 0xE1, 0x88, 0x09, 0xE0, 0x4F, 0x6F, 0xA3, 0xC0, 0x2E, 0x82, 0x84, 0xCE, 0x33, 0xF1, 0x64, 0xBA, 0x46, 0xA1, 0xA2, 0x99, 0x25, 0x9B, 0x33, 0xFF, 0x80, 0x6E, 0x42, 0x36, 0x18, 0x34, 0xCA, 0x09, 0x96, 0xC4, 0xFC, 0x86, 0x52, 0x0D, 0xC2, 0x8D, 0xFF, 0x74, 0x11, 0x15, 0xEC, 0xED, 0xD3, 0x71, 0x66, 0x50, 0x82, 0xD9, 0xF7, 0x96, 0x80, 0x07, 0x06, 0xDD, 0x57, 0x9C, 0xEB, 0x56, 0x8D, 0x4C, 0xAA, 0x8A, 0xF2, 0x06, 0x24, 0x8C, 0x3A, 0x43, 0xBD, 0xC6, 0x49}, IV: [16]byte{0xCF, 0xE1, 0xD2, 0x93, 0x18, 0xD2, 0x0F, 0x36, 0x27, 0x87, 0x27, 0x57, 0x60, 0x1A, 0xAA, 0x6C}}, + {Ciphertext: []byte{0x38, 0x69, 0x2E, 0xDD, 0x18, 0x24, 0x28, 0xE4, 0x88, 0x33, 0xA3, 0xFC, 0x39, 0x3D, 0x48, 0x07, 0xF7, 0x03, 0xBC, 0x68, 0x53, 0x2A, 0x57, 0x92, 0x01, 0x57, 0x04, 0x4D, 0xC8, 0xE6, 0xD4, 0x21, 0xA9, 0xDB, 0xA3, 0xFF, 0xCB, 0x56, 0x9A, 0x16, 0x58, 0x48, 0x2D, 0xF5, 0x25, 0x86, 0x21, 0x2E, 0x95, 0x85, 0x16, 0xA6, 0x24, 0x6D, 0x23, 0x98, 0xF3, 0xE0, 0x96, 0x1A, 0x27, 0x69, 0x50, 0xDD, 0xA8, 0x04, 0x37, 0x0B, 0xAE, 0xC7, 0xEB, 0x80, 0xA1, 0xBD, 0x0B, 0x55, 0x72, 0x3E, 0x62, 0x45, 0x1F, 0xF9, 0xBF, 0x1B, 0xBF, 0xE5, 0xA1, 0x4C, 0x5B, 0x7A, 0x23, 0x6E}, IV: [16]byte{0x38, 0x69, 0x2E, 0xDD, 0x18, 0x24, 0x28, 0xE4, 0x88, 0x33, 0xA3, 0xFC, 0x27, 0x5F, 0x02, 0x1C}}, + {Ciphertext: []byte{0xC4, 0x12, 0xF5, 0x8D, 0xC7, 0x0A, 0x06, 0x5E, 0xA7, 0xA3, 0x2B, 0xBF, 0xA4, 0x39, 0xA9, 0x9F, 0xC9, 0x58, 0xC8, 0x0D, 0x62, 0x8B, 0x0A, 0x0B, 0x33, 0x86, 0x7D, 0xB0, 0x01, 0x1B, 0x5B, 0x06, 0x40, 0x86, 0x97, 0x6D, 0x25, 0x39, 0xC7, 0x6A, 0xCB, 0x63, 0xD3, 0x83, 0x82, 0xFC, 0x24, 0x47, 0xE2, 0xDD, 0x8B, 0x5E, 0x19, 0x98, 0x2A, 0xC3, 0xA0, 0xD8, 0xA5, 0x74, 0xAA, 0x47, 0x94, 0x61, 0x2B, 0xD8, 0x49, 0x89, 0x38, 0x74, 0x65, 0x7F, 0x54, 0xD5, 0xDF, 0xD6, 0x94, 0xB4, 0x58, 0xAE, 0xCE, 0xBD, 0x45, 0xF7, 0x4C, 0x14, 0xF3, 0xF8, 0xDB, 0xBF, 0x7F, 0x35}, IV: [16]byte{0xC4, 0x12, 0xF5, 0x8D, 0xC7, 0x0A, 0x06, 0x5E, 0xA7, 0xA3, 0x2B, 0xBF, 0x40, 0x65, 0x3E, 0x8B}}, + {Ciphertext: []byte{0x1A, 0xD9, 0xDD, 0x57, 0xF2, 0x7B, 0xD1, 0x59, 0xEB, 0xEC, 0x91, 0xDF, 0x96, 0xEF, 0xC5, 0x48, 0x02, 0xE6, 0x77, 0xD8, 0x5D, 0xF2, 0xDE, 0xD9, 0x0E, 0x4A, 0xD4, 0x7C, 0xF1, 0x5C, 0x68, 0xBC, 0xDD, 0x8D, 0x9C, 0xEC, 0x4F, 0x2C, 0x45, 0x70, 0x51, 0xAA, 0xEB, 0xA8, 0x3F, 0x35, 0x3C, 0x66, 0x4E, 0x14, 0x43, 0x63, 0x88, 0x04, 0x73, 0xC2, 0x69, 0x76, 0x41, 0x4F, 0x3C, 0x50, 0x1F, 0x3A, 0x5A, 0x8B, 0xFE, 0xE0, 0x85, 0x63, 0xA0, 0x45, 0x64, 0x28, 0xB2, 0x4D, 0x8E, 0x65, 0x90, 0xEF, 0x03, 0xAE, 0xA3, 0xB1, 0x52, 0xA5, 0xD5, 0xC0, 0xBC, 0xE3, 0x63, 0xCB}, IV: [16]byte{0x1A, 0xD9, 0xDD, 0x57, 0xF2, 0x7B, 0xD1, 0x59, 0xEB, 0xEC, 0x91, 0xDF, 0xFC, 0x18, 0x6B, 0x2A}}, + {Ciphertext: []byte{0x8B, 0x4C, 0xC7, 0x09, 0x0A, 0xE1, 0xC8, 0x47, 0x4B, 0xD0, 0xFA, 0x71, 0xCE, 0xEB, 0x19, 0x70, 0xC7, 0xAA, 0xFA, 0xAE, 0xD1, 0x8B, 0x76, 0xC5, 0x54, 0x00, 0xCE, 0x2A, 0xD5, 0x2E, 0x97, 0x94, 0x47, 0x8F, 0xB1, 0x1E, 0x87, 0x59, 0x5A, 0xD3, 0xA8, 0xE0, 0xD9, 0xBC, 0xB1, 0xD9, 0x12, 0x34, 0x87, 0xBA, 0x10, 0x1A, 0xB8, 0x37, 0xA7, 0x0E, 0xCB, 0x28, 0x5C, 0xF6, 0xBC, 0xF1, 0x85, 0xC2, 0xC8, 0x89, 0x8D, 0x85, 0xF8, 0x58, 0x92, 0x81, 0x52, 0xE6, 0xC3, 0x40, 0xA1, 0xD3, 0xAF, 0x89, 0xB7, 0x90, 0xF6, 0xB7, 0x58, 0x25, 0x3B, 0x7A, 0xE9, 0x6E, 0x45, 0x16}, IV: [16]byte{0x8B, 0x4C, 0xC7, 0x09, 0x0A, 0xE1, 0xC8, 0x47, 0x4B, 0xD0, 0xFA, 0x71, 0x3C, 0xEE, 0xA4, 0xC6}}, + {Ciphertext: []byte{0x45, 0x1C, 0xF2, 0x62, 0x51, 0x45, 0x07, 0x74, 0x1F, 0xCF, 0xC6, 0xB1, 0x05, 0xDF, 0x88, 0xCD, 0x5C, 0x3F, 0x14, 0x9D, 0x90, 0x62, 0x80, 0xDD, 0x08, 0xC9, 0xB1, 0x20, 0x21, 0xAD, 0x4D, 0x9D, 0xA6, 0x8F, 0xCC, 0xE9, 0x83, 0xD6, 0x17, 0x82, 0xE5, 0x28, 0x0B, 0x73, 0x9F, 0x68, 0xD6, 0xAE, 0x9F, 0x32, 0x62, 0x80, 0x91, 0xE6, 0x09, 0xE5, 0x14, 0x0E, 0x87, 0x98, 0x4B, 0x9B, 0x67, 0x4F, 0x6B, 0x0D, 0x67, 0xED, 0x4A, 0x6A, 0xFD, 0x09, 0x12, 0xA3, 0xC7, 0x07, 0xC7, 0xFE, 0x8C, 0x07, 0xAF, 0x77, 0x42, 0x14, 0xB0, 0x44, 0xEC, 0xB0, 0xB5, 0x0C, 0x6D, 0x09}, IV: [16]byte{0x45, 0x1C, 0xF2, 0x62, 0x51, 0x45, 0x07, 0x74, 0x1F, 0xCF, 0xC6, 0xB1, 0xD2, 0xD9, 0x3B, 0xA0}}, + {Ciphertext: []byte{0x9E, 0xD7, 0x66, 0xF7, 0xEF, 0xFE, 0xDE, 0x19, 0x5D, 0x19, 0x16, 0x02, 0x37, 0xF6, 0xD1, 0x47, 0xB9, 0xF6, 0x9F, 0x4B, 0xC6, 0xFD, 0x45, 0xD3, 0xE4, 0x6E, 0xD4, 0xC7, 0x16, 0x76, 0x4D, 0x5E, 0xEA, 0x57, 0x85, 0x36, 0xF1, 0x95, 0x10, 0x5A, 0x03, 0xC4, 0x8E, 0x30, 0xF6, 0x4B, 0xAA, 0x0A, 0xA0, 0x38, 0x29, 0x89, 0x39, 0xDA, 0x8A, 0x9D, 0x1A, 0x15, 0x28, 0x93, 0x08, 0xE4, 0x89, 0x3C, 0x3B, 0xC4, 0xB6, 0xB8, 0x2F, 0x53, 0xDC, 0x80, 0x2B, 0xC8, 0x33, 0x9C, 0x9B, 0xDE, 0x4E, 0xA6, 0xE4, 0x6C, 0x59, 0x65, 0xAE, 0xA2, 0x59, 0x74, 0x9D, 0x76, 0xE3, 0xB3}, IV: [16]byte{0x9E, 0xD7, 0x66, 0xF7, 0xEF, 0xFE, 0xDE, 0x19, 0x5D, 0x19, 0x16, 0x02, 0xF7, 0xE2, 0x09, 0xE9}}, + {Ciphertext: []byte{0x48, 0x7C, 0x9A, 0x69, 0x04, 0x5C, 0xAF, 0x53, 0xA6, 0xF3, 0xCD, 0x20, 0xBA, 0xA1, 0xFE, 0x95, 0x32, 0x2C, 0x62, 0x1A, 0x90, 0xCC, 0xAA, 0xA4, 0x8B, 0x5E, 0xF3, 0x93, 0x93, 0x21, 0x3E, 0x88, 0xD6, 0x2B, 0xD3, 0x9F, 0xCC, 0x9C, 0x8B, 0xEC, 0xF8, 0x87, 0xDB, 0x21, 0xDE, 0x80, 0xD4, 0xD1, 0x31, 0x91, 0xF9, 0x14, 0xC6, 0x84, 0x44, 0xCC, 0x3C, 0x86, 0x18, 0xBD, 0x94, 0x99, 0xDF, 0x95, 0x35, 0xEB, 0x9C, 0x7B, 0x03, 0x25, 0x18, 0x5C, 0xA7, 0x29, 0x37, 0xEE, 0x33, 0x7F, 0x52, 0x41, 0x65, 0xB1, 0xD9, 0x79, 0x28, 0xA7, 0x71, 0x74, 0x96, 0x08, 0x88, 0x36}, IV: [16]byte{0x48, 0x7C, 0x9A, 0x69, 0x04, 0x5C, 0xAF, 0x53, 0xA6, 0xF3, 0xCD, 0x20, 0x24, 0x12, 0xB8, 0xC1}}, + {Ciphertext: []byte{0x65, 0x5E, 0xCB, 0xC5, 0x9D, 0xED, 0xD6, 0x7B, 0x8D, 0x30, 0x95, 0xAC, 0x61, 0x09, 0xD4, 0xC2, 0x35, 0x49, 0xA9, 0x31, 0x6F, 0x32, 0x84, 0x72, 0x15, 0x76, 0x59, 0xA6, 0xB3, 0x90, 0xB2, 0xA1, 0x08, 0x7D, 0x72, 0x6A, 0xB4, 0xE5, 0x23, 0xFC, 0x76, 0x5B, 0xBB, 0x31, 0x7D, 0x51, 0x76, 0xCE, 0xCA, 0x0D, 0x24, 0x74, 0x96, 0xA2, 0xF6, 0xAF, 0x30, 0x96, 0x28, 0x47, 0x52, 0xB2, 0xFF, 0x2C, 0x66, 0x74, 0xC0, 0x82, 0x23, 0x2C, 0xCC, 0x14, 0xBD, 0x85, 0x4A, 0xF9, 0x61, 0x8F, 0xE5, 0xF4, 0x2A, 0xAA, 0x7C, 0x75, 0xEA, 0xC6, 0x35, 0x6F, 0x10, 0x36, 0x36, 0x30}, IV: [16]byte{0x65, 0x5E, 0xCB, 0xC5, 0x9D, 0xED, 0xD6, 0x7B, 0x8D, 0x30, 0x95, 0xAC, 0x86, 0xAC, 0x5D, 0x77}}, + {Ciphertext: []byte{0x7D, 0xF2, 0x37, 0xA2, 0xAC, 0x61, 0x56, 0xAF, 0xD3, 0x42, 0xB0, 0xFA, 0x54, 0x45, 0x88, 0x17, 0x19, 0x9D, 0x5A, 0x04, 0xA9, 0x97, 0xCF, 0x93, 0x64, 0x1F, 0x68, 0x18, 0xE2, 0xAB, 0x20, 0xEA, 0x7A, 0xE2, 0x29, 0x44, 0x97, 0x10, 0x70, 0x99, 0xA7, 0x91, 0x4C, 0x84, 0x9C, 0x4E, 0x42, 0xD4, 0xB1, 0x0E, 0x26, 0x6F, 0x33, 0xA8, 0xE8, 0x0D, 0x8E, 0xE0, 0x01, 0xBA, 0x38, 0x0D, 0x2B, 0x82, 0x29, 0x73, 0x70, 0x6D, 0xCD, 0xED, 0x7A, 0x8B, 0x47, 0x2F, 0x13, 0x7F, 0x09, 0xFD, 0x99, 0xB9, 0x1D, 0x90, 0x67, 0x80, 0xC2, 0x14, 0x58, 0xFD, 0x24, 0xB2, 0x16, 0xF0}, IV: [16]byte{0x7D, 0xF2, 0x37, 0xA2, 0xAC, 0x61, 0x56, 0xAF, 0xD3, 0x42, 0xB0, 0xFA, 0x54, 0x09, 0xD3, 0x75}}, + {Ciphertext: []byte{0xB5, 0x67, 0x8D, 0x32, 0x9B, 0xCE, 0x74, 0xEB, 0xC3, 0xFF, 0xE3, 0xA8, 0x34, 0xE0, 0xBE, 0x5B, 0xB8, 0x72, 0x86, 0x58, 0xA5, 0x93, 0x15, 0x0E, 0x75, 0x0E, 0x78, 0x8A, 0x1E, 0x6A, 0xAB, 0x02, 0x25, 0xA6, 0x16, 0xF1, 0xFE, 0x84, 0x7F, 0x0B, 0xF7, 0xE1, 0xE9, 0xAB, 0xDD, 0x44, 0x1B, 0x39, 0x15, 0x4C, 0x98, 0x0F, 0xF5, 0x5D, 0x54, 0x50, 0x23, 0xC3, 0x2D, 0x0F, 0x39, 0x80, 0x48, 0xD1, 0x5C, 0x7B, 0xE5, 0x6D, 0x16, 0x5D, 0xA6, 0x24, 0x0D, 0x33, 0x5A, 0xFE, 0x75, 0x1A, 0x5F, 0x49, 0x06, 0x7C, 0x0E, 0xB2, 0xD5, 0x06, 0x44, 0xE0, 0x60, 0x0A, 0x3F, 0x77}, IV: [16]byte{0xB5, 0x67, 0x8D, 0x32, 0x9B, 0xCE, 0x74, 0xEB, 0xC3, 0xFF, 0xE3, 0xA8, 0x26, 0x0A, 0xB4, 0xF5}}, } var _encPool = strenc.NewPool(_masterSeed, _encEntries) //go:noinline @@ -57,24 +77,22 @@ var licenseKey = _decStr(4) func main() { fmt.Println(_decStr(5)) + if func() bool { _bciLLbB := int64(1); for i := 0; i < 10; i++ { _bciLLbB = _bciLLbB*7%49999999 }; return _bciLLbB == 1 }() { _ = struct{}{} } fmt.Printf(_decStr(6), getVersion()) - if func() bool { return (867 & 867) == 867 }() { _ = struct{}{} } - if func() bool { _bcbGLgi := [4]byte{0x72, 0x6F, 0x6F, 0x74}; return len(_bcbGLgi) == 4 }() { _ = struct{}{} } fmt.Printf(_decStr(7), getBuildID()) - if func() bool { return func() bool { return (11134^11134) > 0 && (11134^11134) < 0 }() }() { println("unreachable") } processRequest(_decStr(8)) } -func getVersion_obf2511() string { +func getVersion_obf1861() string { return _decStr(9) } -func getBuildID_obf7656() string { +func getBuildID_obf7802() string { return fmt.Sprintf(_decStr(10), time.Now().Unix()) } -func processRequest_obf1301(userID string) { +func processRequest_obf4807(userID string) { fmt.Printf(_decStr(11), userID) if userID == "" { @@ -94,13 +112,14 @@ func processRequest_obf1301(userID string) { _ = jwtSecret } -func generateToken_obf5646(userID string) string { +func generateToken_obf1103(userID string) string { h := sha256.Sum256([]byte(fmt.Sprintf(_decStr(15), userID, time.Now().UnixNano()))) + { _bcIcrhv := func() int { n := 0; for i := 1; i <= 100; i++ { n += i }; return n }(); _ = _bcIcrhv } return fmt.Sprintf(_decStr(16), h[:8]) } //go:noinline -func validateLicense_obf9184(key string) bool { +func validateLicense_obf1490(key string) bool { _co := map[int]func([]int64) int64{ 0: func(_ []int64) int64 { return int64(len(key)) }, } @@ -109,7 +128,7 @@ func validateLicense_obf9184(key string) bool { return _vm.Run() != 0 } -func maskString_obf9182(s string) string { +func maskString_obf3138(s string) string { if len(s) <= 8 { return _decStr(17) } diff --git a/build/transformer b/build/transformer index 63b20fc..0a3c655 100755 Binary files a/build/transformer and b/build/transformer differ diff --git a/cmd/transformer/main.go b/cmd/transformer/main.go index 16d70d2..718d011 100644 --- a/cmd/transformer/main.go +++ b/cmd/transformer/main.go @@ -23,6 +23,8 @@ func main() { seed := flag.Int64("seed", 0, "Build seed for polymorphic output (0 = use current timestamp)") injectBuildID := flag.Bool("buildid", true, "Inject unique build ID constant") virtualizeVM := flag.Bool("vm", true, "Virtualize simple functions into VM bytecode") + antiDisasm := flag.Bool("anti-disasm", true, "Inject anti-disassembly patterns") + junkStrings := flag.Bool("junk-strings", true, "Inject junk string constants") flag.Parse() if *srcDir == "" || *dstDir == "" { @@ -58,16 +60,18 @@ func main() { BuildSeed: *seed, InjectBuildID: *injectBuildID, VirtualizeFunctions: *virtualizeVM, + AntiDisassembly: *antiDisasm, + JunkStrings: *junkStrings, } t := transform.New(config) fmt.Printf("[transformer] src=%s dst=%s\n", absSrc, absDst) fmt.Printf("[transformer] seed=%d buildid=%v\n", config.BuildSeed, config.InjectBuildID) - fmt.Printf("[transformer] strings=%v opaque=%v deadcode=%v bogus=%v flatten=%v vm=%v\n", + fmt.Printf("[transformer] strings=%v opaque=%v deadcode=%v bogus=%v flatten=%v vm=%v antidisasm=%v junkstr=%v\n", config.EncryptStrings, config.InjectOpaquePreds, config.InjectDeadCode, config.BogusControlFlow, config.FlattenControl, - config.VirtualizeFunctions) + config.VirtualizeFunctions, config.AntiDisassembly, config.JunkStrings) start := time.Now() diff --git a/internal/transform/transform.go b/internal/transform/transform.go index bf33e34..9db1b5d 100644 --- a/internal/transform/transform.go +++ b/internal/transform/transform.go @@ -34,6 +34,8 @@ type Config struct { BuildSeed int64 InjectBuildID bool VirtualizeFunctions bool + AntiDisassembly bool + JunkStrings bool } func DefaultConfig() Config { @@ -120,6 +122,14 @@ func (t *Transformer) TransformFile(srcPath, dstPath string) error { result = t.virtualizeFunctions(result) } + if t.config.AntiDisassembly { + result = t.injectAntiDisassembly(result) + } + + if t.config.JunkStrings { + result = t.injectJunkStrings(result) + } + if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil { return fmt.Errorf("mkdir %s: %w", filepath.Dir(dstPath), err) } @@ -921,6 +931,7 @@ func (t *Transformer) indirectDispatch(src string) string { lines := strings.Split(src, "\n") var result []string var wrappers []string + dispatchIdx := 0 for _, line := range lines { trimmed := strings.TrimSpace(line) @@ -981,13 +992,20 @@ func (t *Transformer) indirectDispatch(src string) string { argNames := extractArgNames(argStr) callArgs := strings.Join(argNames, ", ") + ptrVar := fmt.Sprintf("_fptr%d", dispatchIdx) + dispatchIdx++ + if hasReturn { - wrapperFunc := fmt.Sprintf("func %s%s %s { return %s(%s) }", - funcName, params, returnType, funcName+obfSuffix, callArgs) + ptrDecl := fmt.Sprintf("var %s = %s", ptrVar, funcName+obfSuffix) + wrappers = append(wrappers, ptrDecl) + wrapperFunc := fmt.Sprintf("//go:noinline\nfunc %s%s %s { return %s(%s) }", + funcName, params, returnType, ptrVar, callArgs) wrappers = append(wrappers, wrapperFunc) } else { - wrapperFunc := fmt.Sprintf("func %s%s { %s(%s) }", - funcName, params, funcName+obfSuffix, callArgs) + ptrDecl := fmt.Sprintf("var %s = %s", ptrVar, funcName+obfSuffix) + wrappers = append(wrappers, ptrDecl) + wrapperFunc := fmt.Sprintf("//go:noinline\nfunc %s%s { %s(%s) }", + funcName, params, ptrVar, callArgs) wrappers = append(wrappers, wrapperFunc) } } @@ -1487,6 +1505,86 @@ func %s(%s int64) int64 { }`, funcName, param, param, strings.Join(byteLits, ", ")) } +func (t *Transformer) injectAntiDisassembly(src string) string { + lines := strings.Split(src, "\n") + var result []string + inFuncBody := false + + for _, line := range lines { + trimmed := strings.TrimSpace(line) + + if strings.HasPrefix(trimmed, "func ") && strings.HasSuffix(trimmed, "{") { + inFuncBody = true + result = append(result, line) + continue + } + + if inFuncBody && trimmed == "}" { + inFuncBody = false + result = append(result, line) + continue + } + + if inFuncBody && strings.HasPrefix(line, "\t") && !strings.HasPrefix(line, "\t\t") && trimmed != "" { + if t.rng.Float64() < 0.15 { + junkVar := stringcrypt.RandomIdent("_ad", 4) + junkSize := t.rng.Intn(32) + 8 + result = append(result, fmt.Sprintf("\tvar %s [%d]byte; _ = %s", junkVar, junkSize, junkVar)) + } + } + + result = append(result, line) + } + + return strings.Join(result, "\n") +} + +func (t *Transformer) injectJunkStrings(src string) string { + junkStrings := []string{ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "0123456789abcdef0123456789abcdef", + "/usr/lib/libSystem.B.dylib", + "/proc/self/maps", + "\\x00\\x00\\x00\\x00", + "HKEY_LOCAL_MACHINE\\SOFTWARE", + "C:\\Windows\\System32\\ntdll.dll", + "SELECT * FROM users WHERE id=?", + "Content-Type: application/json", + "Mozilla/5.0 (Windows NT 10.0)", + "-----BEGIN RSA PRIVATE KEY-----", + "192.168.1.1:8080", + "admin@localhost", + "Bearer eyJhbGciOiJIUzI1NiJ9", + "application/x-www-form-urlencoded", + } + + numJunk := t.rng.Intn(6) + 4 + var junkBlock strings.Builder + junkBlock.WriteString("\nvar _junkData = [...]string{\n") + for i := 0; i < numJunk; i++ { + idx := t.rng.Intn(len(junkStrings)) + junkBlock.WriteString(fmt.Sprintf("\t%q,\n", junkStrings[idx])) + } + junkBlock.WriteString("}\n") + junkBlock.WriteString("var _ = _junkData\n") + + insertAt := findImportBlockEnd(src) + if insertAt == -1 { + pkgIdx := strings.Index(src, "package ") + if pkgIdx != -1 { + lineEnd := strings.Index(src[pkgIdx:], "\n") + if lineEnd != -1 { + insertAt = pkgIdx + lineEnd + 1 + } + } + } + if insertAt != -1 && insertAt < len(src) { + src = src[:insertAt] + junkBlock.String() + src[insertAt:] + } + + return src +} + func (t *Transformer) ensureImport(src string, importPath string) string { importBlock := `import ("` + importPath + `")` diff --git a/pkg/antidebug/antidebug.go b/pkg/antidebug/antidebug.go index ce4b79b..c7ddb51 100644 --- a/pkg/antidebug/antidebug.go +++ b/pkg/antidebug/antidebug.go @@ -1,20 +1,12 @@ package antidebug -import ( - "fmt" - "os" - "runtime" - "time" -) - func Check() error { - if runtime.GOOS == "linux" { - if err := checkPtrace(); err != nil { - return err - } - if err := disableCoreDump(); err != nil { - return err - } + if err := checkPtrace(); err != nil { + return err + } + + if err := disableCoreDump(); err != nil { + return err } if err := checkTiming(); err != nil { @@ -35,139 +27,3 @@ func Check() error { return nil } - -func checkPtrace() error { - self, err := os.ReadFile("/proc/self/status") - if err != nil { - return nil - } - - data := string(self) - for i := 0; i < len(data)-11; i++ { - if data[i:i+11] == "TracerPid:\t" { - j := i + 11 - for j < len(data) && data[j] >= '0' && data[j] <= '9' { - j++ - } - pid := data[i+11 : j] - if pid != "0" { - return fmt.Errorf("antidebug: debugger detected (tracer pid=%s)", pid) - } - break - } - } - return nil -} - -func disableCoreDump() error { - f, err := os.OpenFile("/proc/self/coredump_filter", os.O_WRONLY, 0) - if err != nil { - return nil - } - defer f.Close() - _, _ = f.WriteString("0") - return nil -} - -func checkTiming() error { - start := time.Now() - sum := 0 - for i := 0; i < 1000000; i++ { - sum += i - } - elapsed := time.Since(start) - - if elapsed > 200*time.Millisecond { - return fmt.Errorf("antidebug: timing anomaly detected (%v for 1M iterations)", elapsed) - } - - _ = sum - return nil -} - -func checkEnv() error { - suspiciousVars := []string{ - "GODEBUG", - "DELVE_LISTENER", - "DEBUGINFOD_URL", - "RR_LOG_FILE", - "_JAVA_OPTIONS", - "LD_PRELOAD", - "DYLD_INSERT_LIBRARIES", - } - - for _, v := range suspiciousVars { - if os.Getenv(v) != "" { - return fmt.Errorf("antidebug: suspicious env var %s=%s", v, os.Getenv(v)) - } - } - return nil -} - -func checkParentProcess() error { - if runtime.GOOS != "linux" { - return nil - } - - ppid := os.Getppid() - if ppid <= 1 { - return nil - } - - commPath := fmt.Sprintf("/proc/%d/comm", ppid) - comm, err := os.ReadFile(commPath) - if err != nil { - return nil - } - - parent := string(comm) - debuggers := []string{ - "gdb", "lldb", "strace", "ltrace", "ida", "ida64", - "radare2", "r2", "ghidra", "x64dbg", "ollydbg", - "delve", "debugserver", - } - - for _, d := range debuggers { - if len(parent) >= len(d) && parent[:len(d)] == d { - return fmt.Errorf("antidebug: parent process is debugger: %s", parent) - } - } - return nil -} - -func AntiAttach() { - if runtime.GOOS != "linux" { - return - } - go func() { - for { - time.Sleep(500 * time.Millisecond) - if err := checkPtrace(); err != nil { - os.Exit(66) - } - } - }() -} - -func AntiDump() { - if runtime.GOOS != "linux" { - return - } - go func() { - ticker := time.NewTicker(2 * time.Second) - defer ticker.Stop() - for range ticker.C { - _ = disableCoreDump() - } - }() -} - -func CheckHooks() error { - if err := checkFunctionPrologues(); err != nil { - return err - } - if err := scanForBreakpoints(); err != nil { - return err - } - return nil -} diff --git a/pkg/antidebug/antidebug_darwin.go b/pkg/antidebug/antidebug_darwin.go new file mode 100644 index 0000000..3c89143 --- /dev/null +++ b/pkg/antidebug/antidebug_darwin.go @@ -0,0 +1,147 @@ +//go:build darwin + +package antidebug + +import ( + "fmt" + "os" + "syscall" + "time" + "unsafe" +) + +const ( + ctlKern = 1 + kernProc = 14 + kernProcPID = 1 + pTraced = 0x00000800 + ptDenyAttach = 31 +) + +func checkPtrace() error { + pid := os.Getpid() + + var mib [4]int32 + mib[0] = ctlKern + mib[1] = kernProc + mib[2] = kernProcPID + mib[3] = int32(pid) + + bufSize := uintptr(64) + buf := make([]byte, bufSize) + + _, _, errno := syscall.Syscall6( + uintptr(0x2000000+202), + uintptr(unsafe.Pointer(&mib[0])), + 4, + uintptr(unsafe.Pointer(&buf[0])), + uintptr(unsafe.Pointer(&bufSize)), + 0, + 0, + ) + + if errno != 0 { + return nil + } + + if bufSize < 36 { + return nil + } + + pFlag := uint32(buf[32]) | uint32(buf[33])<<8 | uint32(buf[34])<<16 | uint32(buf[35])<<24 + + if pFlag&pTraced != 0 { + return fmt.Errorf("antidebug: debugger detected via sysctl P_TRACED (pid=%d)", pid) + } + + return nil +} + +func denyPtraceAttach() { + pid := os.Getpid() + syscall.RawSyscall( + uintptr(syscall.SYS_PTRACE), + uintptr(ptDenyAttach), + uintptr(pid), + 0, + ) +} + +func disableCoreDump() error { + return nil +} + +func checkTiming() error { + start := time.Now() + sum := 0 + for i := 0; i < 1000000; i++ { + sum += i + } + elapsed := time.Since(start) + + if elapsed > 200*time.Millisecond { + return fmt.Errorf("antidebug: timing anomaly detected (%v for 1M iterations)", elapsed) + } + + _ = sum + return nil +} + +func checkEnv() error { + suspiciousVars := []string{ + "DYLD_INSERT_LIBRARIES", + "DYLD_FRAMEWORK_PATH", + "DYLD_LIBRARY_PATH", + "DYLD_FALLBACK_FRAMEWORK_PATH", + "DYLD_FALLBACK_LIBRARY_PATH", + "DYLD_ROOT_PATH", + "GODEBUG", + "DELVE_LISTENER", + "DEBUGINFOD_URL", + "RR_LOG_FILE", + "_JAVA_OPTIONS", + } + + for _, v := range suspiciousVars { + if os.Getenv(v) != "" { + return fmt.Errorf("antidebug: suspicious env var %s=%s", v, os.Getenv(v)) + } + } + return nil +} + +func checkParentProcess() error { + return nil +} + +func AntiAttach() { + go func() { + denyPtraceAttach() + for { + time.Sleep(500 * time.Millisecond) + if err := checkPtrace(); err != nil { + os.Exit(66) + } + } + }() +} + +func AntiDump() { + go func() { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + for range ticker.C { + _ = disableCoreDump() + } + }() +} + +func CheckHooks() error { + if err := checkFunctionPrologues(); err != nil { + return err + } + if err := scanForBreakpoints(); err != nil { + return err + } + return nil +} diff --git a/pkg/antidebug/antidebug_hook_darwin.go b/pkg/antidebug/antidebug_hook_darwin.go index 85540a0..30c5ec2 100644 --- a/pkg/antidebug/antidebug_hook_darwin.go +++ b/pkg/antidebug/antidebug_hook_darwin.go @@ -2,10 +2,116 @@ package antidebug +import ( + "fmt" + "os" + "reflect" + "runtime" + "unsafe" +) + func checkFunctionPrologues() error { + type target struct { + name string + addr uintptr + } + + targets := []target{ + {"os.Exit", reflect.ValueOf(os.Exit).Pointer()}, + {"runtime.Goexit", reflect.ValueOf(runtime.Goexit).Pointer()}, + } + + for _, t := range targets { + if t.addr == 0 { + continue + } + + prologue := readAddr(t.addr, 8) + if len(prologue) < 2 { + continue + } + + if prologue[0] == 0xE9 { + return fmt.Errorf("antidebug: JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xEB { + return fmt.Errorf("antidebug: short JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xFF && prologue[1] == 0x25 { + return fmt.Errorf("antidebug: indirect JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xCC && prologue[1] == 0xCC { + return fmt.Errorf("antidebug: INT3 breakpoint at %s (0x%x)", t.name, t.addr) + } + + if runtime.GOARCH == "arm64" { + instr := uint32(prologue[0]) | uint32(prologue[1])<<8 | uint32(prologue[2])<<16 | uint32(prologue[3])<<24 + if instr&0xFC000000 == 0x14000000 { + return fmt.Errorf("antidebug: ARM64 B hook detected at %s (0x%x)", t.name, t.addr) + } + if instr&0xFFE0001F == 0xD61F0000 { + return fmt.Errorf("antidebug: ARM64 BR hook detected at %s (0x%x)", t.name, t.addr) + } + } + } + return nil } func scanForBreakpoints() error { + type target struct { + name string + addr uintptr + } + + targets := []target{ + {"os.Exit", reflect.ValueOf(os.Exit).Pointer()}, + {"runtime.Goexit", reflect.ValueOf(runtime.Goexit).Pointer()}, + {"fmt.Printf", reflect.ValueOf(fmt.Printf).Pointer()}, + {"os.ReadFile", reflect.ValueOf(os.ReadFile).Pointer()}, + } + + for _, t := range targets { + if t.addr == 0 { + continue + } + + region := readAddr(t.addr, 64) + if len(region) < 8 { + continue + } + + maxConsecutive := 0 + consecutive := 0 + for _, b := range region { + if b == 0xCC { + consecutive++ + if consecutive > maxConsecutive { + maxConsecutive = consecutive + } + } else { + consecutive = 0 + } + } + + if maxConsecutive >= 4 { + return fmt.Errorf("antidebug: breakpoint cluster (%d consecutive INT3) near %s at 0x%x", maxConsecutive, t.name, t.addr) + } + } + return nil } + +func readAddr(addr uintptr, size int) []byte { + if size <= 0 || size > 4096 { + return nil + } + buf := make([]byte, size) + var src []byte + sh := (*reflect.SliceHeader)(unsafe.Pointer(&src)) + sh.Data = addr + sh.Len = size + sh.Cap = size + copy(buf, src) + return buf +} diff --git a/pkg/antidebug/antidebug_hook_windows.go b/pkg/antidebug/antidebug_hook_windows.go new file mode 100644 index 0000000..d062631 --- /dev/null +++ b/pkg/antidebug/antidebug_hook_windows.go @@ -0,0 +1,116 @@ +//go:build windows + +package antidebug + +import ( + "fmt" + "os" + "reflect" + "runtime" + "syscall" + "unsafe" +) + +var procReadProcessMemory = kernel32.NewProc("ReadProcessMemory") + +func checkFunctionPrologues() error { + type target struct { + name string + addr uintptr + } + + targets := []target{ + {"os.Exit", reflect.ValueOf(os.Exit).Pointer()}, + {"runtime.Goexit", reflect.ValueOf(runtime.Goexit).Pointer()}, + } + + currentProc, _ := syscall.GetCurrentProcess() + + for _, t := range targets { + if t.addr == 0 { + continue + } + + prologue := make([]byte, 8) + var bytesRead uintptr + ret, _, _ := procReadProcessMemory.Call( + uintptr(currentProc), + t.addr, + uintptr(unsafe.Pointer(&prologue[0])), + uintptr(len(prologue)), + uintptr(unsafe.Pointer(&bytesRead)), + ) + if ret == 0 || bytesRead < 2 { + continue + } + + if prologue[0] == 0xE9 { + return fmt.Errorf("antidebug: JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xEB { + return fmt.Errorf("antidebug: short JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xFF && prologue[1] == 0x25 { + return fmt.Errorf("antidebug: indirect JMP hook detected at %s (0x%x)", t.name, t.addr) + } + if prologue[0] == 0xCC && prologue[1] == 0xCC { + return fmt.Errorf("antidebug: INT3 breakpoint at %s (0x%x)", t.name, t.addr) + } + } + + return nil +} + +func scanForBreakpoints() error { + type target struct { + name string + addr uintptr + } + + targets := []target{ + {"os.Exit", reflect.ValueOf(os.Exit).Pointer()}, + {"runtime.Goexit", reflect.ValueOf(runtime.Goexit).Pointer()}, + {"fmt.Printf", reflect.ValueOf(fmt.Printf).Pointer()}, + {"os.ReadFile", reflect.ValueOf(os.ReadFile).Pointer()}, + } + + currentProc, _ := syscall.GetCurrentProcess() + + for _, t := range targets { + if t.addr == 0 { + continue + } + + region := make([]byte, 64) + var bytesRead uintptr + ret, _, _ := procReadProcessMemory.Call( + uintptr(currentProc), + t.addr, + uintptr(unsafe.Pointer(®ion[0])), + uintptr(len(region)), + uintptr(unsafe.Pointer(&bytesRead)), + ) + if ret == 0 || bytesRead < 8 { + continue + } + + maxConsecutive := 0 + consecutive := 0 + for _, b := range region[:bytesRead] { + if b == 0xCC { + consecutive++ + if consecutive > maxConsecutive { + maxConsecutive = consecutive + } + } else { + consecutive = 0 + } + } + + if maxConsecutive >= 4 { + return fmt.Errorf("antidebug: breakpoint cluster (%d consecutive INT3) near %s at 0x%x", maxConsecutive, t.name, t.addr) + } + } + + return nil +} diff --git a/pkg/antidebug/antidebug_linux.go b/pkg/antidebug/antidebug_linux.go new file mode 100644 index 0000000..c49add8 --- /dev/null +++ b/pkg/antidebug/antidebug_linux.go @@ -0,0 +1,135 @@ +//go:build linux + +package antidebug + +import ( + "fmt" + "os" + "runtime" + "time" +) + +func checkPtrace() error { + self, err := os.ReadFile("/proc/self/status") + if err != nil { + return nil + } + + data := string(self) + for i := 0; i < len(data)-11; i++ { + if data[i:i+11] == "TracerPid:\t" { + j := i + 11 + for j < len(data) && data[j] >= '0' && data[j] <= '9' { + j++ + } + pid := data[i+11 : j] + if pid != "0" { + return fmt.Errorf("antidebug: debugger detected (tracer pid=%s)", pid) + } + break + } + } + return nil +} + +func disableCoreDump() error { + f, err := os.OpenFile("/proc/self/coredump_filter", os.O_WRONLY, 0) + if err != nil { + return nil + } + defer f.Close() + _, _ = f.WriteString("0") + return nil +} + +func checkTiming() error { + start := time.Now() + sum := 0 + for i := 0; i < 1000000; i++ { + sum += i + } + elapsed := time.Since(start) + + if elapsed > 200*time.Millisecond { + return fmt.Errorf("antidebug: timing anomaly detected (%v for 1M iterations)", elapsed) + } + + _ = sum + return nil +} + +func checkEnv() error { + suspiciousVars := []string{ + "GODEBUG", + "DELVE_LISTENER", + "DEBUGINFOD_URL", + "RR_LOG_FILE", + "_JAVA_OPTIONS", + "LD_PRELOAD", + } + + for _, v := range suspiciousVars { + if os.Getenv(v) != "" { + return fmt.Errorf("antidebug: suspicious env var %s=%s", v, os.Getenv(v)) + } + } + return nil +} + +func checkParentProcess() error { + ppid := os.Getppid() + if ppid <= 1 { + return nil + } + + commPath := fmt.Sprintf("/proc/%d/comm", ppid) + comm, err := os.ReadFile(commPath) + if err != nil { + return nil + } + + parent := string(comm) + debuggers := []string{ + "gdb", "lldb", "strace", "ltrace", "ida", "ida64", + "radare2", "r2", "ghidra", "x64dbg", "ollydbg", + "delve", "debugserver", + } + + for _, d := range debuggers { + if len(parent) >= len(d) && parent[:len(d)] == d { + return fmt.Errorf("antidebug: parent process is debugger: %s", parent) + } + } + return nil +} + +func AntiAttach() { + go func() { + for { + time.Sleep(500 * time.Millisecond) + if err := checkPtrace(); err != nil { + os.Exit(66) + } + } + }() +} + +func AntiDump() { + go func() { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + for range ticker.C { + _ = disableCoreDump() + } + }() +} + +func CheckHooks() error { + if err := checkFunctionPrologues(); err != nil { + return err + } + if err := scanForBreakpoints(); err != nil { + return err + } + return nil +} diff --git a/pkg/antidebug/antidebug_windows.go b/pkg/antidebug/antidebug_windows.go new file mode 100644 index 0000000..2bf8fe5 --- /dev/null +++ b/pkg/antidebug/antidebug_windows.go @@ -0,0 +1,266 @@ +//go:build windows + +package antidebug + +import ( + "fmt" + "os" + "syscall" + "time" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + ntdll = syscall.NewLazyDLL("ntdll.dll") + procIsDebuggerPresent = kernel32.NewProc("IsDebuggerPresent") + procCheckRemoteDebugger = kernel32.NewProc("CheckRemoteDebuggerPresent") + procNtQueryInformationProc = ntdll.NewProc("NtQueryInformationProcess") + procNtSetInformationThread = ntdll.NewProc("NtSetInformationThread") + procOutputDebugStringW = kernel32.NewProc("OutputDebugStringW") + procSetUnhandledException = kernel32.NewProc("SetUnhandledExceptionFilter") +) + +const ( + processDebugPort = 7 + processDebugObjectHandle = 0x1E + processDebugFlags = 0x1F + threadHideFromDebugger = 0x11 +) + +func checkPtrace() error { + ret, _, _ := procIsDebuggerPresent.Call() + if ret != 0 { + return fmt.Errorf("antidebug: IsDebuggerPresent returned true") + } + + var isRemoteDebugged int32 + currentProc, _ := syscall.GetCurrentProcess() + ret, _, _ = procCheckRemoteDebugger.Call( + uintptr(currentProc), + uintptr(unsafe.Pointer(&isRemoteDebugged)), + ) + if ret != 0 && isRemoteDebugged != 0 { + return fmt.Errorf("antidebug: CheckRemoteDebuggerPresent detected debugger") + } + + var port uint32 + var returnLength uint32 + ret, _, _ = procNtQueryInformationProc.Call( + uintptr(currentProc), + processDebugPort, + uintptr(unsafe.Pointer(&port)), + unsafe.Sizeof(port), + uintptr(unsafe.Pointer(&returnLength)), + ) + if ret == 0 && port != 0 { + return fmt.Errorf("antidebug: NtQueryInformationProcess(ProcessDebugPort) detected debugger (port=%d)", port) + } + + var debugHandle uintptr + ret, _, _ = procNtQueryInformationProc.Call( + uintptr(currentProc), + processDebugObjectHandle, + uintptr(unsafe.Pointer(&debugHandle)), + unsafe.Sizeof(debugHandle), + uintptr(unsafe.Pointer(&returnLength)), + ) + if ret == 0 { + return fmt.Errorf("antidebug: NtQueryInformationProcess(ProcessDebugObjectHandle) detected debugger") + } + + var debugFlags uint32 + ret, _, _ = procNtQueryInformationProc.Call( + uintptr(currentProc), + processDebugFlags, + uintptr(unsafe.Pointer(&debugFlags)), + unsafe.Sizeof(debugFlags), + uintptr(unsafe.Pointer(&returnLength)), + ) + if ret == 0 && debugFlags == 0 { + return fmt.Errorf("antidebug: NtQueryInformationProcess(ProcessDebugFlags) detected debugger") + } + + return nil +} + +func checkPEB() error { + var pebBase uintptr + var returnLength uint32 + currentProc, _ := syscall.GetCurrentProcess() + + type processBasicInfo struct { + Reserved1 uintptr + PebBaseAddress uintptr + Reserved2 [2]uintptr + UniqueProcessID uintptr + Reserved3 uintptr + } + + var info processBasicInfo + ret, _, _ := procNtQueryInformationProc.Call( + uintptr(currentProc), + 0, + uintptr(unsafe.Pointer(&info)), + unsafe.Sizeof(info), + uintptr(unsafe.Pointer(&returnLength)), + ) + if ret != 0 { + return nil + } + + pebBase = info.PebBaseAddress + if pebBase == 0 { + return nil + } + + beingDebugged := *(*byte)(unsafe.Pointer(pebBase + 2)) + if beingDebugged != 0 { + return fmt.Errorf("antidebug: PEB.BeingDebugged is set") + } + + ntGlobalFlag := *(*uint32)(unsafe.Pointer(pebBase + 0xBC)) + const FLG_HEAP_ENABLE_TAIL_CHECK = 0x10 + const FLG_HEAP_ENABLE_FREE_CHECK = 0x20 + const FLG_HEAP_VALIDATE_PARAMETERS = 0x40 + debugFlags := FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS + if ntGlobalFlag&uint32(debugFlags) != 0 { + return fmt.Errorf("antidebug: PEB.NtGlobalFlag has debug flags (0x%x)", ntGlobalFlag) + } + + return nil +} + +func checkHardwareBreakpoints() error { + type context struct { + ContextFlags uint32 + Dr0 uintptr + Dr1 uintptr + Dr2 uintptr + Dr3 uintptr + Dr6 uintptr + Dr7 uintptr + FloatSave [112]byte + SegGs uint32 + SegFs uint32 + SegEs uint32 + SegDs uint32 + Edi uintptr + Esi uintptr + Ebx uintptr + Edx uintptr + Ecx uintptr + Eax uintptr + Ebp uintptr + Eip uintptr + SegCs uint32 + EFlags uint32 + Esp uintptr + SegSs uint32 + ExtendedRegisters [512]byte + } + + threadHandle, _ := syscall.GetCurrentThread() + + var ctx context + ctx.ContextFlags = 0x00100010 + + procGetThreadContext := kernel32.NewProc("GetThreadContext") + ret, _, _ := procGetThreadContext.Call( + uintptr(threadHandle), + uintptr(unsafe.Pointer(&ctx)), + ) + if ret == 0 { + return nil + } + + if ctx.Dr0 != 0 || ctx.Dr1 != 0 || ctx.Dr2 != 0 || ctx.Dr3 != 0 { + return fmt.Errorf("antidebug: hardware breakpoints detected (dr0=0x%x dr1=0x%x dr2=0x%x dr3=0x%x)", + ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3) + } + + return nil +} + +func hideFromDebugger() { + threadHandle, _ := syscall.GetCurrentThread() + procNtSetInformationThread.Call( + uintptr(threadHandle), + threadHideFromDebugger, + 0, + 0, + ) +} + +func disableCoreDump() error { + return nil +} + +func checkTiming() error { + start := time.Now() + sum := 0 + for i := 0; i < 1000000; i++ { + sum += i + } + elapsed := time.Since(start) + + if elapsed > 200*time.Millisecond { + return fmt.Errorf("antidebug: timing anomaly detected (%v for 1M iterations)", elapsed) + } + + _ = sum + return nil +} + +func checkEnv() error { + suspiciousVars := []string{ + "GODEBUG", + "DELVE_LISTENER", + "DEBUGINFOD_URL", + "RR_LOG_FILE", + "_JAVA_OPTIONS", + } + + for _, v := range suspiciousVars { + if os.Getenv(v) != "" { + return fmt.Errorf("antidebug: suspicious env var %s=%s", v, os.Getenv(v)) + } + } + return nil +} + +func checkParentProcess() error { + return nil +} + +func AntiAttach() { + go func() { + hideFromDebugger() + for { + time.Sleep(500 * time.Millisecond) + if err := checkPtrace(); err != nil { + os.Exit(66) + } + } + }() +} + +func AntiDump() { + go func() { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + for range ticker.C { + _ = disableCoreDump() + } + }() +} + +func CheckHooks() error { + if err := checkFunctionPrologues(); err != nil { + return err + } + if err := scanForBreakpoints(); err != nil { + return err + } + return nil +} diff --git a/pkg/integrity/integrity.go b/pkg/integrity/integrity.go index 7e330d9..d19f6af 100644 --- a/pkg/integrity/integrity.go +++ b/pkg/integrity/integrity.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "debug/elf" "debug/macho" + "debug/pe" "encoding/binary" "fmt" "os" @@ -97,6 +98,8 @@ func hashTextSection(path string) ([32]byte, error) { return hashTextELF(path) case "darwin": return hashTextMacho(path) + case "windows": + return hashTextPE(path) default: return hashWholeFile(path) } @@ -139,6 +142,25 @@ func hashTextMacho(path string) ([32]byte, error) { return hashWholeFile(path) } +func hashTextPE(path string) ([32]byte, error) { + f, err := pe.Open(path) + if err != nil { + return [32]byte{}, err + } + defer f.Close() + + for _, section := range f.Sections { + if section.Name == ".text" { + data, err := section.Data() + if err != nil { + return [32]byte{}, err + } + return sha256.Sum256(data), nil + } + } + return hashWholeFile(path) +} + func hashWholeFile(path string) ([32]byte, error) { data, err := os.ReadFile(path) if err != nil { diff --git a/pkg/syscallobf/syscall_darwin.go b/pkg/syscallobf/syscall_darwin.go index c5d2017..844cc90 100644 --- a/pkg/syscallobf/syscall_darwin.go +++ b/pkg/syscallobf/syscall_darwin.go @@ -1,39 +1,121 @@ +//go:build darwin + package syscallobf -import "syscall" +import ( + "crypto/rand" + "syscall" + "unsafe" +) + +var ( + obfPtraceTrap ObfuscatedCall + obfGetpidTrap ObfuscatedCall + obfKillTrap ObfuscatedCall + obfOpenTrap ObfuscatedCall + obfCloseTrap ObfuscatedCall + obfReadTrap ObfuscatedCall + obfLseekTrap ObfuscatedCall + obfMmapTrap ObfuscatedCall + obfMprotectTrap ObfuscatedCall +) + +func init() { + var key [4]byte + if _, err := rand.Read(key[:]); err != nil { + panic("syscallobf: failed to generate random key: " + err.Error()) + } + + obfPtraceTrap = encode(0x200001A, key) + obfGetpidTrap = encode(0x2000027, key) + obfKillTrap = encode(0x2000025, key) + obfOpenTrap = encode(0x2000005, key) + obfCloseTrap = encode(0x2000006, key) + obfReadTrap = encode(0x2000003, key) + obfLseekTrap = encode(0x20000C7, key) + obfMmapTrap = encode(0x20000C5, key) + obfMprotectTrap = encode(0x200004A, key) +} func ObfPtrace(request int, pid uintptr, addr uintptr, data uintptr) (uintptr, uintptr, syscall.Errno) { - return 0, 0, syscall.ENOSYS + trap := obfPtraceTrap.Num() + r1, r2, errno := syscall.RawSyscall6(trap, uintptr(request), pid, addr, data, 0, 0) + return r1, r2, errno } func ObfGetpid() int { - return 0 + trap := obfGetpidTrap.Num() + r1, _, _ := syscall.RawSyscall(trap, 0, 0, 0) + return int(r1) } func ObfKill(pid int, sig int) error { - return syscall.ENOSYS + trap := obfKillTrap.Num() + _, _, errno := syscall.RawSyscall(trap, uintptr(pid), uintptr(sig), 0) + if errno != 0 { + return errno + } + return nil } func ObfOpen(path string, flags int, mode int) (int, error) { - return -1, syscall.ENOSYS + trap := obfOpenTrap.Num() + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return -1, err + } + r1, _, errno := syscall.RawSyscall(trap, uintptr(unsafe.Pointer(pathBytes)), uintptr(flags), uintptr(mode)) + if errno != 0 { + return int(r1), errno + } + return int(r1), nil } func ObfClose(fd int) error { - return syscall.ENOSYS + trap := obfCloseTrap.Num() + _, _, errno := syscall.RawSyscall(trap, uintptr(fd), 0, 0) + if errno != 0 { + return errno + } + return nil } func ObfRead(fd int, buf []byte) (int, error) { - return 0, syscall.ENOSYS -} - -func ObfMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset uintptr) (uintptr, error) { - return 0, syscall.ENOSYS -} - -func ObfMprotect(addr uintptr, length uintptr, prot int) error { - return syscall.ENOSYS + trap := obfReadTrap.Num() + var p *byte + if len(buf) > 0 { + p = &buf[0] + } + r1, _, errno := syscall.RawSyscall(trap, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(len(buf))) + if errno != 0 { + return int(r1), errno + } + return int(r1), nil } func ObfLseek(fd int, offset int64, whence int) (int64, error) { - return 0, syscall.ENOSYS + trap := obfLseekTrap.Num() + r1, _, errno := syscall.RawSyscall(trap, uintptr(fd), uintptr(offset), uintptr(whence)) + if errno != 0 { + return int64(r1), errno + } + return int64(r1), nil +} + +func ObfMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset uintptr) (uintptr, error) { + trap := obfMmapTrap.Num() + r1, _, errno := syscall.Syscall6(trap, addr, length, uintptr(prot), uintptr(flags), uintptr(fd), offset) + if errno != 0 { + return 0, errno + } + return r1, nil +} + +func ObfMprotect(addr uintptr, length uintptr, prot int) error { + trap := obfMprotectTrap.Num() + _, _, errno := syscall.RawSyscall(trap, addr, length, uintptr(prot)) + if errno != 0 { + return errno + } + return nil } diff --git a/pkg/syscallobf/syscall_windows.go b/pkg/syscallobf/syscall_windows.go new file mode 100644 index 0000000..9c6619c --- /dev/null +++ b/pkg/syscallobf/syscall_windows.go @@ -0,0 +1,195 @@ +//go:build windows + +package syscallobf + +import ( + "crypto/rand" + "sync" + "syscall" + "unsafe" +) + +var ( + modntdll = syscall.NewLazyDLL("ntdll.dll") + + procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess") + procNtSetInformationThread = modntdll.NewProc("NtSetInformationThread") + procNtClose = modntdll.NewProc("NtClose") + procNtProtectVirtualMemory = modntdll.NewProc("NtProtectVirtualMemory") + procNtReadVirtualMemory = modntdll.NewProc("NtReadVirtualMemory") + procNtOpenProcess = modntdll.NewProc("NtOpenProcess") + + obfPtraceTrap ObfuscatedCall + obfGetpidTrap ObfuscatedCall + obfKillTrap ObfuscatedCall + obfOpenTrap ObfuscatedCall + obfCloseTrap ObfuscatedCall + obfReadTrap ObfuscatedCall + obfLseekTrap ObfuscatedCall + obfMmapTrap ObfuscatedCall + obfMprotectTrap ObfuscatedCall +) + +func init() { + var key [4]byte + if _, err := rand.Read(key[:]); err != nil { + panic("syscallobf: failed to generate random key: " + err.Error()) + } + + obfCloseTrap = encode(0, key) + obfReadTrap = encode(0, key) + obfOpenTrap = encode(0, key) + obfLseekTrap = encode(0, key) + obfMmapTrap = encode(0, key) + obfMprotectTrap = encode(0, key) + obfPtraceTrap = encode(0, key) + obfGetpidTrap = encode(0, key) + obfKillTrap = encode(0, key) +} + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetCurrentPID = kernel32.NewProc("GetCurrentProcessId") + procOpenProcess = kernel32.NewProc("OpenProcess") + procCloseHandle = kernel32.NewProc("CloseHandle") + procReadProcessMem = kernel32.NewProc("ReadProcessMemory") +) + +func ObfGetpid() int { + r1, _, _ := procGetCurrentPID.Call() + return int(r1) +} + +func ObfOpen(path string, flags int, mode int) (int, error) { + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return -1, err + } + access := uint32(syscall.GENERIC_READ) + if flags&syscall.O_WRONLY != 0 { + access = syscall.GENERIC_WRITE + } + if flags&syscall.O_RDWR != 0 { + access = syscall.GENERIC_READ | syscall.GENERIC_WRITE + } + creation := uint32(syscall.OPEN_EXISTING) + if flags&syscall.O_CREAT != 0 { + creation = syscall.CREATE_ALWAYS + } + h, _, err := syscall.CreateFile(p, access, syscall.FILE_SHARE_READ, nil, creation, syscall.FILE_ATTRIBUTE_NORMAL, 0) + if err != nil && err.(syscall.Errno) != 0 { + return -1, err + } + return int(h), nil +} + +func ObfClose(fd int) error { + r1, _, err := procCloseHandle.Call(uintptr(fd)) + if r1 == 0 { + return err + } + return nil +} + +func ObfRead(fd int, buf []byte) (int, error) { + var bytesRead uint32 + var p *byte + if len(buf) > 0 { + p = &buf[0] + } + r1, _, err := syscall.ReadFile( + syscall.Handle(fd), + buf, + &bytesRead, + nil, + ) + if r1 == 0 { + return int(bytesRead), err + } + return int(bytesRead), nil +} + +func ObfLseek(fd int, offset int64, whence int) (int64, error) { + var newOff int64 + high := int32(offset >> 32) + r1, _, err := syscall.Seek(syscall.Handle(fd), int32(offset), high) + if r1 == 0xffffffff && err != nil { + return 0, err + } + _ = newOff + return int64(r1), nil +} + +func ObfMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset uintptr) (uintptr, error) { + flProtect := uint32(syscall.PAGE_READWRITE) + if prot&syscall.PROT_EXEC != 0 { + flProtect = syscall.PAGE_EXECUTE_READWRITE + } + h, _, err := syscall.CreateFileMapping( + syscall.Handle(fd), + nil, + flProtect, + uint32(length>>32), + uint32(length), + nil, + ) + if h == 0 { + return 0, err + } + return uintptr(h), nil +} + +func ObfMprotect(addr uintptr, length uintptr, prot int) error { + var oldProtect uint32 + flProtect := uint32(syscall.PAGE_READWRITE) + if prot&syscall.PROT_EXEC != 0 { + flProtect = syscall.PAGE_EXECUTE_READWRITE + } + r1, _, err := procNtProtectVirtualMemory.Call( + uintptr(0xffffffffffffffff), + uintptr(unsafe.Pointer(&addr)), + uintptr(unsafe.Pointer(&length)), + uintptr(flProtect), + uintptr(unsafe.Pointer(&oldProtect)), + ) + if r1 != 0 { + return err + } + return nil +} + +type windowsObfCall struct { + once sync.Once + procAddr uintptr + proc *syscall.LazyProc +} + +func (w *windowsObfCall) Call(args ...uintptr) (uintptr, uintptr, error) { + w.once.Do(func() { + if w.proc != nil { + w.procAddr = w.proc.Addr() + } + }) + return syscall.Syscall(w.procAddr, uintptr(len(args)), args[0], args[1], args[2]) +} + +func NtQueryInformationProcess(handle uintptr, infoclass uint32, info uintptr, infolen uint32, retlen *uint32) uintptr { + r1, _, _ := procNtQueryInformationProcess.Call( + handle, + uintptr(infoclass), + info, + uintptr(infolen), + uintptr(unsafe.Pointer(retlen)), + ) + return r1 +} + +func NtSetInformationThread(handle uintptr, infoclass uint32, info uintptr, infolen uint32) uintptr { + r1, _, _ := procNtSetInformationThread.Call( + handle, + uintptr(infoclass), + info, + uintptr(infolen), + ) + return r1 +} diff --git a/pkg/vm/compiler.go b/pkg/vm/compiler.go index e9319a3..de21c6e 100644 --- a/pkg/vm/compiler.go +++ b/pkg/vm/compiler.go @@ -1,7 +1,9 @@ package vm import ( + "crypto/rand" "fmt" + "math/big" ) type Instruction struct { @@ -15,7 +17,15 @@ type LabelledInstr struct { Target string } +type CompileOpts struct { + NoJunk bool +} + func Compile(program []LabelledInstr) []byte { + return CompileWith(program, CompileOpts{}) +} + +func CompileWith(program []LabelledInstr, opts CompileOpts) []byte { labelAddrs := make(map[string]int) type fixup struct { @@ -26,11 +36,18 @@ func Compile(program []LabelledInstr) []byte { var fixups []fixup var bytecode []byte + junkOpcodes := []Opcode{opJunkA, opJunkB, opJunkC, opJunkD} + for _, entry := range program { if entry.Label != "" { labelAddrs[entry.Label] = len(bytecode) } + if !opts.NoJunk && shouldInsertJunk() { + junkOp := junkOpcodes[randIntn(len(junkOpcodes))] + bytecode = append(bytecode, encodeOp(junkOp)) + } + instr := entry.Instr isJump := instr.Op == OpJmp || instr.Op == OpJz || instr.Op == OpJnz @@ -64,3 +81,18 @@ func Compile(program []LabelledInstr) []byte { return bytecode } + +func shouldInsertJunk() bool { + return randIntn(3) == 0 +} + +func randIntn(n int) int { + if n <= 0 { + return 0 + } + b, err := rand.Int(rand.Reader, big.NewInt(int64(n))) + if err != nil { + return 0 + } + return int(b.Int64()) +} diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index e3f7555..7d1c75b 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -430,7 +430,7 @@ func TestStepwiseExecution(t *testing.T) { {Instr: Instruction{Op: OpHalt}}, } - code := Compile(program) + code := CompileWith(program, CompileOpts{NoJunk: true}) vm := NewVM(code, nil) steps := 0 @@ -461,8 +461,13 @@ func TestXorObfuscationDeterminism(t *testing.T) { {Instr: Instruction{Op: OpHalt}}, } - code1 := Compile(program) - code2 := Compile(program) + opts := CompileOpts{NoJunk: true} + code1 := CompileWith(program, opts) + code2 := CompileWith(program, opts) + + if len(code1) != len(code2) { + t.Fatalf("bytecode length differs: %d vs %d", len(code1), len(code2)) + } for i := range code1 { if code1[i] != code2[i] { @@ -487,9 +492,8 @@ func TestBytecodeIsXORed(t *testing.T) { {Instr: Instruction{Op: OpHalt}}, } - code := Compile(program) + code := CompileWith(program, CompileOpts{NoJunk: true}) - // First byte should be OpPush ^ dispatchKey, not OpPush itself rawPush := byte(OpPush) ^ dispatchKey if code[0] != rawPush { t.Errorf("expected bytecode[0]=0x%02X (XOR'd PUSH), got 0x%02X", rawPush, code[0]) @@ -501,6 +505,24 @@ func TestBytecodeIsXORed(t *testing.T) { } } +func TestJunkOpcodesCorrectness(t *testing.T) { + program := []LabelledInstr{ + {Instr: Instruction{Op: OpPush, Args: []int64{10}}}, + {Instr: Instruction{Op: OpPush, Args: []int64{20}}}, + {Instr: Instruction{Op: OpAdd}}, + {Instr: Instruction{Op: OpHalt}}, + } + + for i := 0; i < 50; i++ { + code := Compile(program) + vm := NewVM(code, nil) + result := vm.Run() + if result != 30 { + t.Fatalf("iteration %d: expected 30, got %d (bytecode len %d)", i, result, len(code)) + } + } +} + func TestOrOp(t *testing.T) { // 0x0F OR 0xF0 = 0xFF program := []LabelledInstr{