直接系统调用之从上层API到下层API的旅程
字数 2416 2025-10-01 14:05:44
直接系统调用技术:从原理到实战实现
1. 系统调用基础概念
1.1 什么是系统调用
系统调用(System Call/Syscall)是用户模式程序与内核模式交互的接口机制。当用户程序需要访问受保护的内核资源或服务时,必须通过系统调用实现从用户态(Ring 3)到内核态(Ring 0)的切换。
1.2 Windows API调用链示例
以Notepad创建文件为例的调用流程:
- 调用Kernel32.dll中的CreateFileW
- Kernel32.dll调用Kernelbase.dll中的CreateFileW
- Kernelbase.dll调用Ntdll.dll中的NtCreateFile
- Ntdll.dll中的NtCreateFile包含Syscall指令,触发模式切换
1.3 Syscall指令架构差异
- x64处理器:使用
syscall指令 - x86处理器:使用
sysenter指令 - 早期x86系统:使用
int 2eh指令
1.4 系统调用结构
系统调用由两部分组成:
- Syscall Stub(系统调用存根):准备工作
- 将系统调用号放入指定寄存器
- 设置参数到寄存器或堆栈
- Syscall指令:实际执行模式切换
1.5 系统调用号特性
系统调用号(System Call Number/System Service Number/System Call ID)是内核函数的唯一标识。关键特性:
- 同一内核函数在不同Windows版本中具有不同的调用号
- 调用号在执行Syscall指令时必须正确传递
2. 需要系统调用的场景
2.1 必须使用系统调用的操作
- 硬件设备访问(扫描仪、打印机等)
- 网络连接和数据传输
- 文件读写操作
- 任何需要内核处理的任务
2.2 无需系统调用的操作
- 数学计算(如1+1=2)
- 用户态内存管理操作:
- malloc的"小内存分配"(使用进程堆缓存时)
- memcpy等内存拷贝操作
3. 直接系统调用技术详解
3.1 技术定义
直接系统调用是攻击者在恶意软件中使用的技术,通过自行实现Syscall指令来绕过AV/EDR在用户层对ntdll.dll的hook。
3.2 技术原理
用户模式下的恶意软件自行实现Syscall指令,直接进入内核模式,避免了通过ntdll.dll的正常路径。
3.3 为什么使用直接系统调用
EDR常用的Hook技术:
- Import Address Table (IAT) hooking:易于绕过
- SSDT hooking:Windows引入Patch Guard后无法使用
- Inline API hooking:当前主流检测技术
Inline Hooking通过在内存中添加无条件跳转指令,跳转到安全厂商的Hooking.dll进行分析:
- 研判为非恶意:跳转回原执行流程
- 研判为恶意:终止执行
3.4 EDR Hook检测方法
无EDR Hook环境(仅Windows Defender):
- Windbg和x64dbg显示正常的NtAllocateVirtualMemory调用
- 无额外跳转指令
有EDR Hook环境:
- 存在
jmp ntdll.7FFCC600A827等跳转指令 - Step into跟踪会进入EDR厂商的Hooking.dll
4. 实战实现:直接系统调用Loader
4.1 工具和资源准备
- 主要工具:Visual Studio C++开发环境
- 关键项目:SysWhispers2(https://github.com/jthuraisamy/SysWhispers2)
- 分析工具:API Monitor、Dumpbin、x64dbg
4.2 实现步骤
步骤1:Win32 API版本Loader
首先使用标准Win32 API编写基础Loader:
- shellcode位于.text节区
- 超过255字节的shellcode使用.rdata节保存
- 编译后使用x64dbg查看,可见syscall指令位于ntdll.dll内存中
步骤2:生成直接系统调用代码
使用SysWhispers2生成替代代码:
- syscalls.h:头文件
- syscalls.c:源文件
- syscallsstubs.std.x64.asm:资源文件(Microsoft Macro Assembler)
步骤3:替换实现
用SysWhispers2生成的文件替代ntdll依赖,实现直接系统调用:
- 主要修改main.cpp中的调用方式
- 生成的syscall指令将位于程序自身内存中,而非ntdll.dll
4.3 技术分析要点
- PE结构分析:使用Dumpbin检查导入表
- 内存执行分析:使用x64dbg验证syscall指令位置
- 节区特征:确认syscall指令在.text节执行
- API监控:使用API Monitor验证是否绕过了常规API调用链
5. 检测与对抗考虑
5.1 检测直接系统调用的方法
- 监控非标准位置的syscall指令执行
- 分析PE导入表异常(缺少预期的ntdll导入)
- 检测用户态系统调用存根的实现
5.2 进阶对抗技术
- Unhooking:恢复被Hook的原始函数
- 间接系统调用:通过合法模块间接执行系统调用
- 系统调用号混淆:动态获取和计算系统调用号
6. 总结
直接系统调用技术通过绕过用户态的API监控机制,为防御方提供了新的挑战。理解其原理和实现方式对攻防双方都至关重要:攻击者可以更有效地规避检测,防御者则可以开发相应的检测策略。这种技术的核心在于理解Windows系统调用机制和EDR的检测原理,并通过工具实现自定义的系统调用路径。
随着安全厂商不断改进检测能力,直接系统调用技术也在持续演进,包括系统调用号的动态解析、调用路径的随机化等高级技术,这些都是二进制安全领域持续对抗的焦点。