QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:* t" e# T2 p2 p9 Z
--------------------------------------------------------------------------------. J+ A6 k1 ?0 l
作者:suxm < suxm@nsfocus.com >% m( q8 b5 |7 C$ q
主页:http://www.nsfocus.com& P; A* Z/ x2 J0 ?! E- h9 }
日期:2001-08-13
' F( J- O, z! r8 M$ j& J7 z
8 B  A  P! l9 y7 `& H/ A2 [) I几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。
- c8 W9 o: [( Q5 p迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。; ]$ l7 N! A! a
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。2 y/ k# g" m$ t8 x* z8 Z9 j5 l2 S! `
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),
( C' ]# q  l1 z. g4 z  v8 e9 B& W  B# W1 U5 c0 f2 K0 l6 u3 p/ z7 D5 p

2 E, f* Q' T3 A% @
, q; R. a- F8 G3 K) J6 T; G% q其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。! p* M0 ?" Q3 t
Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。
% \2 c  Z- S4 l8 K4 u( i下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):) v, `3 |; y3 H! Q0 C  w9 R! O
int51 dw kb_int ;keyboard-handler offset' g, ~. V" c( a
dw kb_sel ;keyboard-handler code selector
( e5 c9 P& Q5 @- {! odb 0 ' A5 X5 W7 Z  h" u) L- d
db 8eh ;386 interrupt-gate" P8 U! C3 q3 T1 R: R8 r1 ]* a
dw 0 ;offset is in first 64KB of segment
" u; h0 z7 M* k+ w% {1 @! T9 g是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
8 R% Z* N$ q. p# z, u" B4 h3 J2 f这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。! N, S: O' u1 a+ Z
提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
" Q# \( A. u3 ^5 x+ E答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。- p- {' D4 ?: `7 O  n* H
在单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的情况是大不相同 的。
" I& D( q+ H1 z" FAladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook$ V2 G& q. G: B2 i7 n. i6 O* f
IRQL * `1 Y" g6 I! d8 Z. l& P
1 3D 3D
# \: N0 E. Z0 J0 x# \! I2 41 41  p, X6 O* w  n7 U
3* C: d+ K( {" j- ^* s$ W: k
4 51 51 51
! A) E7 v4 ]; o. r7 X! j; p5 61 61 61
7 \9 {7 W1 Z; `0 m7 B6 71 71
! P! Q  K5 m$ B0 O! r7 81/82 81/82 81+ j: ?) N# M5 ^% Q! g
8 91/92 91/92 91/92
4 k" b# f" o/ G5 W, P- M4 h$ ~9 A2 A2 A1
" H9 N2 ?( }( ~/ Y- H* ~/ ~3 ]3 G5 D6 A10 B1 B1 B1/B2
1 L2 M! T1 E: [' L11; |$ v8 G( n7 Y; [: ]/ u
12 3F 1 `) ]3 H% P& x" g$ W& V  Q
13 3E 3E 3E 3E
& H8 o) G( q: Q" @& |14
0 D9 I( [' w& o# p9 [6 Z% ~' E: `15 3C 3C 3C 3C 3C! j3 ^6 a9 K0 W# K$ H
16 3B 3B 3B2 v4 B5 n" r. M  d8 S1 u
17 3A 3A
  v! z& z$ B9 q1 Q18 39 39% E( {, ^6 ^$ h3 w
195 a8 ~# }/ X5 I# d- P* h
20 37 37 37
8 Y- }7 U+ h$ n: V: W: E21 36 36 36 36 36 36
3 a+ h' s' N- J8 n: u' H. `! x22 35 35
0 H) k/ d2 n1 `$ x' w8 x23 34 34 34 34 34 34
9 V# c6 _: Z  s1 `8 d3 G24 33
, I3 @: R# o6 W9 z" q6 A25 ) o/ |: b1 ~5 V3 g2 f: i
26 31 31 31 31 31 31
& Z: `* ~* b& @! d* S+ m' g27 C1 38 C1 38 38 38 38 C1 38
: X" R& b( W$ ^6 Y! ?6 P28 D1 30 D1 30 30 30 30 D1 30
3 t8 o4 n% s7 S29 E1 E1 E1
8 X4 B. ]3 B/ j1 B9 |30 FE/FD FD/FE FD/FE
6 P. J) T- N6 q( T  @  C" W( D31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32. P% Y& D( o9 G* j# c

6 q) \( Y, q8 I9 ~255 50 50 50! u; O; u! u& M* R8 C# i+ j7 B* V
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E
/ O' P( g& @4 C- w) G( W+ b% U0 z7 N. B: O
机器配置:$ T: W0 \- k2 u
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3& o* U* l; P4 N$ f
BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3$ _# C3 P3 D" Z3 Y. I
BIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
. j4 F0 j! y! V. V0 a4 zHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
+ J, z) E# w) h/ \- [Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
" z$ w: p2 H1 s6 uStat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP29 B" }( O  h4 I1 d1 I' D
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP4
, x5 l# H! X( A& |: o: {" ASanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP30 R! e3 I' g) d! m! Z
Notebook - Pentium 200 MHz, NT 4.0 (free), SP3
2 `0 n% k; S# U3 S- A2 G2 e5 I. ]0 J8 x) [% k8 ^3 |
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
, h1 Z4 u% `8 l. g# i) |Win2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。2 q! c0 j% _# k: U/ y- }! j
:idt* F: _# ~9 K. Y, Q
Int Type Sel:Offset Attributes Symbol/Owner# c7 I! x9 a9 n
IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit3 [4 e* s1 b8 z5 |: U% M
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+05901 h5 T8 ~! b3 q; r) K; [3 g. l/ e3 }
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E04 ]9 m. W" d2 ]. O
……
+ v8 G: t8 |+ R2 s3 C/ G8 J* u00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
  C: x- W, r7 P4 v00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+0923 R1 L# \' {5 H9 g# r8 T' G6 H
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093% [* z: C. x: @& T3 ?3 B5 Y2 F
从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
3 {4 a3 i9 }; }- ~在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。  t- w, V+ s6 x% [

& m% K" v' n: E. O+ K% R
, ^& ]5 ~+ f# o" H; T  M! C
* y) u) y. `! V' V! b) b提问:IDT表的Base Address怎样得到的呢?' M2 {, O  p) T" A. J: l" M, u8 e1 N1 z
答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
% @. S" r; z& K( @$ G" S8 f& Xhttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:' i3 X7 L# `4 \
SIDT - Store Interrupt Descriptor Table Register/ h% _, s: V# e9 D1 p9 g, A

( G+ G0 F+ N/ _2 n+ oGuido Wischrop提供了下面的代码可以读取IDT的所有256项。/ L% G* v( \, E/ t' F
' l+ A( W- h7 p
UCHAR *mBuffer;
4 s' n2 {$ X& lULONG dummy;: r0 w9 q/ D* W/ F
……
0 H: x3 e9 q7 n_asm
- t' E  R8 g6 r' }+ a6 T/ J{
% B, Z4 `& ~/ s, v, g& }3 Imov esi,mBuffer
8 b6 [4 S* s8 @' w2 I1 r, Qsidt [esi] //load IDTR to *mBuffer
0 X4 T# f6 r0 O* ~' @2 \movzx ecx,word ptr [esi] //load size of IDT to ECX
4 ^. K  P  A5 X6 B9 X6 @1 ^0 }mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX
* N) b" B4 S$ `/ A: a8 v+ q+ N8 Winc ecx
% P* ?+ i! L  X3 g# Lmov edi,mBuffer //mBuffer is the target6 t. i  _0 J( C2 Z
mov dummy,ecx //store size in dummy
- F9 d) H$ Z" u3 _mov esi,ebx //store IDT Base Address to ESI5 y; m4 s$ r& R( g! t) @  z
shr ecx,2
, U+ c9 ?2 i4 B- a+ brep movsd //copy IDT to mBuffer$ {& N2 J3 l2 A( J9 z. \: V5 V
}5 Q$ K5 U/ a; G3 ]# A4 x. X
( I8 ~9 P; n! ^; {7 |9 r
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。
; w; s- v& @! I; `3 }我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
* Y+ G% \0 ~" [/ E2 J(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
8 p; I; E5 N( n# ~% h: w(2) Interrupts---> New
0 T% g: @0 k, \Interrupt Number = 14(或别的) & Edge Triggered & Shared2 D: }) l) t7 h- N7 `0 v0 j+ ?
(3) Listen to Interrupts
. H: z, G, W' S) x如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
1 i2 T. A' l8 P(4) Generate Code; H4 x5 s* L: ^
(5) Build and Run
$ i7 i- ^4 P7 O2 v" G(6) Enable Interrupt" D; c0 W& J% A/ z" i2 Y) ?( f7 o
(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:" J( u( a  A! e. Z! F7 d% P
:intobj
/ u- g7 B# z9 }5 M9 S5 ]" A) sObject Service Service Affinity
# _4 Z( M( A; `. UAddress Vector Address Context IRQL Mode Mask Symbol! Z3 a. F7 A/ Y
FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600# L  a; d) m$ N1 @$ m- w+ ~, O/ @7 R
FD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C
* f. Q$ C$ p) i7 a; z. |0 O& nFD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+20407 k. v$ E8 a% Z2 D  S# G7 i  i
FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2  G8 B2 _# e4 w: ~8 g( p. |3 Q7 U0 Z
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM6 S$ b: A+ p) ^7 e4 p
NTICE: Exit32 PID=70 MOD=ps2_diag8 K5 I1 p7 b# `" k

, i1 m: O: b5 r% |" r$ E# z6 @从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
0 E5 R* I5 s* f5 s; b0 `$ [; x$ R; D9 ^; z; B6 Q2 p: N8 s

0 L- b+ \' d# ?- U" N# t2 u% [, ^3 V+ t2 g5 t5 d2 _
我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
* ^( {7 n/ T6 ]" U
: s8 Q) q' b4 n  @$ S一个问题马上被提出来了
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 20:27 , Processed in 0.314796 second(s), 51 queries .

回顶部