API函数的调用过程(保存现场)
前言:作为API函数的调用过程(保存现场)的学习笔记
前面一篇的总结:
1、如果CPU支持sysenter指令,那么API调用时会通过sysenter指令进入0环,如果不支持sysenter指令,通过中断门进0环,默认的中断号:0x2E(IDT表)
这边笔记把前面的两种方法,分别是中断门进0环和sysenter进0环调用内核函数KiSystemService和KiFastCallEntry,这篇笔记主要分析这两个函数的参数的传递
关于KCPR/ETHREAD/KTHREAD的知识点
因为下面分析要用到,所以这里先来大概了解下
前置知识点
先提出一个小问题,为什么在做中断门实验的时候在int xx
进入0环的时候,事先需要进行mov fs, 0x30
然后再pop fs
呢?就比如在int 2E
进行0环的时候
我具体也没多去了解其他的中断门描述符,不过我感觉可能是这样子的,首先需要知道的一个知识点:
在三环fs:[0] -> TEB
在零环fs:[0] -> KPCR
而通过int 2e
中断门进入0环的时候,如下图所示,他就会对0环的fs进行改变为0x30,让其0环的base指向的地址为KPCR的地址
这也就说明了如果我们不事先在通过中断门进入零环的时候,不提前进行三环的fs,那么中断门调用完之后就会找不到三环的fs:[0] -> TEB,就会产生错误
什么是KPCR
KPCR又被称作为CPU控制块,通常零环的fs:[0]都指向这个结构体
dt _KPCR
,KPCR是一个结构体,每个核都有一个这样的结构体
通过dd KeNumberProcessors
可以查看核数量
_NT_TIB
KPCR结构体中第一个成员是_NT_TIB结构体
_KPRCB
KPCR结构体中还有一个成员,这个成员的结构体为_KPRCB,这个结构体是作为KPCR的扩展,其中同样也保存了当前线程相关的信息
dt _KPRCB
通过这种方式也可以查看当前核的_KPRCB
dd KiProcessorBlock
可以看到地址是0xffdff120,而这个值正好就是当前核的KPCR结构体的+0x120的偏移
dd KiProcessorBlock-0x120
KiSystemService的过程
进0环后,原来的寄存器存在哪里?
答案:Trap_Frame结构体
KiSystemService是通过中断门int 2e
来进行调用的,然后这里接着看IDT中位置为0x2e的段描述,如下图所示,指向的地址为0x804de7d1的位置
跟到0x804de7d1的位置,如下图所示,就来到了KiSystemService的函数调用
接着这里就需要引出Trap_Frame结构体了,它的结构体定义如下图所示
_Trap_Frame结构体中可以看到,先0x68-0x78偏移地址中保存的分别就是三环的ss esp eflags cs eip
这五个寄存器也就是我们每次通过中断门进入内核之后看到的五个寄存器,如下图所示,正常中断门提权的堆栈图
这里还可以在内核函数中看到,还会压入相关的寄存器,如下图所示
所以说三环压入的ss esp eflags cs eip之后,内核中还会保存相关三环的其他寄存器的信息,那么对应到_Trap_Frame的结构体也就是如下,0x54-0x64的位置
知识点:
1、每个线程都有一个这样的_Trap_Frame结构体,后面在学习_ETHREAD结构体的时候会讲到,因为每个_ETHREAD结构体就代表一个线程,而每个_ETHREAD结构体中的_KTHREAD结构体中都会保存一个单独_KTRAP_FRAME(_Trap_Frame)这样的结构体,这个后面会再次提及
2、_Trap_Frame就是调用门进入0环后使用的堆栈
思考:
如果每个线程都有一个_Trap_Frame结构体,而在单核的情况下,一个核只有一个TSS任务段,而调用门进入零环的时候,其中ESP0和SS都是TSS任务段来进行提供的,那么问题来了,操作系统在处理这么多个线程的时候,是怎么保证每个thread都能拿到单独的一个_Trap_Frame结构体呢?
其实操作系统在进行线程切换的时候都会在TSS任务段中刷新把ESP0的地址更改,指向一个新的TRAP_FRAME结构体的地址
KiSystemService如何根据系统调用号(eax中存储)找到要执行的内核函数
https://www.cnblogs.com/zpchcbd/p/15962710.html
KiSystemService调用时参数是存储到3环的堆栈,如何传递给内核函数?
https://www.cnblogs.com/zpchcbd/p/15962710.html
KiSystemService如何返回到3环的?
相关APC的知识点后面学习到了再来补上
KiFastCallEntry的过程
KiFastCallEntry进0环后,原来的寄存器存在哪里?
也是存储到TRAP_FRAME结构体中,如下图所示
KiFastCallEntry如何根据系统调用号(eax中存储)找到要执行的内核函数?
https://www.cnblogs.com/zpchcbd/p/15962710.html
KiFastCallEntry调用时参数是存储到3环的堆栈,如何传递给内核函数?
https://www.cnblogs.com/zpchcbd/p/15962710.html
KiFastCallEntry如何返回到3环的?
相关APC的知识点后面学习到了再来补上
KiFastCallEntry和KiSystemService共同点和不同点
共同点
1、除了一开始的TRAP_FRAME初始化有些不同,其他的流程都是一样的
2、最后的处理都会走到处理找到系统服务表
不同点
TRAP_FRAME初始化有些不同,对于KiFastCallEntry是操作系统手动压入如下五个参数,而对于KiSystemService的话,这五个参数是CPU直接来进行压入的,如下图所示
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2020-03-04 MemoryModule(没写)