首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
编程技术
发新帖
2
2
[原创]Windows x64 系统调用链:从用户态到 NtCreateFile
发表于: 2026-6-17 13:18
1826
[原创]Windows x64 系统调用链:从用户态到 NtCreateFile
4seaynl
2026-6-17 13:18
1826
## 整体调用链概览 ``` 用户态 App │ ▼ NtCreateFile (ntdll.dll) ← 用户态存根函数 │ MOV EAX, syscall_number │ SYSCALL ▼ ═══════════════════════════════════ Ring3 → Ring0 切换 ═══════════════════ │ │ CPU 读取 MSR_LSTAR (0xC0000082) 获取入口地址 ▼ KiSystemCall64 (ntoskrnl.exe) ← 内核态系统调用入口 │ ▼ KiSystemServiceRepeat ← 查 SSDT / KiServiceTable │ ▼ nt!NtCreateFile (ntoskrnl.exe) ← 真正的内核实现 ``` --- ## 1. 用户态:ntdll!NtCreateFile 存根 ```asm ntdll!NtCreateFile: mov r10, rcx ; SYSCALL 会用 rcx 保存返回地址,所以先搬走第一个参数 mov eax, 0x55 ; 系统调用号(不同 Windows 版本不同) test byte ptr [SharedUserData+0x308], 1 jne use_int2e ; 极少走这条路径 syscall ; 触发系统调用 ret ``` **关键点:** - `EAX` = 系统调用号(syscall number),是 SSDT 中的索引 - `SYSCALL` 指令是 x64 唯一的快速系统调用机制(替代了 x86 的 `SYSENTER`/`INT 0x2E`) --- ## 2. SYSCALL 指令与 MSR_LSTAR ### MSR_LSTAR 的作用 | MSR 寄存器 | 地址 | 作用 | |---|---|---| | MSR_LSTAR | 0xC0000082 | 存储 **SYSCALL 的 Ring0 入口点**(RIP 目标) | | MSR_STAR | 0xC0000081 | 存储 CS/SS 选择子(高32位=用户态, 低32位=内核态) | | MSR_SFMASK | 0xC0000084 | SYSCALL 时对 RFLAGS 的掩码(关中断等) | **CPU 在执行 SYSCALL 时硬件自动完成:** ``` 1. RCX ← RIP(保存用户态返回地址) 2. R11 ← RFLAGS(保存用户态标志) 3. RFLAGS &= ~MSR_SFMASK(通常关闭 IF,即关中断) 4. CS ← MSR_STAR[47:32](内核代码段选择子) 5. SS ← MSR_STAR[47:32] + 8(内核栈段选择子) 6. RIP ← MSR_LSTAR(跳转到 KiSystemCall64) ``` > **注意:** SYSCALL **不切换 RSP**。栈的切换由 KiSystemCall64 代码自行完成。 ### 内核初始化时设置 MSR_LSTAR ```c // 在 KiInitializeBootStructures 或类似函数中 wrmsr(MSR_LSTAR, (ULONG64)KiSystemCall64); ``` --- ## 3. KiSystemCall64:内核入口处理 ```asm nt!KiSystemCall64: swapgs ; GS 切换到内核 PCR(KPCR) mov gs:[UserRsp], rsp ; 保存用户态 RSP mov rsp, gs:[KernelStack] ; 切换到内核栈 ; 构造 KTRAP_FRAME push UmSS ; 用户态 SS push gs:[UserRsp] ; 用户态 RSP push r11 ; 用户态 RFLAGS push UmCS ; 用户态 CS push rcx ; 用户态 RIP(返回地址) ; ... 保存其余寄存器 ... sti ; 重新开中断 ; 参数复制:将用户态栈上的参数复制到内核栈 ; (x64 前4个参数在寄存器,第5个起在用户态栈上) ; ── 进入分发逻辑 ── ; 落入 KiSystemServiceRepeat ``` --- ## 4. SSDT 与 KiServiceTable(服务分发) ### 4.1 数据结构 ```c // SSDT = System Service Descriptor Table // 实际结构:KeServiceDescriptorTable typedef struct _KSERVICE_TABLE_DESCRIPTOR { PLONG Base; // KiServiceTable — 函数偏移数组 PULONG Count; // 调用计数(调试用,可能为 NULL) ULONG Limit; // 表中最大服务号 PUCHAR Number; // 参数字节数表(KiArgumentTable) } KSERVICE_TABLE_DESCRIPTOR; // 系统中有两张表: // [0] KeServiceDescriptorTable → nt 系统调用 (KiServiceTable) // [1] KeServiceDescriptorTableShadow → 包含 win32k 的扩展表 (W32pServiceTable) ``` ### 4.2 KiServiceTable 的编码方式(x64 特有) 在 x64 Windows 中,`KiServiceTable` **不是**直接存储函数指针,而是存储 **相对偏移(编码后的 4 字节值)**: ```c // KiServiceTable[i] 的编码: // 高28位 = 函数相对于 KiServiceTable 基址的字节偏移(带符号右移4位) // 低 4位 = 该系统调用在栈上的额外参数个数 offset = (INT32)KiServiceTable[syscall_number] >> 4; target_function = (ULONG_PTR)KiServiceTable + offset; stack_params = KiServiceTable[syscall_number] & 0xF; ``` 这种编码节省空间(4字节 vs 8字节指针),并且可在单次查表中同时获得目标地址和参数信息。 ### 4.3 分发逻辑(KiSystemServiceRepeat) ```asm KiSystemServiceRepeat: ; EAX = 系统调用号 ; 位[12] 区分是 nt 表(0) 还是 win32k 表(1) mov edi, eax shr edi, 7 ; 取出表索引位 and edi, 0x20 ; 0 或 0x20(选 nt 表或 shadow 表) and eax, 0xFFF ; 低12位 = 表内索引 ; 边界检查 lea r10, [KeServiceDescriptorTable + rdi] cmp eax, [r10+LIMIT_OFFSET] jae invalid_syscall ; 查 KiServiceTable lea r11, [r10+BASE_OFFSET] ; r11 = KiServiceTable 基址 movsxd r11, dword ptr [r11 + rax*4] ; 取编码后的偏移 mov ecx, r11 shr ecx, (not implemented) ; 取参数数信息用于栈复制 sar r11, 4 ; 算术右移,得到真实偏移 add r11, [r10+BASE_OFFSET] ; 加基址 = 目标函数地址 ; 复制用户态栈参数到内核栈(如果有超过4个参数) ; ... call r11 ; 调用 nt!NtCreateFile ``` --- ## 5. nt!NtCreateFile 执行 ```c NTSTATUS NtCreateFile( PHANDLE FileHandle, // rcx (实际已在r10) ACCESS_MASK DesiredAccess, // rdx POBJECT_ATTRIBUTES ObjectAttributes, // r8 PIO_STATUS_BLOCK IoStatusBlock, // r9 PLARGE_INTEGER AllocationSize, // 栈参数[0] ULONG FileAttributes, // 栈参数[1] ULONG ShareAccess, // 栈参数[2] ULONG CreateDisposition, // 栈参数[3] ULONG CreateOptions, // 栈参数[4] PVOID EaBuffer, // 栈参数[5] ULONG EaLength // 栈参数[6] ); // → 调用 IoCreateFile → IopCreateFile → 对象管理器 → 文件系统驱动 ``` --- ## 6. 返回路径 ```asm ; NtCreateFile 返回值在 RAX(NTSTATUS) ; 恢复寄存器,准备返回 mov rcx, [TrapFrame.Rip] ; 用户态返回地址 → RCX mov r11, [TrapFrame.EFlags] ; 用户态 RFLAGS → R11 mov rsp, [TrapFrame.Rsp] ; 恢复用户态 RSP swapgs ; GS 切回用户态 TEB sysretq ; 返回 Ring3 ; CPU: RIP←RCX, RFLAGS←R11, CS←STAR[63:48]+16, SS←STAR[63:48]+8 ``` --- ## 总结图 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ User Mode │ │ │ │ CreateFileW (kernel32/kernelbase) │ │ ↓ │ │ NtCreateFile (ntdll.dll) │ │ │ mov eax, 0x55 ← syscall number │ │ │ syscall ← CPU reads MSR_LSTAR │ │ ↓ │ ├═══════════════════════ RING 3 → RING 0 ════════════════════════════╡ │ Kernel Mode │ │ │ │ MSR_LSTAR (0xC0000082) → KiSystemCall64 地址 │ │ ↓ │ │ KiSystemCall64: │ │ • swapgs, 切换内核栈, 构建 TRAP_FRAME │ │ ↓ │ │ KiSystemServiceRepeat: │ │ • EAX[12] 选表 → SSDT (KeServiceDescriptorTable) │ │ • EAX[11:0] 作为索引 → KiServiceTable[index] │ │ • 解码偏移 → 得到 nt!NtCreateFile 地址 │ │ ↓ │ │ nt!NtCreateFile │ │ → IoCreateFile → 文件系统驱动 │ │ ↓ │ │ 返回 NTSTATUS → sysretq → 回到用户态 │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 各组件核心职责 | 组件 | 职责 | |------|------| | **MSR_LSTAR** | 告诉 CPU "`SYSCALL` 应该跳到哪" — 硬件级别的入口地址寄存器 | | **KiSystemCall64** | 系统调用的软件入口:切栈、保存上下文、分发、返回 | | **SSDT** | 服务描述符表,描述每张服务表的基址、上限、参数表 | | **KiServiceTable** | SSDT 中"Base"指向的实际函数偏移数组,通过 syscall number 索引得到目标函数 |
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
2
点赞
・
2
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
感谢你的贡献,论坛因你而更加精彩!
2026-7-16 10:33
木志本柯
+1
为你点赞!
2026-6-17 13:32
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
1
)
mb_gmajzygm
雪 币:
20
能力值:
( LV1,RANK:0 )
在线值:
发帖
4
回帖
37
粉丝
1
关注
私信
mb_gmajzygm
2
楼
还是请求ssdt啊
2026-6-25 16:41
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
4seaynl
7
发帖
6
回帖
20
RANK
关注
私信
他的文章
[原创]CVE-2022-0847 Dirty Pipe 漏洞原理深度分析 近年来最"干净"的内核提权漏洞之一
10940
[原创]Windows x64 系统调用链:从用户态到 NtCreateFile
1826
[继续开源一套] 一件设置静态IP PS1脚本
2436
[开源一套]VMWARE DETECT PS1脚本
9318
[原创] VMX CPUID 一键生成源
3848
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部