Windows系统调用学习笔记(二)—— 3环进0环
前言
一、学习自
滴水编程达人
中级班课程,官网:https://bcdaren.com
二、海东老师牛逼!
要点回顾
上一篇我们分析了ReadProcessMemory这个函数的3环部分
- ReadProcessMemory函数存在于kernel32.dll中
- 它并没有做什么,只是调用了另一个函数(NtReadVirtualMemory),然后设置了一些返回值
- NtReadVirtualMemory函数来自ntdll.dll
- NtReadVirtualMemory也没做什么,只是提供了一个编号(0BAh)和一个函数地址(7FFE0300h),然后进行了内核调用
本篇将弄清这个函数地址(7FFE0300h)是什么
基本概念
_KUSER_SHARED_DATA
- 在 User 层和 Kernel 层分别定义了一个 _KUSER_SHARED_DATA 结构区域,用于 User 层和 Kernel 层共享某些数据
- 它们使用固定的地址值映射,_KUSER_SHARED_DATA结构区域在User层和Kernel层地址分别为:
User
:0x7ffe0000
Kernnel
:0xffdf0000
注意:虽然指向的是同一个物理页,但在User层是只读的,在Kernnel层是可写的
0x7FFE0300
描述:
当通过eax=1来执行cpuid
指令时,处理器的特征信息被放在ecx和edx寄存器中,其中edx包含了一个SEP位(11位),该位指明了当前处理器知否支持sysenter
/sysexit
指令
- 支持:
ntdll.dll! KiFastSystemCall() - 不支持:
ntdll.dll! KiIntSystemCall()
实验:判断CPU是否支持快速调用
第一步:修改EAX=1
第二步:将当前汇编指令修改为cpuid
第三步:清空ECX与EDX
第四步:执行cpuid,观察结果
第五步:观察EDX的SEP位(第11位)
0xBFF = 二进制:1011 1111 1111
SEP=1,说明当前CPU支持 sysenter / sysexit 指令
3环进0环
基本步骤
- CS的权限由3变为0,意味着需要新的CS
- SS与CS的权限永远一致,需要新的SS
- 权限发生切换的时候,堆栈也一定会切换,需要新的ESP
- 进0环后会修改EIP
中断门进0环
分析 KiIntSystemCall
该函数函数只执行了两行代码
分析:
- 第一行将参数的地址放入EDX中
- 第二行调用了0x2e中断(所有的API进内核时,统一的中断号为0x2e)
注意:在执行KiIntSystemCall函数前,编号已被写入EAX
分析 INT 0x2E
第一步:在IDT表中找到0x2E号门描述符
门描述符:804d
ee00`0008e7d1
指向地址:804de7d1
第二步:分析CS/SS/ESP/EIP的来源
CS:门描述符的段选择子部分(0008)
SS:从段选择子指向的TSS段描述符指向的TSS表中取出
ESP:从段选择子指向的TSS段描述符指向的TSS表中取出
EIP:804de7d1
第三步:查看门描述符指向的EIP
nt
表示当前函数为内核函数
快速调用进0环
快速调用:
- 中断门进0环,需要的CS、EIP在IDT表中,需要查内存(SS与ESP由TSS提供)
- CPU如果支持sysenter指令,操作系统会提前将CS/SS/ESP/EIP的值存储在MSR寄存器中,sysenter指令执行时,CPU会将MSR寄存器中的值直接写入相关寄存器,没有读内存的过程,所以叫快速调用,它们的本质是一样的
分析 KiFastSystemCall
该函数函数只执行了两行代码
分析:
- 第一行将当前栈顶(esp)的值放入edx中
- 第二行执行了sysenter指令
注意:在执行KiIntSystemCall函数前,编号已被写入EAX
分析 sysenter指令
注意:
- 在执行sysenter指令之前,操作系统必须指定0环的CS段、SS段、EIP以及ESP
- 其中,CS段、EIP以及ESP来自MSR寄存器
MSR寄存器
描述:MSR寄存器非常庞大,这里只列出三个值,详细信息参照Intel白皮书
可以通过RDMSR/WRMST来进行读写(操作系统使用WRMST写该寄存器):
- kd> rdmsr 174 //查看CS
- kd> rdmsr 175 //查看ESP
- kd> rdmsr 176 //查看EIP
查看EIP所在地址的反汇编
nt
表示当前函数为内核函数
注意:
4. 在执行sysenter指令时,只有CS、ESP、EIP三个寄存器的值可从MSR寄存器中获得,其中并不包括SS!
5. SS
= IA32_SYSENTER_CS + 8
6. 这些操作与操作系统无关,而是硬件(CPU)做的(详情参考Intel白皮书第二卷)
总结
API通过中断门进0环
- 固定中断号为0x2E
- CS/EIP由门描述符提供,ESP/SS由TSS提供
- 进入0环后执行的内核函数:NT!KiSystemService
API通过sysenter指令进0环
- CS/ESP/EIP由MSR寄存器提供(SS是算出来的)
- 进入0环后执行的内核函数:NT!KiFastCallEntry
内核模块
10-10-12分页:ntoskrnl.exe
2-9-9-12分页:ntkrnlpa.exe
练习
要求:通过IDA找到KiSystemService和KiFastCallEntry函数并分析
问题:
- 进0环后,原来的寄存器存在哪里?
- 如何根据系统调用号(eax中存储)找到要执行的内核函数?
- 调用时参数是存储到3环的堆栈,如何传递给内核函数?
- 2种调用方式是如何返回到3环的?
答案:见下篇