This commit is contained in:
2026-05-31 19:48:56 +01:00
parent 7f32417736
commit 68f8904282
39 changed files with 4519 additions and 5 deletions
+65
View File
@@ -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
}
+53
View File
@@ -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
}
+70
View File
@@ -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
}
+35
View File
@@ -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
}