sufeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-27
  • 最后登录2004-08-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1490回复:9

很糊涂的问题,大家多指点。

楼主#
更多 发布于:2002-11-27 19:50
几个问题:
1.系统启动进入内核之后ring0,最后必然要回到用户态,这其中的切换需要什么代价?
是如何切换的?比如设置哪些状态,保护什么东东标志?
比如ring3可以通过 int 2e进入ring0,那么ring0怎么回到ring3.

2.关于system service.
我想win 32 api最终会调用native api。但是ntdll.dll和ntoskrnl.exe都会导出Ntxxxx,那么这个native api到底是哪个导出的?
ntdll.dll中的Ntxx通过int 2e进入内核, ntoskrnl.exe的Zwx也通过int 2e进入内核,为什么还要设计两个东东都通过int 2e进入,一个不就完了吗?
ntdll.dll运行ring3态,可以被用户程序调用,ntoskrnl.exe运行ring0态,是否只能被kernel mode程序调用? Zwxx通过int 2e重入ring0时,由于pre mode=ring0,所以没有安全检查??

---------------
后两个问题我同学问:
3.windows 2000为何要把gui,user也搞进kernel,有何大用?

4.为何system service用int 2e进入,而不用callgate??

-------------------
有点罗嗦,但是确实很糊涂,希望得到大家的指点。
ysy
ysy
驱动中牛
驱动中牛
  • 注册日期2002-02-18
  • 最后登录2008-08-25
  • 粉丝0
  • 关注0
  • 积分201分
  • 威望29点
  • 贡献值0点
  • 好评度19点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-11-28 11:35
几个问题:
1.系统启动进入内核之后ring0,最后必然要回到用户态,这其中的切换需要什么代价?
至少保护所有的寄存器.

是如何切换的?比如设置哪些状态,保护什么东东标志?
比如ring3可以通过 int 2e进入ring0,那么ring0怎么回到ring3.
基本就是保存寄存器,切换选择子,返回就是做相反的动作调用iret返回。

2.关于system service.
我想win 32 api最终会调用native api。但是ntdll.dll和ntoskrnl.exe都会导出Ntxxxx,那么这个native api到底是哪个导出的?
好像是ntdll.dll里要调用int2e,而ntoskrnl.exe里的是具体的服务例程。native api是从ntoskrnl.exe里导出。

ntdll.dll中的Ntxx通过int 2e进入内核, ntoskrnl.exe的Zwx也通过int 2e进入内核,为什么还要设计两个东东都通过int 2e进入,一个不就完了吗?
对ZwXXX的调用都是在kernel,也就是ring0.Ntxxx在ring3。

ntdll.dll运行ring3态,可以被用户程序调用,ntoskrnl.exe运行ring0态,是否只能被kernel mode程序调用?

Zwxx通过int 2e重入ring0时,由于pre mode=ring0,所以没有安全检查??


---------------
后两个问题我同学问:
3.windows 2000为何要把gui,user也搞进kernel,有何大用?
减少从ring3到ring0的开销,提高效率。

4.为何system service用int 2e进入,而不用callgate??
也可以用callgate,但是好像使用中断们更舒服些,习惯都这么用。linux也是。呵呵。。。
-------------------
有点罗嗦,但是确实很糊涂,希望得到大家的指点。  
ysy
ysy
驱动中牛
驱动中牛
  • 注册日期2002-02-18
  • 最后登录2008-08-25
  • 粉丝0
  • 关注0
  • 积分201分
  • 威望29点
  • 贡献值0点
  • 好评度19点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-11-28 11:37
补充一下,从ring0返回ring3的时候还要检查是否需要进程切换,有没有apc在排队。。。。
sufeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-27
  • 最后登录2004-08-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-11-28 12:33
多谢ysy
呵呵,大家继续讨论。
sufeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-27
  • 最后登录2004-08-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-11-28 12:36
下面是pjf的解释。
------------------------------
1.系统启动进入内核之后ring0,最后必然要回到用户态,这其中的切换需要什么代价?
是如何切换的?比如设置哪些状态,保护什么东东标志?
//范围so大,岂是几句能说清楚的
比如ring3可以通过 int 2e进入ring0,那么ring0怎么回到ring3.
//ft iretd ,sysexit,......

