QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |正序浏览
|招呼Ta 关注Ta
文章内容:
( x1 h1 [8 L+ |; [/ n2 b--------------------------------------------------------------------------------* L  Y1 g! F: H+ Z) ~" E6 C
作者:suxm < suxm@nsfocus.com >6 W' L" x1 p4 S; ?( q
主页:http://www.nsfocus.com
" x; B, r/ i$ z$ Q  g$ h) p4 Y  }* T& l日期:2001-08-13
* U* h8 A% w# ~3 n# `2 _1 k% Y0 U2 z# g+ H* B
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。( u1 k) T  Y0 ^0 I. n3 e
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。
  }2 \# m4 `9 N  D) ?让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。7 B1 b5 u/ t# E2 N4 M
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),* ~: M9 ?7 R# L
7 A( t, {& ~0 t$ @
0 K$ U5 G8 ?4 V" q6 ]
) b1 u, L' ?. k# k& |
其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
( Y* k+ y9 s1 A4 x/ nTrap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。5 X6 r0 D" P6 W; Z7 b( m
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
4 H4 w& L! @; E' s/ I6 G+ s" dint51 dw kb_int ;keyboard-handler offset
- R  A9 U; A0 m% S  x5 ?dw kb_sel ;keyboard-handler code selector
9 V: G- y3 ?- v7 qdb 0 $ d1 j2 U$ E8 Y) ~+ V
db 8eh ;386 interrupt-gate
8 R5 D+ K" I" C5 S+ hdw 0 ;offset is in first 64KB of segment
  J, X" p# b; B7 d3 r" d# ^是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?/ a4 p7 V, u. D$ j1 R
这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
: m! d# T+ k% H2 J提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
- K* v* x; x' y% g. t  n- S答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。
! S. e0 i( X7 f$ g  D, C在单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的情况是大不相同 的。7 K' ?0 d" ^6 e! G( k0 x6 u# {! Z
Aladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook1 P3 ]. {$ f# w' I; T
IRQL 8 t1 _- f; r7 k* p: O
1 3D 3D
, h' U- y2 z/ y; d! g3 ?2 41 41
) t$ c2 r+ ~3 s) c/ Z! h3$ O. O( v& Y2 v( i
4 51 51 51
; l: a1 K9 a+ D% z  u. g* @5 61 61 61
$ z$ l5 O) H- K8 L" ]3 w# q6 71 71: ^/ q" v! D, k) h1 ?8 d0 H
7 81/82 81/82 81
/ C+ o* S. ]) P# g: l8 91/92 91/92 91/92# U+ j; m7 M1 `6 s6 U
9 A2 A2 A11 w8 f9 s4 X5 I" j# n
10 B1 B1 B1/B2
6 ^; v5 {+ N3 I3 @: N3 |11
6 ~( V3 t; P# V% a/ r12 3F
+ Z. T7 ^( q, ?& g$ N+ h/ X5 s13 3E 3E 3E 3E
8 c* [! I" C) q8 F$ \  ]  m140 z' Q* B) a- z/ }! \( X2 s
15 3C 3C 3C 3C 3C
" ?: ?  Y" i/ i" b' M1 S16 3B 3B 3B
' B. H: ]+ a% G4 y- v4 n# e6 O17 3A 3A' N. w0 b. s7 A2 c+ N' o
18 39 39
* X! G% R3 o* ~19
" R9 G. P' _, a# u, ^20 37 37 37
8 y/ D1 x9 V0 w) }4 i# H21 36 36 36 36 36 36
" N/ u! D+ x% _9 f8 ?' m! f22 35 350 N6 y! W+ l" v
23 34 34 34 34 34 340 l* }7 O+ ]. u- v" X# N3 v
24 33
& P9 [, W2 i/ ~$ U25 % e6 [$ h# a4 y: K
26 31 31 31 31 31 31
1 W/ l0 |+ G# r3 U5 N27 C1 38 C1 38 38 38 38 C1 38
: _3 _! w8 \, K+ ~$ T0 D28 D1 30 D1 30 30 30 30 D1 304 [' @; l1 A$ D: h5 Q+ k% J
29 E1 E1 E15 b9 F9 }5 t0 a
30 FE/FD FD/FE FD/FE
' Z; e1 R! L$ V% a" J6 C31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32
7 U! M# l: c+ v# `
2 Q* c  f" {/ }9 A* v255 50 50 50
8 ~" a: D" T/ C0 S; N7 ZDPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E, i- ]% L* Q0 v7 B) W4 R6 d" X/ G
, {  `1 m# M1 h, _8 ~3 R
机器配置:  Z' _. t& d3 I' r/ m$ ]( d
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
( [( N, r* S* q' _) Y3 \BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3' h" K6 c( H; ?3 l$ }
BIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3" U% j) X( u* ?5 o9 v
Hugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
2 e% l- s! A6 i8 c3 C5 mStat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
! a+ s7 b0 O. a, h# A4 SStat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2
9 r; I; l  f1 u/ N4 B9 \1 cOTTO - Pentium II 300 MHz, NT 4.0 (free) SP43 V  T6 K1 ]' Q& M& B' q
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP30 d7 I0 _! d1 F* O( a* Z
Notebook - Pentium 200 MHz, NT 4.0 (free), SP37 D% j- G' a2 W: U1 {
% I$ j2 _/ E; Z( m6 q
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
' s: N! S* Z. n% j7 A0 K" yWin2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。
( Y. W3 I% U# i  U4 I% c:idt7 J* U7 ]$ R8 c
Int Type Sel:Offset Attributes Symbol/Owner
6 f7 z* B' `6 B# Z5 O& i8 P, nIDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit
5 B* ^8 T' x2 w4 i0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
- p- k/ g5 H6 f! ~+ q  E$ _6 q0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E03 y: z# Q' {% i( D: r- W9 }, [
……- B5 Y# |' X6 ?* C9 \: I
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
' r* Q+ f1 w+ x( S0 ~, Q00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092* {3 X/ X* R  K
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093% p: }0 s$ A& k1 }
从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。2 B+ u7 k0 S9 W4 Y% {. m
在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。) M( G8 \( k0 J2 \. k. ?4 T
- ?+ c9 u( W' E( h2 V  ?  ~* N

9 ?  I! O: V- s  @* i. L
3 f6 @! t% J( W3 V$ v5 L% k5 Q提问:IDT表的Base Address怎样得到的呢?
3 S& y) n0 `2 N2 t答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
* F4 N4 l# a: H' q+ n6 X. Thttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
4 t, F* N- W/ ^4 T; Z+ K+ q: `SIDT - Store Interrupt Descriptor Table Register
# e3 G7 c0 D4 }9 o' R/ D, |
. q$ |; ?4 A9 L/ TGuido Wischrop提供了下面的代码可以读取IDT的所有256项。3 q' f# i6 B$ c' M5 h( s: f  q

/ \$ S) l9 o: h) Y& p" tUCHAR *mBuffer;
! h( q* ]; d( {/ wULONG dummy;
. @. d! H6 R: }. W# V7 b! i……
% ~0 L# U' ~% j_asm
6 G  w  `* z: t% R{
6 S' J! z. g  v7 {mov esi,mBuffer 2 W0 ?- z7 O. \, b" G
sidt [esi] //load IDTR to *mBuffer
' t, {4 X% V4 f3 G% ?' Kmovzx ecx,word ptr [esi] //load size of IDT to ECX4 F' J& d: }* e; j) z* i
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX
1 T" T# i$ G# l* rinc ecx
3 W8 t5 J$ {% d; b5 ?mov edi,mBuffer //mBuffer is the target7 y; j9 I  V1 @1 Y/ |' D+ T
mov dummy,ecx //store size in dummy
, J5 M& Z5 E( d. p' \0 ]mov esi,ebx //store IDT Base Address to ESI
7 s7 _1 l$ {% f; j0 K6 Nshr ecx,2 2 f$ E9 _. n5 ?& x
rep movsd //copy IDT to mBuffer
' V& `  T8 V7 i; A% F2 C5 Z}9 A" A8 F2 _) Z7 K/ ], |1 `1 |

2 F0 X: C- L: t* i8 I- @1 w, ?  V这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。% j7 Z) a6 @$ @+ W6 `& ^) @- U
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。7 ^; V6 m8 @) B
(1) Windriver---> Driver Wizard---->New Project----->ISA CARD* n# L: u+ W7 x  t* G
(2) Interrupts---> New4 Z! d3 n' m% x7 {8 C
Interrupt Number = 14(或别的) & Edge Triggered & Shared
' i3 q8 c% C) ~( Y(3) Listen to Interrupts
% G' F. p' }- c5 c. q% I/ W+ |7 F如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。* f, H7 N7 o( K) W; h1 a
(4) Generate Code( o, Z/ Y6 h$ v
(5) Build and Run
* s% n& l2 c; w* v9 Z2 q(6) Enable Interrupt
* w6 K# |+ S" h+ j4 w$ m(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:( L1 v) g* T  s" U
:intobj' \' u  ^2 @/ V& Z$ D0 a9 R
Object Service Service Affinity) A% [. f9 s& z
Address Vector Address Context IRQL Mode Mask Symbol
( q! H  Q/ n1 hFD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
0 g; W  O# L- P8 WFD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C
9 D$ K8 C$ V* P3 w3 T  N% oFD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
/ e( y: I3 Z6 `3 O* u  s0 y& FFD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2
; e* S  R+ D$ s+ g% C3 X2 dFD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
$ O, n9 _. \  a$ @9 MNTICE: Exit32 PID=70 MOD=ps2_diag" y$ X  r; M) Q' y- W

1 w3 I. l+ q' R6 ~+ q) K$ g从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:3 r( C5 L1 Z' T! j2 \! T) {

# z9 h: Z) ?4 C9 w! J; I: @) X3 |7 x. e. v

- t/ h8 U$ J  O+ m; D6 R# X- y+ z我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
) |& B0 z. G! ~8 e' w* ?  z( @
$ M% f& j4 {- `, P2 H& t8 D一个问题马上被提出来了
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-8-28 18:01 , Processed in 0.420154 second(s), 52 queries .

回顶部