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直接来进行压入的,如下图所示

posted @   zpchcbd  阅读(548)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2020-03-04 MemoryModule(没写)
点击右上角即可分享
微信分享提示