2.关于system service.
我想win 32 api最终会调用native api。但是ntdll.dll和ntoskrnl.exe都会导出Ntxxxx,那么这个native api到底是哪个导出的?
//最后进入的是同一个由SSDT纪录的函数里,前者所做的预处理多一
//点而已。另外ntoskrnl导出的NT***与ntdll的不同,ntoskrnl的
//Zw***才用了int2e等。

ntdll.dll中的Ntxx通过int 2e进入内核, ntoskrnl.exe的Zwx也通过int 2e进入内核,为什么还要设计两个东东都通过int 2e进入,一个不就完了吗?
//显然,自己想想看

ntdll.dll运行ring3态,可以被用户程序调用,ntoskrnl.exe运行ring0态,是否只能被kernel mode程序调用?
//of course

Zwxx通过int 2e重入ring0时,由于pre mode=ring0,所以没有安全检查??
//right

---------------
后两个问题我同学问:
3.windows 2000为何要把gui,user也搞进kernel,有何大用?
//说法不准确,效率

4.为何system service用int 2e进入,而不用callgate??
//1、看看unix的核,想想它们的关系;2、看看由那些机器有callgate;3、XP在大多数机器上都不用int2e。

ysy
ysy
驱动中牛
驱动中牛
  • 注册日期2002-02-18
  • 最后登录2008-08-25
  • 粉丝0
  • 关注0
  • 积分201分
  • 威望29点
  • 贡献值0点
  • 好评度19点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-11-28 16:56
pjf说的比较粗,但是我还是支持他的,的确不是几句话就能说明白的。你问的这些问题看似很简单但是需要对cpu的结构有个很清楚的了解,我也觉得真正弄明白的话需要看很多书,还需要时间,除非你是天才。
sufeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-27
  • 最后登录2004-08-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-11-28 18:38
呵呵,真正弄清楚决非一件容易的事情。
也许很多人知道结论,但是不一定就清楚他真正的内部实现机制,也是个似懂非懂。

要想搞定,要自己专心研究,看书,查资料,讨论也是必不可少,也许一个提示就茅塞顿开。

continue.

pjf
pjf
驱动中牛
驱动中牛
  • 注册日期2001-07-08
  • 最后登录2006-10-23
  • 粉丝0
  • 关注0
  • 积分42分
  • 威望4点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-11-28 20:12
其它诸点都不怎么成问题,稍微看一下NT代码即可窥出大概;至于第一点本身描述不甚清楚,“系统启动进入内核之后ring0,最后必然要回到用户态,这其中的切换需要什么代价?”似乎想让人从启动后如何创建system进程说起、直至控制交付某个应用的ring3部分呢,够写半本书。如果很想了解,又不想读NT的汇编码的话,建议去仔细读linux中断与系统调用、进程控制、内存管理(多可略,不过进程空间的一点东西在switch_mm中涉及)部分代码(实在想缩小范围,但实在相关),反过来读NT,你会发现大量相似之处,很容易理解。假若你仅仅是指从ring0退回到ring3那一点点过程的话,那跟其它问题也没什么区别。退回的过程有几种情形,系统调用返回是一种,自己看看很少几行的代码吧,下面是贴过的系统服务处理返回代码,很少的代码只配了简单注释(来自XP):
0008:804D4DCD PUSH 00
0008:804D4DCF PUSH EBP
0008:804D4DD0 PUSH EBX
0008:804D4DD1 PUSH ESI
0008:804D4DD2 PUSH EDI
0008:804D4DD3 PUSH FS
0008:804D4DD5 MOV EBX,00000030
0008:804D4DDA MOV FS,BX
0008:804D4DDD PUSH DWORD PTR [FFDFF000]
0008:804D4DE3 MOV DWORD PTR [FFDFF000],FFFFFFFF
0008:804D4DED MOV ESI,[FFDFF124]
//ETHREAD=>ESI

