QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2325|回复: 0
打印 上一主题 下一主题

关于Winnt/2k IDT的一些思考

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |正序浏览
|招呼Ta 关注Ta
文章内容:
, w/ F0 y6 |! t% ~& |/ Y  `--------------------------------------------------------------------------------
# ^/ D  T3 {6 \% r$ g) N作者:suxm < suxm@nsfocus.com >9 ~) a' i; R4 q9 e  _5 y! y
主页:http://www.nsfocus.com
: J( B: P0 i6 J$ s. D) P) ]日期:2001-08-13
( M, B1 H& r+ P2 ^" x) Y+ _3 ]" |4 P- _) [: F
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。
* m$ H, N1 f( F- S迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。4 l. {% C: `' P2 e
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。# t2 C  c1 o6 L8 Y9 I
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),2 I; o7 I) W& l& J4 M; a/ m
. ~* J! \$ U7 S" S* ~& d
. c: k5 F* h' D

6 B/ |9 k) b$ z: A9 H6 z其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
  T/ L" a+ u* i( E9 a1 yTrap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。/ K; M( x" Y( s2 F/ k
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
8 J& D/ |2 W9 E2 f& r# I8 O$ a3 Jint51 dw kb_int ;keyboard-handler offset4 ?7 @# s1 N, a) o
dw kb_sel ;keyboard-handler code selector
, p! ~& s( y- G1 M6 Udb 0 $ V" Q% b, H0 Y! p* ~
db 8eh ;386 interrupt-gate
( r9 K3 \0 [& x" pdw 0 ;offset is in first 64KB of segment
# B9 v5 S' _1 \) p2 c9 K7 c# h( d是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
( U* ]% {' D! E这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
8 [5 ?" [2 k. t  Z提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?. s1 m$ T% k( K9 X" \4 }9 b) O, t
答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。6 w/ Y, n+ B% g7 ]3 m* D
在单CPU的Winnt下,实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断号30h——3Fh(看 到有些资料上说Winnt下这个映射关系不是确定的,但是我见过的单CPU的Winnt中基本上都是这样的映射关系,而双CPU的情况下,情况 确实有所不同)。从下面这张统计表(http://www.wischrop-net.de/nt/kapitel7.htm#7_2)可以看到单CPU的情况与双CPU的情况是大不相同 的。
) X3 z4 O% t, G. r, G' BAladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook, F2 [( N1 j( P8 N+ _
IRQL
- }( d$ @- M9 N% _9 u1 3D 3D# r$ U9 k, ~8 ?6 B5 `+ X& n3 \
2 41 41
: d0 e9 P% [  I9 Q' I' `3' I% A( H4 k. I9 ^& j
4 51 51 51+ Z# k& ^/ G( j8 ]3 R( p; q  w9 Z
5 61 61 61
  t' K; p2 W0 u8 a' l' F3 r6 71 71
3 Z3 L3 Y) X0 `5 ]: R% Z7 81/82 81/82 81
# [2 q/ V" |& X& @% g& T' D( k8 91/92 91/92 91/924 h; O7 A& {) R& ^6 y
9 A2 A2 A1
. k0 m2 G- B- @10 B1 B1 B1/B22 Q8 m; X6 }4 a' T+ s6 k2 ~
11$ M! ^! x  f5 {& L. Q
12 3F
; y9 R1 K, W% u2 {/ |" x13 3E 3E 3E 3E
6 L" |0 I: \# g4 W14- ^, k' l7 t3 z0 Z  Y
15 3C 3C 3C 3C 3C
/ E$ Q9 J( ?1 |7 n1 J, o16 3B 3B 3B
$ c+ {/ |+ ~% ]) _  s17 3A 3A
% P- W; k, e) J* X18 39 39" h0 X4 O9 z* B7 _7 t- a' j2 M
19% @$ |0 F) c$ @0 A
20 37 37 37' Y5 G9 X# p' }: N" Z* D: ^1 n# @
21 36 36 36 36 36 362 S/ O# A# w+ c/ X# s
22 35 35
% j" w+ `1 B4 \6 t) v23 34 34 34 34 34 34$ i) K/ p7 m" L! Z) H! C; L3 ?
24 33
6 S) {& N- Z6 o5 A/ `3 }7 t: N; ~; V25
) W3 o0 `, V# L# S26 31 31 31 31 31 31
1 s3 N) i- r2 o( F3 U27 C1 38 C1 38 38 38 38 C1 38
- X* O/ y$ \! O0 V28 D1 30 D1 30 30 30 30 D1 30" @+ q, |$ ]3 x7 ^6 l% [7 E  G
29 E1 E1 E1* G* y1 U; y0 \. w3 a! C) X" X+ g8 J/ B
30 FE/FD FD/FE FD/FE
" ^2 @3 H# V& [8 R  H31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32: M" F, O9 b  `* L! B
- h# S2 X) g0 h. J# [6 A
255 50 50 50# x' J- E0 W9 _7 w  q" z  ]% T
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E7 D" w4 S0 _! V0 m5 |; Y; B
9 d0 W# u  k; x- J. x- U" v
机器配置:
/ G# H0 T; e0 d3 ~" PALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3( v; ]9 Z6 W# r  M1 s% h7 Q
BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
9 w$ i6 W' K6 l3 U+ yBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
) c% @0 i4 w3 D& j( T' wHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
3 q+ T$ W" |2 w# z2 lStat_02 - Pentium 166 MHz, NT 4.0 (free) SP32 q( @4 S* k! F2 {
Stat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2
: L7 t2 j6 y/ e4 i4 G& o. oOTTO - Pentium II 300 MHz, NT 4.0 (free) SP46 x/ U; S2 J( X4 x) K- L& b
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
8 V* D: ~# {1 w  I( HNotebook - Pentium 200 MHz, NT 4.0 (free), SP3
) n+ @1 c* x/ y" ^3 E! o. i2 v2 h
$ E0 L+ v  C) n6 D. [! A. ^9 R: x# Q在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
; ]1 N. b, A2 S1 Y6 ^" R# J% G* fWin2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。/ k& b9 g" S4 e3 B& _3 m
:idt
, s! Q: D; e3 FInt Type Sel:Offset Attributes Symbol/Owner
" Y+ B6 e6 J. x6 _: @+ ^IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit. \" j& p& z6 b* b2 A/ X7 Z3 ]; {4 L
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590% M8 c5 m& _; D* P
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E00 m4 z4 o: l% D9 g3 V
……7 n$ N" x& k- f& y' u! `- b% |
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092* O6 r  a& ?+ U4 W$ A: H8 I
00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
1 D! ]0 m/ f# L# ]4 C  a00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
6 ~* ]7 I4 P2 z# Y从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。$ C: r: A; Z' I6 F
在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。5 q6 \% @5 g3 W# m( O( H/ {
; ~' `  v8 [# ]9 E
: @! p; V' Q7 r( L, f7 R0 e
7 C# z, w% z& T
提问:IDT表的Base Address怎样得到的呢?/ Q3 u6 B# A  ^6 L. p
答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
5 e4 G8 ]" Y- M1 \- \3 Ohttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
) O. c( W; ^7 T1 D  H2 BSIDT - Store Interrupt Descriptor Table Register( r- ]$ g: L, P: B" _( A
) ^: ~9 i  a& b4 {" @1 W
Guido Wischrop提供了下面的代码可以读取IDT的所有256项。8 n7 V. w( b, ~% Z1 q9 l5 l
5 ~. l4 s0 S* m2 {
UCHAR *mBuffer;/ O) g: @3 V$ y9 B# w) B! H
ULONG dummy;
, f' s% g5 G- M……
% M5 \; t! G9 h- ]1 g4 W_asm# ?( p0 g3 ^; t, z& K
{- F9 F4 B3 I* }* A" g( a" {
mov esi,mBuffer . x/ ~2 v2 k( s$ t+ y/ W8 l
sidt [esi] //load IDTR to *mBuffer
8 P6 H( Z+ r6 P' ^  dmovzx ecx,word ptr [esi] //load size of IDT to ECX# o" s3 V+ |- L9 L
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX1 o& b7 [# N4 [8 H* V9 N3 e
inc ecx
- K' W8 R, g' _  l7 \$ D1 e1 \mov edi,mBuffer //mBuffer is the target
3 K2 r7 C$ n# O+ o2 Tmov dummy,ecx //store size in dummy
4 R; e* w6 T: Imov esi,ebx //store IDT Base Address to ESI% L- G: b+ @: g* x: T6 C
shr ecx,2
  k! |  G# O, ?. R' i+ _& Prep movsd //copy IDT to mBuffer
/ L$ n1 o. o- i, ?1 F}( b9 D+ W4 E, Y% x+ a  M% K

/ E2 t! _# p6 Z这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。/ K/ t/ p- \* x* A8 d4 T0 \% |7 F
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
& j- u. y3 i3 p1 [+ u(1) Windriver---> Driver Wizard---->New Project----->ISA CARD, m" v2 V; _/ k8 T! ~
(2) Interrupts---> New
9 @5 {: j" q: r: w& BInterrupt Number = 14(或别的) & Edge Triggered & Shared# b" c  Q- o2 j4 \; f4 y
(3) Listen to Interrupts- c# Z6 W: L& B6 n
如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。, C, \( M% ?5 T+ m8 A
(4) Generate Code( p3 g7 x6 a/ [! m; e# h; \3 u
(5) Build and Run
3 |3 ]% R$ {7 a, t' ?, K4 T(6) Enable Interrupt
1 P7 G7 r5 {+ g. i(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:4 O  z' z6 L+ |: T
:intobj& A6 `! b0 r; ?
Object Service Service Affinity! ~- N) ^1 P4 M
Address Vector Address Context IRQL Mode Mask Symbol1 u7 S& |1 y9 ^# R: \
FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
' V2 z; r& o5 i0 U+ s* q: {! q. TFD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C
, j$ G5 B6 p; J4 @FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040; n  T( h8 S1 i+ a; g7 W
FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2: G- V6 R5 c. C$ i2 X; O  ^9 T5 \6 A) Z8 N
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM- O7 x8 \& S8 p* q% U. ~% [. i  s
NTICE: Exit32 PID=70 MOD=ps2_diag
, h9 y" n$ \% ?$ }& z* ?# Y& v6 a. d+ [
从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:& Q& a& v$ X. A9 n) y* L/ e! s

2 ~% s2 q7 k# g" a1 _( D- Z: N- o: u. r5 Q! k

  `0 o( M, e& k* [( ^# h我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
) T5 c  ?7 b" ]: e: p. [; u  T
2 P. T. _: h: C3 x" m3 X一个问题马上被提出来了
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2026-4-19 04:24 , Processed in 0.387385 second(s), 52 queries .

回顶部