QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |正序浏览
|招呼Ta 关注Ta
文章内容:
8 I; n9 U; ]* {7 O--------------------------------------------------------------------------------. q8 o  \! Z2 V
作者:suxm < suxm@nsfocus.com >' R8 r3 S1 Y. b1 m2 B. H
主页:http://www.nsfocus.com
7 t) ]3 R6 ]7 P! Q( N日期:2001-08-13
. F7 |1 g4 Y0 t5 n" `4 H- E8 ~2 J3 p
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。& D: K. ~' e0 |
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。  L$ t( q5 y  R
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。! }) a# w" Z& T: I5 T3 r" k
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),2 ]5 c5 L7 x2 @" L1 t1 f

% _( R) n" Y2 W4 Q
1 R9 a8 M( q$ z9 C! j- ?4 t  u5 v1 s4 g
其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。: F1 ^: x) U8 n5 m: O
Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。& u; j& o, w* D) P7 k5 N9 w6 }
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
4 p' g+ V. _/ d' nint51 dw kb_int ;keyboard-handler offset5 C, `# B, G7 `  C+ p4 ~
dw kb_sel ;keyboard-handler code selector5 t* D2 y. u+ ]! ]8 o5 @7 @
db 0 3 v+ P! V! u+ Q5 k
db 8eh ;386 interrupt-gate
; Z& h# F% }3 _4 h! ]dw 0 ;offset is in first 64KB of segment6 A  x; z- o1 W, F7 K' T9 O( y
是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
. _* C! D$ g1 n+ G: f这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
$ E6 j- E: }  K- w2 T, Q- l0 R提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?+ H3 U( l4 C2 d# Y- _9 s. c6 ^
答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。* J2 V3 j6 q3 \* q8 o
在单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的情况是大不相同 的。+ j, f/ F, c7 g
Aladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook% m4 F, C4 A/ l+ m' G
IRQL
6 S  ~  T3 B2 z8 g$ E3 f; y1 3D 3D- A6 x8 [4 @( }3 E3 ~% s
2 41 41( l. N  Y! g/ C0 P; A* M3 N, _
3! [0 x# `, k/ O$ E5 F
4 51 51 51
, n" Y) a' e$ c1 c/ p& h& G% L5 61 61 612 P( @& K5 x* ?+ V, I2 T
6 71 71. |3 w3 j# A8 Q3 @: W, n# u
7 81/82 81/82 81- P* I4 b1 A, `3 m
8 91/92 91/92 91/92* ^6 [5 t" f% w( v" t
9 A2 A2 A1
3 G: y; F0 j& V9 @$ G10 B1 B1 B1/B23 [4 r5 U* Z2 ]; H
11
5 T3 Q% b% {9 A* a12 3F
+ M2 ]; k- b0 y1 i13 3E 3E 3E 3E; ?/ |. T( m5 t7 t0 I9 b
14! u( a4 {8 d4 J* ~
15 3C 3C 3C 3C 3C; Y- m1 M8 o. j
16 3B 3B 3B
$ s/ D9 x+ Z. \17 3A 3A/ T. U+ W- J5 v0 W
18 39 39
' D, \1 |  M. ~" z191 |& @3 p' M4 q, [
20 37 37 371 R% p  R6 v( ?6 T( [2 V% f, X
21 36 36 36 36 36 36, |/ L, M0 l2 S2 C
22 35 35
3 y  i7 y7 W4 j7 c23 34 34 34 34 34 34
7 a9 j6 I) [- H% i$ l" {! Z24 33
0 Z- O) o1 o. @* G: T3 A4 z2 c/ k25 1 p9 |  B% x; z5 h5 W
26 31 31 31 31 31 31
9 Y& M+ q; @/ [+ j0 p1 L! z, c27 C1 38 C1 38 38 38 38 C1 389 H; j9 V' ~, D, D, ~" t7 P2 ^3 t  l- r
28 D1 30 D1 30 30 30 30 D1 30
1 p! O' V6 j' I, p29 E1 E1 E1
/ m9 Q1 i1 R. G# L' N2 [% P30 FE/FD FD/FE FD/FE% T6 O  i$ V/ \( w! w  v
31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32- G  ^* o( Q  Q7 m3 X5 o6 U* k

$ f! ^/ o% T4 Z8 j" \8 {- S' s255 50 50 50+ b3 j- i" ^! i& |2 X: v1 M2 E- Q
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E& k# u- u# Y" {$ F& J$ F
/ r2 C  N0 X" [9 f% n$ Y1 @2 U- n4 ]8 E
机器配置:
; U, r3 C  k7 U2 j6 D! e6 BALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
5 g: a3 g0 j' ~# OBasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
+ K% v) i" B9 X0 qBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
8 e5 M( `( b& T( N% S4 g/ dHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1( z" ?% y) \. I( J( p- E/ W0 Q
Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP34 r2 B3 J) c- a: P7 l4 w! h; U1 v
Stat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2* v7 t+ G7 W9 r. f  |
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP41 W$ B. H: W+ f1 @1 V0 [; L6 x+ Q' _
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
% L/ P5 u8 n; H" i& p+ y* e: M% P, gNotebook - Pentium 200 MHz, NT 4.0 (free), SP3  ^. k2 C! M: ]+ p

% P" ?& }. _, o" ?% K( r在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
. [; a$ v  t0 l$ I) d; MWin2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。& t$ v! y* H+ z# n- t. f
:idt
* }  Z$ m/ `6 Z5 i' c  aInt Type Sel:Offset Attributes Symbol/Owner! S7 ]4 O( s, f4 a  h
IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit6 A" A0 \4 a+ B) M0 Z( x
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
! z7 j9 x( H4 V6 E8 n0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0
* Z% [/ z, w; `8 R7 w7 e9 n& ?……4 t7 v3 o# R  {$ l" h: v
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
! h- H9 K! `# h, x00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+0922 e" x8 ^. k0 o+ m5 [7 h" ^$ h: G
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
9 s0 ?" ]1 o9 J% @5 p0 N从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
- r, Z  l' l, F$ b1 L8 Q( x. e在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。2 y1 O4 r" [: {& J* F5 f5 T  V
2 Q  S6 q+ `, F" l9 V2 Z3 ^: j2 c

8 \, Q4 S1 k/ C& A; {' J/ Q
7 @4 B: j' |: I/ {$ J提问:IDT表的Base Address怎样得到的呢?' Y: o: G: {5 @* |! a( |+ f
答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下- e0 y: {' q0 D. o$ w
http://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
% B4 b" v3 j' rSIDT - Store Interrupt Descriptor Table Register7 L6 f9 K+ R$ K, a: ]

, k  q  W+ Q7 h% u2 Q. t) JGuido Wischrop提供了下面的代码可以读取IDT的所有256项。! H$ a1 P" f' A% z4 e

5 P% N# d. @: \2 D# {4 RUCHAR *mBuffer;
/ [3 L2 A: `, p4 _3 @ULONG dummy;
2 V( r( Q7 f  g4 j……! r/ ]" ~2 q$ D7 A. x5 }' l
_asm5 r3 O; j% Q% r! }3 \2 {
{2 S# G0 d0 R- l+ u; T9 M+ t
mov esi,mBuffer
' S6 `+ R/ t" J( d% L% G4 R8 Fsidt [esi] //load IDTR to *mBuffer
8 r6 L% y* H1 @7 f9 {& `movzx ecx,word ptr [esi] //load size of IDT to ECX
2 H- s9 U9 Y' P) r: wmov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX+ r' H2 f% @/ `6 s
inc ecx
" K8 ?) x- Q& G( dmov edi,mBuffer //mBuffer is the target* ~7 l' V; i' Q+ m+ O5 X8 v& V2 |. p
mov dummy,ecx //store size in dummy# @! R4 [3 M' c5 p2 Q7 a: \/ f
mov esi,ebx //store IDT Base Address to ESI' b$ T8 B- E5 T/ ~$ s! t0 F# v
shr ecx,2
+ `; Q" `  e) ]% ?" o% {. Crep movsd //copy IDT to mBuffer
1 ]9 {9 v' _+ w& ^! E! d. e}0 h; t- h4 i" k- h( r' e, G
8 ]6 y% z4 R" i
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。- r( a3 k  Y0 C; C( H
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
7 g5 @! ~* ]  L. S(1) Windriver---> Driver Wizard---->New Project----->ISA CARD% B" J1 L2 T: V% ?7 J# ]: \
(2) Interrupts---> New  j8 M- A: v9 Q9 H( O# z
Interrupt Number = 14(或别的) & Edge Triggered & Shared
; |% M4 g% z- L(3) Listen to Interrupts
: p) y; Q4 C" L- s+ S4 z8 d如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。3 C. B' O. z! ^( u+ K
(4) Generate Code/ Z1 E6 ]3 V2 w2 k; L
(5) Build and Run
) |# }% Y% F9 N* o) z0 D(6) Enable Interrupt+ }; J3 C0 C3 B) F7 C5 E# ^  x4 _
(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:
& m9 p$ i8 l+ L" `4 X2 f:intobj0 j& U1 ^4 j6 ~' j2 N
Object Service Service Affinity. y( j- o6 r" G2 t* Z+ n+ j
Address Vector Address Context IRQL Mode Mask Symbol4 N  k  x3 j9 }1 e3 i/ {2 I8 S
FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
+ L0 J6 L2 U" TFD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C( _) `9 I7 ?. C/ j0 p0 `3 |1 K
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
0 r  p, i6 z* {3 x3 L1 AFD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2& F* t) J1 P1 @+ P7 U# W: V
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM( e+ _- E( ~# z6 Q
NTICE: Exit32 PID=70 MOD=ps2_diag
3 |; s6 b( @0 e+ `2 _- z: Q6 f8 C- q/ C  g
从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:# `" `, t8 H$ ]" o" a
+ G$ h$ \- O" ~; d5 e6 M' n% d9 k

7 O9 c" I: ^' H. b2 g
! w9 ?! A' F" F3 d9 g: r我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
1 i( Z# Y4 S3 l% u& F
  ?1 z9 w  c. t0 U" m( [4 z  m/ J一个问题马上被提出来了
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-6-12 17:40 , Processed in 0.427321 second(s), 52 queries .

回顶部