0008:804D4DF3 PUSH DWORD PTR [ESI+00000140]
0008:804D4DF9 SUB ESP,48
0008:804D4DFC MOV EBX,[ESP+6C]
//byte ptr[ESP+6C]=08

0008:804D4E00 AND EBX,01
0008:804D4E03 MOV [ESI+00000140],BL
//BL(0)=>ETHREAD.PreviousMode

0008:804D4E09 MOV EBP,ESP
0008:804D4E0B MOV EBX,[ESI+00000134]
//old ETHREAD.TrapFrame=>EBX

0008:804D4E11 MOV [EBP+3C],EBX
0008:804D4E14 MOV [ESI+00000134],EBP
0008:804D4E1A CLD
0008:804D4E1B TEST BYTE PTR [ESI+2C],FF
//debug flag is active?

0008:804D4E1F JNZ 804D4CEC
0008:804D4E25 STI
0008:804D4E26 MOV EDI,EAX
0008:804D4E28 SHR EDI,08
0008:804D4E2B AND EDI,30
0008:804D4E2E MOV ECX,EDI
0008:804D4E30 ADD EDI,[ESI+000000E0]
//get ServiceTable

0008:804D4E36 MOV EBX,EAX
0008:804D4E38 AND EAX,00000FFF
0008:804D4E3D CMP EAX,[EDI+08]
//correct ServiceId?
 
0008:804D4E40 JAE 804D4CA2
0008:804D4E46 CMP ECX,10
//extended Service?

0008:804D4E49 JNZ 804D4E65
0008:804D4E4B MOV ECX,[FFDFF018]
0008:804D4E51 XOR EBX,EBX
0008:804D4E53 OR EBX,[ECX+00000F70]
0008:804D4E59 JZ 804D4E65
0008:804D4E5B PUSH EDX
0008:804D4E5C PUSH EAX
0008:804D4E5D CALL [80544C44]
0008:804D4E63 POP EAX
0008:804D4E64 POP EDX
0008:804D4E65 INC DWORD PTR [FFDFF638]
0008:804D4E6B MOV ESI,EDX
0008:804D4E6D MOV EBX,[EDI+0C]
0008:804D4E70 XOR ECX,ECX
0008:804D4E72 MOV CL,[EBX+EAX]
//get bytes of parameters

0008:804D4E75 MOV EDI,[EDI]
0008:804D4E77 MOV EBX,[EAX*4+EDI]
//get the service function address
 
0008:804D4E7A SUB ESP,ECX
0008:804D4E7C SHR ECX,02
0008:804D4E7F MOV EDI,ESP
0008:804D4E81 CMP ESI,[ntoskrnl!MmUserProbeAddress]
0008:804D4E87 JAE 804D5033
//do something if ... from ring0

0008:804D4E8D REPZ MOVSD
//copy parameters

0008:804D4E8F CALL EBX
//call service function
 
0008:804D4E91 MOV ESP,EBP
0008:804D4E93 MOV ECX,[FFDFF124]
0008:804D4E99 MOV EDX,[EBP+3C]
0008:804D4E9C MOV [ECX+00000134],EDX
0008:804D4EA2 CLI
0008:804D4EA3 TEST DWORD PTR [EBP+70],00020000
//v86 mode?

0008:804D4EAA JNZ 804D4EB2
0008:804D4EAC TEST BYTE PTR [EBP+6C],01
//ring0 or ring3?

0008:804D4EB0 JZ 804D4F08
0008:804D4EB2 MOV EBX,[FFDFF124]
0008:804D4EB8 MOV BYTE PTR [EBX+2E],00
0008:804D4EBC CMP BYTE PTR [EBX+4A],00
//for APC

