mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-14 05:48:22 +00:00
.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package antidebug
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
offsetofDR0 = 6 * 8 // offsetof(struct user, u_debugreg[0])
|
||||
offsetofDR7 = 13 * 8 // offsetof(struct user, u_debugreg[7])
|
||||
)
|
||||
|
||||
func checkHardwareBreakpoints() bool {
|
||||
pid, _, _ := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
|
||||
|
||||
if pid == 0 {
|
||||
// Child: attach to parent, read debug registers, report via exit code
|
||||
syscall.RawSyscall(syscall.SYS_PTRACE, uintptr(syscall.PTRACE_ATTACH), uintptr(syscall.Getppid()), 0)
|
||||
var status syscall.WaitStatus
|
||||
syscall.RawSyscall(syscall.SYS_WAIT4, uintptr(syscall.Getppid()), uintptr(unsafe.Pointer(&status)), 0, 0)
|
||||
|
||||
detected := false
|
||||
for i := 0; i < 4; i++ {
|
||||
drVal, _, _ := syscall.RawSyscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
uintptr(syscall.PTRACE_PEEKUSER),
|
||||
uintptr(syscall.Getppid()),
|
||||
uintptr(offsetofDR0+i*8),
|
||||
0, 0, 0,
|
||||
)
|
||||
if drVal != 0 {
|
||||
detected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !detected {
|
||||
dr7, _, _ := syscall.RawSyscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
uintptr(syscall.PTRACE_PEEKUSER),
|
||||
uintptr(syscall.Getppid()),
|
||||
uintptr(offsetofDR7),
|
||||
0, 0, 0,
|
||||
)
|
||||
// Bits 0,2,4,6 enable DR0-DR3; bits 1,3,5,7 are condition bits
|
||||
// If any enable bit is set, a hardware breakpoint is active
|
||||
if dr7&0x55 != 0 {
|
||||
detected = true
|
||||
}
|
||||
}
|
||||
|
||||
syscall.RawSyscall(syscall.SYS_PTRACE, uintptr(syscall.PTRACE_DETACH), uintptr(syscall.Getppid()), 0)
|
||||
|
||||
exitCode := 0
|
||||
if detected {
|
||||
exitCode = 1
|
||||
}
|
||||
syscall.RawSyscall(syscall.SYS_EXIT, uintptr(exitCode), 0, 0)
|
||||
}
|
||||
|
||||
// Parent: wait for child result
|
||||
var status syscall.WaitStatus
|
||||
syscall.RawSyscall(syscall.SYS_WAIT4, pid, uintptr(unsafe.Pointer(&status)), 0, 0)
|
||||
return status.ExitStatus() == 1
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//go:build windows
|
||||
|
||||
package antidebug
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const _CONTEXT_DEBUG_REGISTERS = 0x00100010
|
||||
|
||||
type contextDebugRegs struct {
|
||||
Dr0 uint64
|
||||
Dr1 uint64
|
||||
Dr2 uint64
|
||||
Dr3 uint64
|
||||
Dr6 uint64
|
||||
Dr7 uint64
|
||||
}
|
||||
|
||||
func checkHardwareBreakpoints() bool {
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
getCurrentThread := kernel32.NewProc("GetCurrentThread")
|
||||
getThreadContext := kernel32.NewProc("GetThreadContext")
|
||||
|
||||
thread, _, _ := getCurrentThread.Call()
|
||||
|
||||
ctx := struct {
|
||||
contextFlags uint32
|
||||
_ [512]byte
|
||||
debugRegs contextDebugRegs
|
||||
}{}
|
||||
ctx.contextFlags = _CONTEXT_DEBUG_REGISTERS
|
||||
|
||||
ret, _, _ := getThreadContext.Call(
|
||||
thread,
|
||||
uintptr(unsafe.Pointer(&ctx)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if ctx.debugRegs.Dr0 != 0 || ctx.debugRegs.Dr1 != 0 ||
|
||||
ctx.debugRegs.Dr2 != 0 || ctx.debugRegs.Dr3 != 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if ctx.debugRegs.Dr7&0x55 != 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package antidebug
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var suspiciousPatterns = []string{
|
||||
"frida", "dynamorio", "pin", "hook", "inject",
|
||||
"intercept", "instrument", "ltrace", "strace",
|
||||
}
|
||||
|
||||
func checkReturnAddresses() bool {
|
||||
var pcs [16]uintptr
|
||||
n := runtime.Callers(2, pcs[:])
|
||||
if n == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
fn := runtime.FuncForPC(pcs[i])
|
||||
if fn == nil {
|
||||
return true
|
||||
}
|
||||
name := strings.ToLower(fn.Name())
|
||||
for _, pat := range suspiciousPatterns {
|
||||
if strings.Contains(name, pat) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !checkPCInBinary(pcs[0]) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkPCInBinary(pc uintptr) bool {
|
||||
f, err := os.Open("/proc/self/maps")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
selfPath, _ := os.Executable()
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, "r-xp") && !strings.Contains(line, "r--p") {
|
||||
continue
|
||||
}
|
||||
if selfPath != "" && !strings.Contains(line, selfPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
var start, end uintptr
|
||||
if _, err := fmt.Sscanf(line, "%x-%x", &start, &end); err != nil {
|
||||
continue
|
||||
}
|
||||
if pc >= start && pc < end {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package antidebug
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var signalTrapDetected bool
|
||||
|
||||
func checkSignalTrap() bool {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGTRAP)
|
||||
|
||||
signalTrapDetected = false
|
||||
go func() {
|
||||
select {
|
||||
case <-ch:
|
||||
signalTrapDetected = true
|
||||
case <-time.After(200 * time.Millisecond):
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGTRAP)
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
signal.Stop(ch)
|
||||
|
||||
// If the handler received the signal, no debugger intercepted it.
|
||||
// If signalTrapDetected is false, a debugger caught the SIGTRAP.
|
||||
return !signalTrapDetected
|
||||
}
|
||||
Reference in New Issue
Block a user