mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-15 05:58:22 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
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 := checkTiming(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkEnv(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkParentProcess(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := CheckHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build darwin
|
||||
|
||||
package antidebug
|
||||
|
||||
func checkFunctionPrologues() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanForBreakpoints() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
//go:build linux
|
||||
|
||||
package antidebug
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/self-evolving-research/obfuscator/pkg/syscallobf"
|
||||
)
|
||||
|
||||
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()},
|
||||
{"fmt.Printf", reflect.ValueOf(fmt.Printf).Pointer()},
|
||||
{"os.ReadFile", reflect.ValueOf(os.ReadFile).Pointer()},
|
||||
}
|
||||
|
||||
for _, t := range targets {
|
||||
if t.addr == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
prologue, err := readProcMemory(t.addr, t.addr+8)
|
||||
if err != nil || 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)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanForBreakpoints() error {
|
||||
mapsData, err := readProcFile("/proc/self/maps")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(mapsData)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.Contains(parts[1], "x") {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) >= 6 && strings.HasPrefix(parts[5], "[") {
|
||||
continue
|
||||
}
|
||||
|
||||
addrRange := strings.Split(parts[0], "-")
|
||||
if len(addrRange) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
var start, end uintptr
|
||||
fmt.Sscanf(addrRange[0], "%x", &start)
|
||||
fmt.Sscanf(addrRange[1], "%x", &end)
|
||||
|
||||
if end <= start || end-start > 50*1024*1024 {
|
||||
continue
|
||||
}
|
||||
|
||||
mem, err := readProcMemory(start, end)
|
||||
if err != nil || len(mem) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
maxConsecutive := 0
|
||||
consecutive := 0
|
||||
for _, b := range mem {
|
||||
if b == 0xCC {
|
||||
consecutive++
|
||||
if consecutive > maxConsecutive {
|
||||
maxConsecutive = consecutive
|
||||
}
|
||||
} else {
|
||||
consecutive = 0
|
||||
}
|
||||
}
|
||||
|
||||
if maxConsecutive >= 8 {
|
||||
return fmt.Errorf("antidebug: breakpoint cluster (%d consecutive INT3) at 0x%x-0x%x", maxConsecutive, start, end)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readProcFile(path string) ([]byte, error) {
|
||||
fd, err := syscallobf.ObfOpen(path, 0, 0)
|
||||
if fd < 0 {
|
||||
return nil, err
|
||||
}
|
||||
defer syscallobf.ObfClose(fd)
|
||||
|
||||
var result []byte
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, readErr := syscallobf.ObfRead(fd, buf)
|
||||
if n > 0 {
|
||||
result = append(result, buf[:n]...)
|
||||
}
|
||||
if readErr != nil || n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func readProcMemory(start, end uintptr) ([]byte, error) {
|
||||
fd, err := syscallobf.ObfOpen("/proc/self/mem", 0, 0)
|
||||
if fd < 0 {
|
||||
return nil, err
|
||||
}
|
||||
defer syscallobf.ObfClose(fd)
|
||||
|
||||
size := int(end - start)
|
||||
if size <= 0 || size > 50*1024*1024 {
|
||||
return nil, fmt.Errorf("invalid region size")
|
||||
}
|
||||
|
||||
buf := make([]byte, size)
|
||||
|
||||
if _, seekErr := syscallobf.ObfLseek(fd, int64(start), 0); seekErr != nil {
|
||||
return nil, seekErr
|
||||
}
|
||||
|
||||
totalRead := 0
|
||||
for totalRead < size {
|
||||
n, readErr := syscallobf.ObfRead(fd, buf[totalRead:])
|
||||
if n > 0 {
|
||||
totalRead += n
|
||||
}
|
||||
if readErr != nil || n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return buf[:totalRead], nil
|
||||
}
|
||||
Reference in New Issue
Block a user