0008:804D4EC0 JZ 804D4F08
0008:804D4EC2 MOV EBX,EBP
0008:804D4EC4 MOV [EBX+44],EAX
0008:804D4EC7 MOV DWORD PTR [EBX+50],0000003B
0008:804D4ECE MOV DWORD PTR [EBX+38],00000023
0008:804D4ED5 MOV DWORD PTR [EBX+34],00000023
0008:804D4EDC MOV DWORD PTR [EBX+30],00000000
0008:804D4EE3 MOV ECX,00000001
0008:804D4EE8 CALL [HAL!KfRaiseIrql]
0008:804D4EEE PUSH EAX
0008:804D4EEF STI
0008:804D4EF0 PUSH EBX
0008:804D4EF1 PUSH 00
0008:804D4EF3 PUSH 01
0008:804D4EF5 CALL ntoskrnl!KiDeliverApc
0008:804D4EFA POP ECX
0008:804D4EFB CALL [HAL!KfLowerIrql]
0008:804D4F01 MOV EAX,[EBX+44]
0008:804D4F04 CLI
0008:804D4F05 JMP 804D4EB2
0008:804D4F07 NOP

//go on
0008:804D4F08 MOV EDX,[ESP+4C]
0008:804D4F0C MOV EBX,FS:[00000050]
0008:804D4F13 MOV FS:[00000000],EDX
0008:804D4F1A MOV ECX,[ESP+48]
0008:804D4F1E MOV ESI,FS:[00000124]
0008:804D4F25 MOV [ESI+00000140],CL
0008:804D4F2B TEST EBX,0000000F
0008:804D4F31 JNZ 804D4FA8
0008:804D4F33 TEST DWORD PTR [ESP+70],00020000
0008:804D4F3B JNZ 804D57EA
0008:804D4F41 TEST WORD PTR [ESP+6C],FFF8
0008:804D4F48 JZ 804D5001
0008:804D4F4E CMP WORD PTR [ESP+6C],1B
0008:804D4F54 BT DWORD PTR [ESP+6C],00
0008:804D4F5B CMC
0008:804D4F5C JA 804D4FEF  ;if(DT!=1B&&ETHREAD.PreviousMode==UserMode) error;
0008:804D4F62 CMP WORD PTR [EBP+6C],08
0008:804D4F67 JZ 804D4F6E
0008:804D4F69 LEA ESP,[EBP+50]
0008:804D4F6C POP FS
0008:804D4F6E LEA ESP,[EBP+54]
0008:804D4F71 POP EDI
0008:804D4F72 POP ESI
0008:804D4F73 POP EBX
0008:804D4F74 POP EBP
0008:804D4F75 CMP WORD PTR [ESP+08],0080
0008:804D4F7C JA 804D5806
0008:804D4F82 ADD ESP,04
0008:804D4F85 TEST DWORD PTR [ESP+04],00000001
0008:804D4F8D JNZ 804D4F95
0008:804D4F8F POP EDX
0008:804D4F90 POP ECX
0008:804D4F91 POPFD
0008:804D4F92 JMP EDX
//return to ring0 (edx=>eip)
0008:804D4F94 IRETD

0008:804D4F95 POP EDX
0008:804D4F96 ADD ESP,08
0008:804D4F99 POP ECX
0008:804D4F9A STI
0008:804D4F9B SYSEXIT
//return to ring3 (edx=>eip,ecx=>esp)

0008:804D4F9D POP ECX
0008:804D4F9E ADD ESP,08
0008:804D4FA1 POP ESP
0008:804D4FA2 SYSRET
//for AMD cpu

0008:804D4FA4 IRETD
0008:804D4FA5 LEA ECX,[ECX+00]
0008:804D4FA8 TEST DWORD PTR [EBP+70],00020000
0008:804D4FAF JNZ 804D4FBE
0008:804D4FB1 TEST DWORD PTR [EBP+6C],00000001
0008:804D4FB8 JZ 804D4F33
0008:804D4FBE MOV EBX,00000000
0008:804D4FC3 MOV ESI,[EBP+18]
0008:804D4FC6 MOV EDI,[EBP+1C]
0008:804D4FC9 MOV DR7,EBX
0008:804D4FCC MOV DR0,ESI
sufeng
驱动牛犊
驱动牛犊
  • 注册日期2002-04-27
  • 最后登录2004-08-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-11-29 13:07
多谢了。
shiyuewei
驱动牛犊
驱动牛犊
  • 注册日期2002-03-08
  • 最后登录2002-12-13
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-12-01 14:44
看了大补!
游客

返回顶部