QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:
$ j/ t; T4 {9 O+ v$ r8 q( _1 x  C--------------------------------------------------------------------------------+ Y$ `$ ]' {4 l, Z
作者:suxm < suxm@nsfocus.com >
9 a* J. y: V8 I, [主页:http://www.nsfocus.com1 Q6 E- P3 l3 y, I" [8 }
日期:2001-08-13
- T6 l* V3 m. K* J: z
+ g* }! h/ {! J+ O; B! H5 m$ v几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。
/ q8 ?) {  D8 y迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。, @- O$ K7 j# n7 m1 t* x4 ^/ O
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。
  E5 K3 K3 P! G# n; ]+ L2 |Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),
) ^# c' ?* o; ?) y8 Y2 F5 |9 b8 V; A: O0 g

7 `9 m8 c: i" x) V/ d4 y9 i! i( Y# ]
其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
+ N& v) U; I6 D, @) S0 X; K. wTrap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。9 }. e  [7 b1 v
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):+ F2 i* g- s( Q5 {9 j
int51 dw kb_int ;keyboard-handler offset8 ~0 n, ?$ l, x8 h  Q
dw kb_sel ;keyboard-handler code selector
4 n2 F5 s0 Z: Y4 Ydb 0 - H: Y+ ^( p) E
db 8eh ;386 interrupt-gate/ @( [% k* G6 F1 p' ]
dw 0 ;offset is in first 64KB of segment, R) m' u8 d/ m4 j8 f
是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?1 G3 g6 O+ A& m- t( B
这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
# |) q% @- k( k. w0 k6 a8 L  ]提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
8 }7 v! k* W0 C& `) [6 W答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。
( h. O% A& D! N% D; D. r在单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的情况是大不相同 的。1 v6 ^4 {- ?. Z/ L8 c
Aladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook, J% F! C; J# g/ m: Q# e' ~4 c# H
IRQL 9 u8 p: [* k! Q1 y1 A- ]
1 3D 3D
1 H# k: k; g2 a  b( `2 41 41
4 M! C; O; \. E* g0 Y7 s3- W! x. p( e9 o0 }
4 51 51 51
4 g' L  ^8 j9 e& x! Z0 Q5 61 61 61
; X  S, v$ e& X$ R) u( K% P& Y6 71 716 w9 j/ r5 `$ O% S+ ?: ?
7 81/82 81/82 81
5 U' q/ J3 _4 D8 91/92 91/92 91/92
) T" v4 h: D" N! P! w9 A2 A2 A1
* r. Q6 q' W& A3 `# I$ ^2 X/ e10 B1 B1 B1/B2
4 C9 f  [/ {' `* i' t% G11  ?' t, M+ p/ X2 b
12 3F
& r# Z; z5 {' S13 3E 3E 3E 3E
# v$ O/ z1 q$ ?+ m14
& K5 D% _" U" |$ M& G; A8 r15 3C 3C 3C 3C 3C6 A7 j; ~; Q. z4 k0 p9 F5 R) A
16 3B 3B 3B) l, U9 ^6 K: F4 L
17 3A 3A
+ B) x: q3 y( @1 c3 [! f18 39 39
. C. R9 ?7 }4 P6 J" e& d199 }9 X" F* [1 g1 @4 Q( L( F
20 37 37 37# y8 r! e" ~; y. U: L$ H
21 36 36 36 36 36 36  w% y# W1 Q  v0 J
22 35 35' e7 T+ s% i$ ], M' B
23 34 34 34 34 34 344 M* w  k3 a  P
24 33$ _6 B. x* p) E" @' Z
25 6 [* I; g. v$ B& g. W8 P
26 31 31 31 31 31 31
; [1 S: p$ l7 r# z! \" x" x5 l27 C1 38 C1 38 38 38 38 C1 38# ?6 L- ]; L7 f2 ?# v/ _2 y
28 D1 30 D1 30 30 30 30 D1 30
# B1 E2 q9 @3 g5 D+ {! E29 E1 E1 E1
6 ]+ d, }! f' H4 i5 L! R30 FE/FD FD/FE FD/FE
, i' P3 p) z+ P& c31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32. L$ T' q1 ]& X( r

8 g' {) n$ v! f7 u; ]255 50 50 505 |. F9 D- e  a* r/ n  M0 t
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E
" x' o- _4 i7 z' Q# V
  a3 y& w# Y3 }机器配置:# i0 o0 r6 D0 ~% \7 Z
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
" n8 A: z6 x- r6 g" ^BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
2 U7 }( b/ i8 Q. E: WBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
& [* B2 Y8 ^2 D* DHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1( m2 k  O4 j/ C( h0 |9 Z9 n
Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
) p. b! P1 i5 y% y" aStat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2
1 _7 u5 y6 f3 xOTTO - Pentium II 300 MHz, NT 4.0 (free) SP46 y6 ?8 S) G5 a7 q' t
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
$ ~- x0 g5 R: u8 j- r5 ENotebook - Pentium 200 MHz, NT 4.0 (free), SP3
* L( n: N. h9 e; p- X
! x  e9 v3 z" ?5 b& j1 u/ U1 a在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。6 |1 P/ i, h, f9 \. v9 |
Win2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。
& v6 }4 r6 W; A+ _" @- o:idt
8 U5 {+ Q4 D" W6 `9 q# W1 |6 E- gInt Type Sel:Offset Attributes Symbol/Owner
- e+ M5 R/ {7 B5 H" dIDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit5 V  Q, \6 ~- L; y
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590' Q* P, g( F; T! a# i- g! B
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0
! b8 l) G) i9 N: Z; G+ g1 O……
% ^1 Y, w6 D4 h6 e! n+ U9 S' b00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092- l% w* w- V3 d9 ?6 N3 x9 S
00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
. T: A, [8 ~5 j  l0 B4 t0 e8 _( X00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
  p6 p: P0 [' \7 O5 v从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
1 I& P9 z4 l& P7 r在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。
5 t( T0 g! D7 c
+ B4 j- f+ ]1 ^' K- v8 t/ P
7 M/ ?$ l4 S/ }" K- V1 `' P# i$ ?- A4 G* c, E9 [! Z
提问:IDT表的Base Address怎样得到的呢?
9 R; k2 H. j9 H0 Q$ \6 M答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下/ J8 B" G$ n% B5 W2 x/ _; L$ V
http://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
7 }  f4 V  h/ H- s9 RSIDT - Store Interrupt Descriptor Table Register
1 a0 Y9 [  d2 ]( A2 Y( Q( \6 C/ {' Y2 N! {5 l
Guido Wischrop提供了下面的代码可以读取IDT的所有256项。
- q1 w2 |, ?* O) l- a4 d' C  V& T* M0 g
UCHAR *mBuffer;8 M* t* H& d* S9 B( {
ULONG dummy;) t# ^" _$ X, V- o
……) L  D& ]7 e) T6 ~
_asm" _) i, a( h0 l
{4 F, E$ a9 [9 e$ E
mov esi,mBuffer : `& `: s2 |) V) R
sidt [esi] //load IDTR to *mBuffer
" P' c0 s! w8 r# B& T4 Umovzx ecx,word ptr [esi] //load size of IDT to ECX
) r& a4 Q: [. h" v: \2 j8 Jmov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX
; A. y& i/ r3 Z& O0 b% winc ecx
# _' b8 ~9 g1 C8 w0 M$ N2 h! Emov edi,mBuffer //mBuffer is the target9 B# p% n, i" T, l4 a; @
mov dummy,ecx //store size in dummy$ ^7 w! E  Z$ Q* c4 [
mov esi,ebx //store IDT Base Address to ESI# |# i/ e4 e( M% v
shr ecx,2 % [8 @2 B3 E8 S7 A
rep movsd //copy IDT to mBuffer
. W8 G# ~$ X* G" V  d8 P: t}& m7 |0 ~3 \: l, |! I6 |

) H, [$ b6 \! Z8 C  C4 N; T5 j这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。1 K4 F& P1 E3 W0 o2 C0 o
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
9 m, X: W8 R( k& o(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
& j% v  z& F8 A! Q1 ]+ G  a(2) Interrupts---> New+ E# `4 j3 ^$ e3 W
Interrupt Number = 14(或别的) & Edge Triggered & Shared. W; e% X% u( N: t! K
(3) Listen to Interrupts9 T7 ?2 y$ R4 x* g
如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
% z: M! p. K( o$ E) o1 \" `(4) Generate Code
0 A. O. I9 B& K4 ?. l3 R(5) Build and Run
9 F2 K: j% ~) S4 _/ |7 q: F(6) Enable Interrupt
3 L* B8 O( F1 R/ |1 O( g" e(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:; T2 z. L" a) w% v7 `! k
:intobj. V2 j8 j9 {0 C& V) P  B
Object Service Service Affinity
  k$ E+ k- w: kAddress Vector Address Context IRQL Mode Mask Symbol
. D3 A* d: Z0 G( [9 ^FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+16002 o6 Q# T5 F9 s3 N8 U- \
FD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C& D. d8 p' H! n2 s& Q# V" Q
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040, J& \; f0 K; E# l7 V( P* D
FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2
# _" S4 w+ V, m( ]0 N( A  HFD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
* d5 Q8 X/ K8 X; W  H) A7 Z) ?  INTICE: Exit32 PID=70 MOD=ps2_diag% |/ @* L- O3 @" h0 p2 y7 E

% f& q" R' ^% w9 S8 w8 U从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
8 _; V8 n- i9 E8 X7 p0 n7 u! q% d4 n3 E# g6 {9 q, r1 G) `
& h- T5 C% _% I8 Q

( a- s( u! p  b& V  k我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
! L& p- C; ]9 s" P8 I
4 }* j; S" H( R0 T5 j4 ?一个问题马上被提出来了
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-20 04:44 , Processed in 0.391202 second(s), 52 queries .

回顶部