这里我以windows系统为例子,在其他系统实现方式是一样的.
我们都知道xp系统是通过int 2E中断从用户态进入内核态的.,但xp系统之后windows都是通过系统快速调用从用户态进入内核态的.
系统快速调用有两种:
MSR(Model-Specific Register) 是一类寄存器,这类寄存器数量庞大,并且和处理器的model相关.提供对硬件和软件相关功能的一些控制.能够对一些硬件和软件的运行环境进行设置.
每个MSR是64位宽的,每个MSR都有它的的地址值(编号).对MSR操作使用两个指令进行读写,由ecx寄存器提供需要访问的MSR地址值,EDX:EAX提供64位值(EAX表示低32位,EDX表示高32位)
提示:如果MSR地址是保留未实现的,则执行rdmsr和wrmsr指令会产生#GP异常
示例:读取IA32_SYSENTER_EIP寄存器
demo:ShowMSR
试验系统Win7 32位
在32位的windows系统中,是通过sysenter指令从用户态进入内核态的,从内核态返回用户态通过sysexit指令.
IA32_SYSENTER_CS
IA32_SYSENTER_ESP
IA32_SYSENTER_EIP
对应的地址:
我们再做一个小例子:
demo:ShowMSR1
运行后(Win7 32):
可以看到:CS_Selector=8
返回时:CS=CS_Selector+16=24(18H) SS=CS_Selector+24=32(20h)
我们用x64Dbg随便查看一个程序看是否是这样的:
CS=1BH SS=23H 并不是18H和20H,知道有特权级的同学可能已经知道在用户模式下特权级是3,内核态是0,选择子的最后2位表示特权级,所以回到用户态特权级变为3,所以还要加上3.
正好符合我们所描述的.
继续我们的主题
在32位模式下IA32_SYSENTER_EIP和IA32_SYSENTER_ESP的低32位存放进入(sysenter)内核态时的目标代码入口点和栈指针.当返回(sysexit)时需要EDX和ECX分别放入返回点和栈指针.
这里以Windows为例不介绍Long Mode模式,因为在该模式下Windows使用的是syscall和sysret
我们看一下CreateFile是怎么进入内核的:
demo:CreateFile(虚拟机没有按照VS的库,所以使用汇编来编写)
本来想用Windbg在系统快速调用的地址下断点,可是那里会一直断下来,也就放弃了
我们用x64Dbg调试:
syscall通过从IA32_LSTAR MSR加载RIP(syscall的下一条指令地址会保存到RCX).RFLAGS保存到R11寄存器,然后用IA32_FMASK MSR(MSR 地址:C0000084H)屏蔽RFLAGS的值,更具体的说是清除在IA32_FMASK MSR中设置的每一位.
syscall会从IA32_STAR[47:32]中加载CS和SS.
syscall不会保存堆栈指针(RSP).
官方描述(这里我隐藏了描述符检查和控制寄存器检查下同):
RIP=RCX
RFLAGS=R11
返回32位代码:CS=CS_Selector|3 SS=(CS_Selector+8)|3
返回64位代码:CS=(CS_Selector+16)|3 SS=(CS_Selector+8)|3
返回时不会修改(ESP or RSP)
我们看一个demo
driver.c
64.asm
由于在64位我的DbgView看不到信息,所以我在Windbg调试
可以知道:
SYSRET CS_Selector=0x23
读者可以推断在32位和64位时CS和SS的值分别是什么:
我们验证一下:
用x64dbg32位附加一个32位的程序:
用x64Dbg64位附加一个64位的程序
好了正好验证了我们的想法。
其实Windows要从32位进入内核时首先要把CS改为0X33,然后再进入64位,如果我们写了32位的代码,然后去指向64位的代码,其实也是把CS改为0x33.
后面的示例读者可以自己去验证,我已经说到很明白了。
示例程序是两个驱动:都是Win7的。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-4-28 15:42
被chpeagle编辑
,原因: