windows的系统调用
windows系统调用的具体流程在潘爱民老师的《WINDOWS内核原理与实现》中的第8章已经写得很清楚了,先看书中给出的这幅图。
以CreateFile为例,在ring3的CreateFile进行了一些参数检查后最终调用的是Ntdll中的NtCreateFile。同时也有ZwCreateFile,不过它们的地址指向同一区域,所以本质上来说是同一个函数。
可以再ntdll的导出表中看到:
之后通过sysenter或者0x2e中断进入ring0层,并将服务号放入eax中。
ntoskrnl.exe 中的 zwcreatefile:
kd> u nt!zwcreatefile
nt!ZwCreateFile:
80501010 b825000000 mov
eax,25h ;服务号
80501015 8d542404 lea
edx,[esp+4]
80501019 9c pushfd
8050101a 6a08 push 8
8050101c e830140400 call nt!KiSystemService (80542451)
80501021 c22c00 ret
2Ch
使用int 0x2e进入ring0
使用windbg可以直接查看idt的0x2e号中断:
kd>!idt 2e
Dumping IDT:
2e: 80542451 nt!KiSystemService ;可以看到指向的是KiSystemService这个例程
当然,也可以通过查看idt表计算出0x2e中断所指向的地址,首先找到idt表中0x2e项的内容:
kd> !pcr
KPCR for Processor 0 at ffdff000:
Major 1 Minor 1
NtTib.ExceptionList: 80551cb0
NtTib.StackBase: 805524f0
NtTib.StackLimit: 8054f700
NtTib.SubSystemTib: 00000000
NtTib.Version: 00000000
NtTib.UserPointer: 00000000
NtTib.SelfTib: 00000000
SelfPcr: ffdff000
Prcb: ffdff120
Irql: 00000000
IRR: 00000000
IDR: ffffffff
InterruptMode: 00000000
IDT: 8003f400 ;IDT表的地址
GDT: 8003f000
TSS: 80042000
CurrentThread: 8055ce60
NextThread: 00000000
IdleThread: 8055ce60
计算一下 8003f400 + 8*0x2e = 8003F570
查看:
kd> db 8003F570
8003f570 51 24 08 00 00 ee 54 80-e0 57 08 00 00 8e 54 80 Q$....T..W....T.
8003f580 10 1b 08 00 00 8e 54 80-1a 1b 08 00 00 8e 54 80 ......T.......T.
8003f590 24 1b 08 00 00 8e 54 80-2e 1b 08 00 00 8e 54 80 $.....T.......T.
8003f5a0 38 1b 08 00 00 8e 54 80-42 1b 08 00 00 8e 54 80 8.....T.B.....T.
根据IDT中断描述符的格式,可以知道该例程偏移为 80542451 ,段选择符为0x8 (IDT结构的内容在《WINDOWS内核原理与实现》中的第5章有讲解)
知道了偏移地址,还需要知道段地址才可以计算出实际的地址。
已经知道了段选择符为0x8,可以查看相应的段描述符:
其中,TI为0表示改索引指向GDT,RPL为0表示当前特权级是0,索引代表它在GDT中的位置是第一项。
(这一部分的知识在书中第4章有介绍,但不是十分详细,具体内容可以查阅一些保护模式的资料)
查看GDT:
kd> r gdtr
gdtr=8003f000 ;也可以使用!pcr指令找到GDT地址
kd> db 8003f000
8003f000 00 00 00 00 00 00 00 00-ff ff 00 00 00 9b cf 00 ................
8003f010 ff ff 00 00 00 93 cf 00-ff ff 00 00 00 fb cf 00 ................
由段描述格式获得基地址为 0x0000
计算出中断例程的地址为 0000 : 80542451 与windbg直接获得的地址一样。
通过sysenter进入ring0
先看sysenter指令的调用位置:
kd> u ntdll!KiFastSystemCall
ntdll!KiFastSystemCall:
770801d0 8bd4
mov
edx,esp
770801d2 0f34
sysenter
ntdll!KiFastSystemCallRet:
770801d4 c3
ret
770801d5 8da42400000000 lea
esp,[esp]
770801dc 8d642400
lea
esp,[esp]
sysenter指令的工作原理是读取MSR寄存器,加载RING0层的CS,EIP,ESP,清楚Eflags中的VM标示.
IA32_SYSENTER_CS 0x174
IA32_SYSENTER_ESP 0x175
IA32_SYSENTER_EIP 0x176
使用windbg查看:
kd> rdmsr 174
msr[174] = 00000000`00000008
kd> rdmsr 175
msr[175] = 00000000`f8ac2000
kd> rdmsr 176
msr[176] = 00000000`80542520
CS段选择符为0x00000008与之前的一样,所以目标地址为 0000:80542520
反汇编此地址:
kd> u 80542520
nt!KiFastCallEntry:
80542520 b923000000
mov
ecx,23h
80542525 6a30
push 30h
80542527 0fa1
pop
fs
80542529 8ed9
mov
ds,cx
8054252b 8ec1 mov
es,cx
8054252d 648b0d40000000 mov
ecx,dword ptr fs:[40h]
80542534 8b6104 mov
esp,dword ptr [ecx+4]
KiFastCallEntry就是进入RING0的调用例程。
其实对KiSystemService的反汇编进行查看会发现,KiSystemService最终还是调用了KiFastCallEntry的例程:
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/69893.html