QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:8 O6 h- q& x' b
--------------------------------------------------------------------------------4 L* m. u8 J& ~3 y, q  ?
作者:suxm < suxm@nsfocus.com >- k. }2 z' _. d
主页:http://www.nsfocus.com
$ A6 m2 L8 r5 v! r日期:2001-08-131 n  o7 o6 s2 z6 x4 Z, \; Y7 u
* l( Z  d0 w5 w5 Q% i0 L' u
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。
4 I. U# S: `- i& i# T! k  l! i: l迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。3 [5 I' O& K+ M6 j( ~2 o. ~! n
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。
- M7 r3 b6 Q- s1 U% @Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),2 ?/ V0 z# J/ D+ q& Z3 e
  \6 c  n- {0 t, F  P4 Y

" C* z5 _: s! v& {# I5 T
- F0 v" D2 F( @* E% m0 E/ u其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。( t, o0 Q- ?1 N4 \9 |7 B
Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。* c# I! r& ~5 N' B+ }' W( w1 B
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
# ~( b: w3 ?. x% F9 M  Yint51 dw kb_int ;keyboard-handler offset8 q& s# ?$ ?; N# s
dw kb_sel ;keyboard-handler code selector# F9 }* [$ j. e9 G, z3 Y4 d. [
db 0 6 X/ h% C; n, }6 G' P
db 8eh ;386 interrupt-gate
+ U( [* B% |: {  o: P) _9 g- kdw 0 ;offset is in first 64KB of segment
& \* {( Q0 T* a$ E) e9 P是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
+ ]/ g7 k4 T7 I/ {8 O$ A这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
5 |7 M4 @" |3 L! ]5 B( g* e提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?0 X9 q* D6 A. k9 p) Q8 d8 X& I9 ~
答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。
  `5 m% N8 {. N7 j8 W# V- f在单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的情况是大不相同 的。
0 J/ j' I' q* _- ~" c, rAladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook5 z  E( ]1 W6 g5 O' R3 i* |
IRQL ; w; b4 |  }8 }. i; N# C
1 3D 3D
! F7 L, z/ I" j% z& n3 f& Z- \" v2 41 41' s. k7 \9 g* y$ r) w
3- }' U! Q6 O: |
4 51 51 51
" U& A  t# K/ X8 N2 e# q/ v' j: ~- |5 61 61 61) S6 N7 s3 F2 h
6 71 71( E5 N7 Y7 P* n( t0 r/ `$ i
7 81/82 81/82 81
/ `2 s: J* R- N8 91/92 91/92 91/92  p4 H! x! @+ g7 V' @7 P+ p
9 A2 A2 A19 r2 l* @6 @6 i
10 B1 B1 B1/B2/ _, o1 s9 R* R. b) H6 Y/ r
11
' y5 q3 n1 A9 \12 3F ; K% |- |  m( `6 N
13 3E 3E 3E 3E
) P" m, ]2 g6 g14
1 x4 t1 [8 T  r7 X. a9 d# Q: w15 3C 3C 3C 3C 3C/ m2 ^/ |+ z; w
16 3B 3B 3B
. |  b6 }2 }8 b0 o1 @7 `17 3A 3A- B, I9 f" G1 V& R
18 39 39
3 _! r8 R( C) f19
& r6 R- R% O/ I; \20 37 37 37, `; O4 n8 k% O+ g4 L
21 36 36 36 36 36 363 i4 b# v) |. e- G9 I3 V; t) S' x# ]
22 35 35$ W( k4 o4 L4 s- n
23 34 34 34 34 34 34
& g1 `, K- c# P( c24 33  g: o* l* \3 G. }4 {
25
" @  X% i$ C: S& \2 t* E+ I26 31 31 31 31 31 31; j* r) u0 `4 M1 j3 z
27 C1 38 C1 38 38 38 38 C1 38
5 d0 X) e6 M/ R. z: k28 D1 30 D1 30 30 30 30 D1 30
5 @% e$ g8 E2 A; y29 E1 E1 E1( u3 B: B, d9 P
30 FE/FD FD/FE FD/FE
  g+ K$ w0 i" W31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32& k6 U# R, C+ ^& q# G7 k1 F0 r

1 E! w* a9 P5 k. \" ]" I* N4 N255 50 50 50; {+ s% u" ?$ C3 }6 R
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E
- v. G1 ~$ [$ o+ O3 J0 L$ {  M
% L8 X; D% w: N" d& X" e  {+ U机器配置:( \  f9 @9 U1 W! k0 n* b5 d
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
; f% e. g. V! ]7 w. f9 w3 k+ `& [BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3/ z. k$ q1 t- v: M! F7 \. R
BIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
$ Z, u3 |/ x% o3 U& NHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP16 r, ?$ ?* v( `% i' H  K/ k9 x
Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
6 {. S2 p5 c% P; O% NStat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP29 K; }8 s* [2 O
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP4: e) o  s* A( B6 ^% C" Y. y- g
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
5 a0 n, N6 R9 S) w; ^6 J7 w4 DNotebook - Pentium 200 MHz, NT 4.0 (free), SP3
+ |! K5 [0 E' ]& H! j" r6 t% P& |3 c3 ^1 ~. F8 |5 ?8 s8 q/ u
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
2 `" v/ a4 x( w5 j; v& \9 rWin2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。: `2 r. F# ]3 z* d: p: r
:idt
3 Z$ O6 V4 L& w* H  aInt Type Sel:Offset Attributes Symbol/Owner
4 ]9 z7 H# y" ]' z) [. ]IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit0 }1 X; G  o4 q/ \6 m; [! t: z( f
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590  X* a0 D$ v3 H# B9 O1 ^! h9 q, M! f
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0! ?- B/ v( \" I5 ~; E
……
0 H4 S; I/ x9 z00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
/ o1 B& h) O5 W00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
/ H; R$ q: K& n4 X& u1 H. |+ Y  y00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
: I2 y" z6 g4 p  X从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
4 Z' U& c- Q9 I8 L; C) ?在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。
  Z6 R1 Y% [% x; H  y7 ]. ?+ k7 T2 i8 u# R% v1 M
. |+ D! T  T, [8 @7 n+ Z

  J6 M1 H7 ~: A& {) u$ D3 l提问:IDT表的Base Address怎样得到的呢?
1 }, B1 A+ P( y+ q0 H7 u答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
' O$ U1 t& W' I. g" k7 nhttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:' t' H2 N3 a4 Z! P" ~0 X9 e+ [7 g9 A# i
SIDT - Store Interrupt Descriptor Table Register" d% V$ }. b9 a0 e  z8 C+ P
7 R8 N3 `7 L1 a" r2 k# j( @: N
Guido Wischrop提供了下面的代码可以读取IDT的所有256项。5 `% u  r( c0 `7 b; ^* M6 Y1 Z0 h) i6 O

4 K' R" ]+ r* _5 CUCHAR *mBuffer;
2 ]+ B* `" j5 G0 E; ^. `7 UULONG dummy;/ Z: N/ m, n$ ?; E; p' n. z0 {7 O2 c+ Z
……
3 I/ q& w  [# p: M  x5 C- k( i_asm
+ T# L# Q; O3 A0 r% ]: ]& Z" t, C{
# }$ Q: [2 Y, n# ~+ S: D" Omov esi,mBuffer # E9 C$ T9 o8 n  |7 c8 p; R
sidt [esi] //load IDTR to *mBuffer& q7 z2 [8 ^' b2 Z- u
movzx ecx,word ptr [esi] //load size of IDT to ECX* z9 z2 A8 l) B3 d2 v
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX
7 j- P7 u4 D( O/ U- J& u/ jinc ecx 2 Z( m3 S7 a: }
mov edi,mBuffer //mBuffer is the target
$ l3 W$ g. y; _- S6 Rmov dummy,ecx //store size in dummy
8 O0 _" U0 ~  ?; _mov esi,ebx //store IDT Base Address to ESI
& p" m# _/ F3 jshr ecx,2
8 t) [" s8 U- u0 O. w9 W8 Mrep movsd //copy IDT to mBuffer8 q; t  }7 e: y# n" ~/ k
}
+ D4 G8 u1 g9 I6 v- s! m6 w9 V7 J- b" v. z% C/ n
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。+ ^4 B9 H. e/ F% X$ _" z6 {8 m
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。8 e( R* I/ X$ s: e/ c  F( _
(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
4 T# W& ^) K! R+ t5 i, X! T0 |(2) Interrupts---> New$ v2 X; q- B" C6 u' H$ b
Interrupt Number = 14(或别的) & Edge Triggered & Shared. ]) W( V% g6 G- t( C. k/ e
(3) Listen to Interrupts
( d  u6 \  l) g$ W1 m+ A如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
; _% |( r$ ]: q, a(4) Generate Code
% F* v) s5 }  ]# c1 {8 ]" N(5) Build and Run
  V+ |" m, N9 b7 R(6) Enable Interrupt
/ ?$ i4 \& y) |& M8 I1 S0 y. U(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:
4 b4 f% a# n: g5 y( Z:intobj' K+ B+ R% y! ], R
Object Service Service Affinity
& x3 [( K1 X7 V) N9 o/ e" lAddress Vector Address Context IRQL Mode Mask Symbol
9 m: L6 L: }1 |+ p9 ^% ^: Y- ~FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
" K9 q1 n% B  V, K0 ]8 TFD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C
+ }: h7 A* k1 U6 ^* kFD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040; H1 K9 y; ~( f, ?1 z& k
FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2
: V& S( `; S* C+ hFD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
9 q2 D# E! b& v2 R. qNTICE: Exit32 PID=70 MOD=ps2_diag
+ j. D) ]( }8 F$ Q
5 }  M( \: v& g! Y$ ?0 ?从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
' w: ]( ?: U8 `: t6 P8 A7 F5 p- U2 B5 g
2 j" H6 N1 z/ ^9 R" v3 D  X, E
& u- P' K/ H( w0 `: U) i% u
我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
0 v) B& Y8 B6 D3 S. m/ Y( g6 [, o, i4 j, L' B8 g2 N3 ?
一个问题马上被提出来了
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-18 23:22 , Processed in 0.445636 second(s), 51 queries .

回顶部