QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:
" n8 }/ l2 Q: C0 k6 U- m$ E--------------------------------------------------------------------------------: s% C6 {1 i; n8 t+ h# |; D
作者:suxm < suxm@nsfocus.com >
0 h. ]6 e8 S2 N7 l主页:http://www.nsfocus.com0 j" J4 _) r2 b# p6 D1 i
日期:2001-08-13
5 u4 N  W5 V1 B9 D2 w1 ^4 c4 u5 m9 D% T3 U0 e8 H: |
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。; l- S6 @$ D7 ^
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。
$ N  \' C  @& v: U6 _让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。( Q1 h& K. `& C+ J' I# B
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),9 X- `4 X; D* y5 V. k* T

' S  P8 B! ~4 G8 G  d* H6 |7 H3 a$ ]- k/ |1 m4 S

) {5 ]. T5 t/ g. ]其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
0 [* \" J/ W; j5 U) D$ e2 L1 D) fTrap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。7 k1 i6 }! O, e$ l' u
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):, G4 B) I, j9 r) Y1 U
int51 dw kb_int ;keyboard-handler offset
- v/ q  w+ g# ldw kb_sel ;keyboard-handler code selector  x0 c" ]# S! {/ K# n6 c! {
db 0
2 ]* r2 c+ w  D1 C* Bdb 8eh ;386 interrupt-gate
( ^5 I9 K' B! p1 Ydw 0 ;offset is in first 64KB of segment
' ^1 G, k7 r2 i4 u: r2 l* C是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
& m, Z3 Y% X+ ~这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。) y+ K# u1 E; _
提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
/ V, k# r4 R; Z7 u8 G& X; A' k2 O答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。; i7 n" l/ d/ 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的情况是大不相同 的。
) ]2 q5 a* Y$ hAladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook8 e" W/ X' p) x8 _
IRQL : `* o; \4 C6 W) y7 ^4 E
1 3D 3D5 I* o- P- o* \+ r  x
2 41 41. P  E( r2 H& z; m% g" Y
3
* u' D, ~7 j  a3 C- {# c# @, r' s4 51 51 51
$ K! X- J2 a; u/ r8 f: _5 61 61 619 E1 i& @% g) x
6 71 71
1 P; ^$ m' K1 _0 J; Q# K7 81/82 81/82 81
$ ~2 b; w% o) S* }2 l$ y$ B8 91/92 91/92 91/92
/ X8 u; e( c% h9 A2 A2 A1* h) ^7 V7 l7 _  I& \
10 B1 B1 B1/B2
# e7 B& t( x4 S11
+ g1 J8 d% K6 I- b8 W12 3F 2 t( Z( z  T  |% ]
13 3E 3E 3E 3E
( ?1 p4 `! p1 ~3 D, F. x# d14, g4 X) x! }' Q
15 3C 3C 3C 3C 3C2 Z" p4 {* }# @8 M# g
16 3B 3B 3B" z$ `8 h- z" y3 Q5 Y6 ~8 F
17 3A 3A
! m) b- U4 P& p8 e! b18 39 39# A* i/ G: _4 \: V( O
19* v* n. ~( x7 w, @
20 37 37 37
9 o4 ~' Q- y$ |, c. ]21 36 36 36 36 36 36
. c: p3 q- ^- g: r# f# [( g/ e9 }1 j22 35 359 q, W* x+ }& d- ~
23 34 34 34 34 34 343 j! m( x3 |; a0 L2 i2 \& D1 j
24 334 I9 ]1 \& O: h$ K1 f- H
25
2 E1 G3 D! I% W+ ~- t, s! x26 31 31 31 31 31 31
1 W& B. P- W2 z27 C1 38 C1 38 38 38 38 C1 38
* t/ Z/ p/ E3 [  N1 D, }. `( s28 D1 30 D1 30 30 30 30 D1 30
7 a5 |7 j3 S% m: s1 Q, g0 Y29 E1 E1 E1/ p% h0 Z3 g( z6 d8 B
30 FE/FD FD/FE FD/FE
" P; Q8 F- ^' a8 W1 {- t# V7 l( N! M31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32& |9 ~- F0 Q$ H9 Q+ K
. v! K* p. r! \8 A, E
255 50 50 50
% s6 @" N& ~$ {DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E
! L3 P* p. D8 |/ L, Y
1 x9 E+ F) R! r' Z- G机器配置:
9 Z6 e8 j* h9 O, }5 ?/ hALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3* e3 h' q2 _7 K2 C
BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3) j3 T, e- R3 S7 y9 Z# o* Y" D
BIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3; ?9 m: z: h# D. J; U3 w2 L% k
Hugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
" x3 v; L0 I3 e/ w! cStat_02 - Pentium 166 MHz, NT 4.0 (free) SP3* a3 Z  |& u  W) ]
Stat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2$ v% H% n+ z/ V6 U7 K  y. R6 l
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP4; m8 B" C0 {8 G
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
& Y$ [$ E! j4 z/ a5 VNotebook - Pentium 200 MHz, NT 4.0 (free), SP3, C9 b" D) D( p5 M% s+ ^( B- d
" h/ S6 P9 a  {) J
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。# z% V  w. p6 [3 c0 B4 q- [0 e
Win2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。, U+ c! q4 Q- R8 ]  _; |
:idt
9 h1 n0 M6 f( e+ m2 E$ |Int Type Sel:Offset Attributes Symbol/Owner5 P" x5 C  r* p% c& ]
IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit! p! C/ g3 G" E& e" w
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590- J' q, p3 @" H% o  x) W/ E
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0/ C! x  S6 f, s6 c
……# X% C! f* p$ G4 b  i" [0 H
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092+ ~! i1 Y" |3 a0 s  L/ `3 G" O& H
00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
4 p  B6 Y! I) T  @! \00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093( T+ p! O1 @' B: c
从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。) x$ Z. {8 }3 [. Z6 L
在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。" j; }6 A, N" w/ [$ ^6 Z

' n9 g( j" z/ D' f: v; K0 M& Y! Z. A0 k2 T0 k) Q3 k# S8 r/ w$ b
' e+ P9 t  P5 \9 s" z# i
提问:IDT表的Base Address怎样得到的呢?
  V# S% i% m+ Q& O7 F0 G答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下$ ]# t3 K( x# ?2 g/ U; t; P  B
http://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
7 s5 d$ \7 I+ [( M* W( |& xSIDT - Store Interrupt Descriptor Table Register# }# a7 t( x3 T& [& a% w& p

/ A; {9 l# F, o- [, z* u3 zGuido Wischrop提供了下面的代码可以读取IDT的所有256项。
3 k& W, b8 O8 W6 F. K* {+ w% q: H; ?  }9 Q2 H9 H, P
UCHAR *mBuffer;+ ]; G1 t! _$ c7 S# K+ R1 }' ^+ X
ULONG dummy;% r: ?4 h0 d. U$ A. A, c# B
……
% H& v' [$ D$ N6 U& l_asm
2 J9 Z% K; L: q) U. E' F{
) `2 E6 v' h3 H  p3 O: v  e  Pmov esi,mBuffer
1 `1 V. [* P' j: v! Isidt [esi] //load IDTR to *mBuffer; O# I; V& B# }: ?. M
movzx ecx,word ptr [esi] //load size of IDT to ECX& a! x' i9 @8 @3 l- @/ X
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX$ a% ?6 Q, i# I) }, ~  _; E$ }
inc ecx
* U, K, P* Q' v- l( ^( S3 Wmov edi,mBuffer //mBuffer is the target
: j: U+ _& ^7 q' tmov dummy,ecx //store size in dummy
  I6 Z  T$ _) `3 _. j# Q' Dmov esi,ebx //store IDT Base Address to ESI
( C- E  C2 Q2 m1 sshr ecx,2 7 V3 v& f5 J8 d
rep movsd //copy IDT to mBuffer7 }, V5 B) S7 I; E4 e; e
}
) u$ k0 V! x+ J# A
) l3 j% B  m& S这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。
) T8 \5 `9 {2 l. |% R. w& }我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。7 Z2 S. t( [7 U& _* A4 G( M
(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
" k; ], ~( |% z5 |0 l3 W(2) Interrupts---> New
, l7 c# k3 i- A; ?1 U) a. [! BInterrupt Number = 14(或别的) & Edge Triggered & Shared
. h  V3 V. `/ A# ~7 f(3) Listen to Interrupts
" _3 S8 U1 D- k5 b* \4 }如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
* _/ D8 Z. E& I- ?3 g(4) Generate Code2 T$ P6 E5 J6 ^2 ]& ^, Q
(5) Build and Run$ x  D% m+ o1 ?
(6) Enable Interrupt% B3 O7 E9 ^4 d( T' K
(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:
* F6 G& O5 T) v, a:intobj
9 A/ g. a- k, G/ t: z1 g! pObject Service Service Affinity. s& R) f8 A/ Y1 |9 p; U
Address Vector Address Context IRQL Mode Mask Symbol
2 m9 a- x) p. G0 Q3 o# @FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600- [% j  g. Q; z, ]( l( R7 d$ ]; B4 {
FD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C0 w8 z8 y1 W5 t# \2 K& o
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
0 |3 K! y4 w0 i4 r2 w$ ]" {FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE21 l4 U! F0 K2 E7 F
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM* H- u+ M" W* M5 z- F( [2 F
NTICE: Exit32 PID=70 MOD=ps2_diag& t( T  S, C; G0 R, F

" ]" V2 v4 [& v9 U2 W, ^2 K* z从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
- x+ m& |$ B3 v  Z$ `
, G, g, U! [# t% [2 }7 y8 [6 f' c& R" b- M% }. v, v6 K) [
2 c1 s$ `% O6 _* h
我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
, G+ s+ m: ^  M5 _; B& D1 i6 A8 S; ?8 B* Y7 {  H
一个问题马上被提出来了
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 19:15 , Processed in 0.697845 second(s), 52 queries .

回顶部