当系统函数进入NT后代码:
mov eax,BE
mov edx,0x7ffe0300
call dword ptr[edx]
retn 10
_KUSER_SHARED_DATA(用户层与内核层分别定义了该结构,用户用户层与内核层共享数据。大小为4KB)
布局
使用windbg查看该结构
dt _kuser_shared_data -v
结构体有75个元素,使用了0x5f0个字节,并没有把所有空间使用完全。
分析_KUSER_SHARED_DATA 用户层与内核层是否共享同一块数据
查看_KUSER_SHARED_DATA需要进入到程序进程。
进入test.exe进程
查看 _KUSER_SHARED_DATA用户层与内核层物理页是否相同
User层和Kernel层映射同一个物理页。虽然它们指向的是同一个物理页,但在User层是只读的,在Kernel层是可写的。
_KUSER_SHARED_DATA结构偏移0x300
这个地方是一个SystemCall,查看一下对应的反汇编代码,看看OpenProcess函数的call dword ptr [edx]具体是做了什么。
该函数KiFastSystemCall,实际上就只有三行代码,首先把esp保存到edx,目的是为了在零环能够方便的找到三环的堆栈。接着用sysenter指令进到零环,最后通过ret指令返回。
从三环进零环的方式有两种方式
当操作系统在启动的时候,需要初始化_KUSER_SHARED_DATA这个结构体,其中最重要的就是初始化0x300这个位置。操作系统要往这里面写一个函数,这个函数决定了所有的三环的API进入零环的方式。
操作系统在写入之前会通过cpuid这个指令来检查当前的CPU是否支持快速调用,如果支持的话,就往0x300这个位置写入KiFastSystemCall。如果不支持,则写入KiIntSystemCall。
KiIntSystemCall通过中断方式进入内核,不具体分析。
通过sysenter快速调用进入零环
想要从三环进入到零环首先必须要提权,提权需要切换CS SS EIP ESP。如果通过中断门进入零环,门描述符里保存有CS和EIP,而SS和ESP来自于TSS。
在了解sysenter指令之前,要先了解一个寄存器,叫MSR。操作系统并没有公开这个寄存器的内部细节。但是我们可以知道这个寄存器的部分含义:
0x174保存的是CS
0x175保存的是ESP
0x176保存的是EIP
如果想查看msr寄存器174就可以使用下面的指令:
kd> rdmsr 174
msr[174] = 00000000`00000008
sysenter快速调用指令完成的事情就是从msr寄存器里拿到174 175和176的值,覆盖原来寄存器的值。int 0x2E和sysenter两种进入零环的方式的本质都是切换寄存器。
通过msr寄存器只能拿到三个值,分别是CS ESP和EIP,那么SS来自于哪呢?这个SS的值实际上是写死的。