重写ring3 API函数
字数 1362 2025-08-29 08:30:05
重写Ring3 API函数实现免杀技术详解
一、系统调用基础概念
1.1 系统调用介绍
系统调用(System Call)是操作系统提供给应用程序与内核交互的核心接口,允许用户程序请求内核执行特权操作,是用户态和内核态之间的桥梁。
在Windows系统中:
Zw*或Nt*类型API通过syscall指令进入内核态- 这些API本质上是Ring3级别的,但通过系统调用触发内核特权操作
- 执行流程:用户态API → syscall指令 → 根据SSN(系统调用号)从SSDT查找 → 执行内核态对应函数
1.2 EDR的用户模式钩子机制
现代EDR通过在ntdll.dll中植入钩子来监控API调用:
- 使用
jmp指令覆盖目标函数(如NtOpenProcess)前5字节 - 重定向执行流到EDR自身的DLL进行参数检查
- 执行原始指令后跳回ntdll继续执行
二、直接系统调用技术原理
2.1 技术优势
- 绕过EDR在ntdll上的用户态钩子
- 直接通过汇编指令实现系统调用,避免被监控
2.2 技术局限性
- 直接使用syscall可能被高级EDR标记为异常行为
- 函数调用栈异常,容易被检测
- 仅对具备用户态Hook的EDR有效(如BitDefender)
2.3 系统调用流程分析(x64架构)
- 参数传递:前4个参数通过
rcx,rdx,r8,r9传递 - 寄存器准备:syscall执行会覆盖
rcx返回地址,需先保存到r10 - 系统调用号设置:不同Windows版本需要不同SSN
- 系统调用指令:现代CPU使用
syscall,旧系统使用int 2Eh
三、环境配置与实现
3.1 Visual Studio配置
- 项目属性 → 生成依赖性 → 勾选"masm"
- 添加.asm文件并设置属性:
- 项类型:自定义生成工具
- 命令行:
ml64 /c %(fileName).asm - 输出:
%(fileName).obj
3.2 汇编代码模板
; 示例:ZwAllocateVirtualMemory (SSN: 0x18)
_TEXT segment
ZwAllocateVirtualMemory proc
mov r10, rcx
mov eax, 18h ; SSN
syscall
ret
ZwAllocateVirtualMemory endp
end
3.3 C++调用示例
// 函数声明
EXTERN_C NTSTATUS ZwAllocateVirtualMemory(
HANDLE ProcessHandle,
PVOID* BaseAddress,
ULONG_PTR ZeroBits,
PSIZE_T RegionSize,
ULONG AllocationType,
ULONG Protect);
int main() {
PVOID baseAddr = nullptr;
SIZE_T size = 0x1000;
// 调用重写的API
ZwAllocateVirtualMemory(
GetCurrentProcess(),
&baseAddr,
0,
&size,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
return 0;
}
四、关键技术与注意事项
4.1 系统调用号(SSN)获取方法
- 使用调试工具(IDA/Windbg/x64dbg)查看ntdll导出函数
- 在"符号"界面找到目标函数对应的汇编代码
- 定位
mov eax, SSN指令获取调用号
4.2 版本兼容性问题
- 不同Windows版本SSN可能不同
- 示例代码仅适用于Windows 11,其他系统需调整
- 建议实现动态SSN获取机制
4.3 高级规避技术
- 间接系统调用:使调用栈看起来更合法
- 动态SSN解析:避免硬编码
- 调用栈混淆:防止ETW分析检测
五、防御与检测
5.1 EDR检测手段
- Windows事件跟踪(ETW)分析线程调用栈
- 检测异常的syscall指令使用模式
- 监控非标准系统调用路径
5.2 应对措施
- 模拟合法程序的调用模式
- 使用间接系统调用技术
- 结合其他混淆技术增强隐蔽性
六、扩展阅读方向
- 动态解析SSN的实现方法
- 间接系统调用技术细节
- 系统调用与内核PatchGuard的交互
- ETW监控机制与反制手段
通过重写Ring3 API函数实现直接系统调用,可以有效绕过EDR的用户态钩子,但需要注意调用栈的合法性和SSN的动态获取,才能在实际对抗中发挥更好的效果。