模块 63 - Syscalls - 简介
恶意软件开发课程 - Syscalls - 简介
模块 63 - Syscalls - 简介#
Syscalls - 简介#
什么是 Syscalls (系统调用)#
Windows 系统调用 (System Calls),简称 Syscalls,是程序与操作系统内核交互的桥梁位。它允许程序请求特定的操作系统服务,如读取或写入文件、创建新进程或分配内存。
回顾之前的入门模块,WinAPI 函数底层实际上都是通过调用这些 Syscalls 来完成实际操作的。例如,当你调用 VirtualAlloc 或 VirtualAllocEx 时,系统底层会触发 NtAllocateVirtualMemory 系统调用。该系统调用会将用户提供的参数传递给 Windows 内核,执行请求的操作,并将结果返回给程序。
所有 Syscalls 都会返回一个 NTSTATUS 值 ↗ 来表示错误代码。如果操作成功,则返回 STATUS_SUCCESS(即 0)。
由于微软官方并未记录大部分 Syscalls,我们的 Syscalls 模块将主要参考以下文档:
NTDLL 与 Syscalls#
绝大多数系统调用都是从 ntdll.dll 中导出的。
为什么要使用 Syscalls?#
- 低级访问:使用系统调用可以获得操作系统的低级访问权限,执行一些标准 WinAPI 无法完成或实现起来非常复杂的任务。例如,
NtCreateUserProcess相比CreateProcess提供了更多的底层配置选项。 - 逃避防御:syscalls 常被用于绕过基于主机的安全解决方案(如 EDR/AV),我们将在后续模块中深入探讨这一点。
Zw 与 Nt 系统调用的区别#
你会发现系统调用通常有两种开头:Nt 和 Zw。
- Nt 系统调用:是用户模式 (User-mode) 程序的主要接口。这是大多数普通 Windows 程序使用的版本。
- Zw 系统调用:则是更底层的系统接口,通常用于内核模式 (Kernel-mode),比如驱动程序开发。
💡 初学者提示:在用户态下它们是一样的
在
ntdll.dll中,如果你查看NtAllocateVirtualMemory和ZwAllocateVirtualMemory的反汇编代码,你会发现它们的地址和代码逻辑是 完全相同 的。它们都指向同一个入口点。在用户层开发中,你可以互换使用它们,但按照惯例,我们通常使用Nt版本。
系统服务号 (SSN)#
每一个系统调用都有一个专属的编号,称为 系统服务号 (System Service Number, SSN)。内核正是通过这个编号来区分不同的系统调用。
- 例如:
NtAllocateVirtualMemory的 SSN 可能是 24。 - 而
NtProtectVirtualMemory的 SSN 可能是 80。
内核接收到编号后,查表就知道该执行哪个函数了。
不同 OS 版本的 SSN 差异#
非常重要的一点:SSN 并不是固定不变的。它会随着 Windows 版本(如 Win10 与 Win11)甚至细分版本(如 Windows 11 21h2 与 22h2)的变化而改变。
同一个 NtAllocateVirtualMemory,在版本 A 上是 24,在版本 B 上可能就变成了 34。
内存中的 Syscalls 排列#
虽然 SSN 在不同版本间会变,但在同一个系统中,它们的排列是有规律的。通常在内存中,系统调用是按顺序排列的,每个 SSN 都等于前一个 SSN + 1。理解这种关联性对于我们后续绕过某些安全监控(Hooking)非常关键。
Syscall 的汇编结构 (X64)#
一个标准的 X64 Syscall 汇编结构通常如下:
mov r10, rcx ; 将第一个参数从 rcx 移动到 r10 (内核要求)
mov eax, SSN ; 将系统服务号存入 eax
syscall ; 执行 syscall 指令,切入内核态
ret ; 返回asm
指令详解#
mov r10, rcx:在 x64 调用约定中,第一个参数在rcx中。但syscall指令会修改rcx寄存器,因此内核规定必须先把第一个参数挪到r10。mov eax, SSN:内核根据eax里的数字来判断程序到底想调用哪个服务。syscall:这是关键指令。它会让 CPU 立即从用户态切换到内核态,并将控制权交给操作系统的系统调用处理程序。
💡 初学者提示:WoW64 指令
在某些反汇编中,你可能看到
test和jne指令。那是为了在 64 位机器上兼容运行 32 位程序(WoW64)设计的。对于纯 64 位进程,这些指令不会影响执行逻辑,可以暂时忽略。
并非所有 NtAPI 都是 Syscalls#
虽然很多 ntdll.dll 导出的函数以 Nt 开头并返回 NTSTATUS,但它们不一定都是系统调用。
- Syscall:具有 SSN,且最终会通过
syscall指令进入内核。 - 常规 NtAPI:可能只是
ntdll内部的一些辅助工具函数(Low-level wrapper)。
例如:
LdrLoadDll:这是LoadLibrary底层使用的函数,但它本身不是 Syscall,它内部会去调用其他的 Syscall。SystemFunction032(RC4):这只是个算法函数,不涉及内核服务请求。
🎯 总结#
在本模块中,我们学习了:
- 内核大门:理解了 Syscall 是程序通往内核的终极关卡。
- SSN 原理:明白了内核是如何通过索引号(SSN)来分发任务的。
- 态转换:理解了
syscall指令是如何实现用户态到内核态的瞬间切换。
📚 下一步学习
下一个模块将介绍 Syscalls - Userland Hooking。我们将学习为什么安全软件要盯着这些 Syscall 看,以及它们是如何在这些“大门”前安插“保镖”的!