QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:& K4 \" b/ H/ f) \3 `* T
--------------------------------------------------------------------------------
5 j1 U7 d7 ~0 A' m6 i作者:suxm < suxm@nsfocus.com >
3 e/ d0 v" r* U主页:http://www.nsfocus.com, x& B, B$ e. N- @% D4 S
日期:2001-08-13
. c7 u, U* S0 ]. n5 v+ D; F* S+ G
+ }* h  I' _5 R+ R/ a几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。+ o) [$ F- f; }
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。9 y$ U+ g' }& o$ b0 j- q
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。! c9 G2 Q- t, F& ]6 t- \% S+ l
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),8 d; B$ O& N/ S* r4 H

/ z$ i+ j6 Y# E) e. }% \' D( W/ _6 c: F: e

+ j- e; d' E/ b其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
) R  t" p1 H0 I6 c7 x& L- d: M) |Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。# K) u# v) `5 v5 m) m- J% p
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
* X8 q+ p" A2 o- dint51 dw kb_int ;keyboard-handler offset# y) y; K% K4 R% m! {. `
dw kb_sel ;keyboard-handler code selector
! r2 e" i" d" }0 Hdb 0
# T9 Y  }* l3 i1 T, p4 |db 8eh ;386 interrupt-gate
$ I9 ~; J. l; Q, s* Qdw 0 ;offset is in first 64KB of segment, ]# Z. p$ M( M7 _- F& @$ D
是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?( l* W9 J# N5 e3 y& ^. y; H7 [* E
这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。  R1 W6 a) o2 f# o
提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
/ {- i1 Q  V$ z9 K答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。( `2 L  d; D) {$ F0 b7 G3 C2 }
在单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的情况是大不相同 的。9 _& Z& q  F! g' W
Aladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook
% g" P- f$ f; H( {- p; q/ MIRQL + H; ^! o8 F7 R6 a
1 3D 3D" n* b7 w% x+ c6 T- v# g) C
2 41 41& i% l& i; F1 h/ g6 ~
3
% w4 }8 x; d. |  H0 b% i( U! Z4 51 51 51
# j0 {4 p8 {) e( G8 V1 d: n& t5 61 61 61
1 ~9 [( F  l; u2 i: J7 P6 71 71
* {! p7 W$ D# `7 81/82 81/82 810 u: Q+ Y9 H9 z- t1 `
8 91/92 91/92 91/923 y9 Y6 R* ?, T4 R
9 A2 A2 A1
& W! V% k, j% B1 }% K5 z/ [10 B1 B1 B1/B2" a3 v7 w: N* S( U$ I
11
6 d- w4 \7 h0 r, X% v- Z+ u12 3F 6 t! _, `& `8 }3 ?5 E  Q
13 3E 3E 3E 3E
, S. T1 I- M! l& D2 \0 v14$ S, V' ^' n% g9 {+ n
15 3C 3C 3C 3C 3C
- J  ?6 J8 v2 n& R& N' E5 R: q) W  \16 3B 3B 3B7 V3 ^8 X0 y4 z& `: `  Z6 W; N
17 3A 3A
4 O$ |6 U4 n- k9 O/ [! Z+ M0 E18 39 39, a& S. V* C, ^9 u; O
19
$ Q( E, I: R  O20 37 37 37
' p. l1 H% ^+ i- ^21 36 36 36 36 36 361 T  f: t& a. \5 O
22 35 35
  x* k8 l+ f2 q& v23 34 34 34 34 34 34
  J9 W2 J2 \4 X: w24 33: T- S7 J# f2 z3 ^; x
25 . P% I9 S3 h, i  D( ]5 J& b
26 31 31 31 31 31 31
3 `9 _8 ^. Y7 f27 C1 38 C1 38 38 38 38 C1 38
, E  R" }7 W# H7 N$ Z* h4 E28 D1 30 D1 30 30 30 30 D1 30
/ _" h+ c/ @% X6 w2 @29 E1 E1 E1
% c- b, x$ r' [/ H- L0 d9 k2 x30 FE/FD FD/FE FD/FE2 |( {8 X3 C' ^* {, ]2 s
31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 323 n  m! v2 c! s& I
6 B8 C; g1 K2 e4 V4 ~
255 50 50 50
( i2 b# s9 ?! D0 r, A6 WDPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E, V/ }; W# K# f1 w; y
* j* s% d: N$ h0 L& R3 O! |
机器配置:" }: c# b  H' g5 j  V
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
; {0 b' ~5 h5 |$ E; f: Y, NBasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
3 K6 d' U& X, p; I6 O6 n3 H$ hBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
" X4 M2 b' h& T2 U0 k' M) RHugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP14 x! ~1 }. _. J
Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
4 i. P5 p% V& J! ]/ C5 Q( BStat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2, }" o3 p. |  W# Z: J% m
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP4
/ I$ x! A, ^, ~( sSanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3# F' v4 T  D. Z8 W
Notebook - Pentium 200 MHz, NT 4.0 (free), SP32 p7 {" J  T! d7 _$ Y/ @  [, e
! H9 k3 V  d) G; r
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。% j( t- }% H: d1 ^% }
Win2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。0 ]3 {5 p/ B  g" m% r/ A
:idt
) }& Z4 V  G$ w9 [' z7 C) eInt Type Sel:Offset Attributes Symbol/Owner* V/ I3 q3 p/ _. m! R+ ^
IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit5 m. g. a% w$ @9 A1 j: h3 i, O
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
2 S2 U! h9 g1 t$ @* n* p/ m0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E04 [7 v8 ~! Z! w4 s+ E
……
) `0 M3 E3 I, ~7 V" q5 T, e8 G7 f8 m! K00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
8 n7 o% y. T4 G; n( A00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+0924 \& n* b8 i0 ~- _1 Z; U! q& y
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
+ U2 g' }) W  r3 E/ a. }$ t/ g从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
3 |9 N6 T8 p" k, f# [在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。3 \7 C4 d: N, W4 a- X* c# W

* z% E8 R$ w; ~' M7 {; ]6 f8 z; u9 Y8 H6 _9 C+ ?4 s

) ^" A/ t& D( T8 I$ b提问:IDT表的Base Address怎样得到的呢?
/ J: F" r7 d9 r& W% t# R9 S答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
/ s4 ]1 n; A3 W! A) B4 h2 Ahttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
! w% k6 D8 ^3 ySIDT - Store Interrupt Descriptor Table Register
% L! \! J  x; U  M* ~0 z+ B9 z1 v, z, V2 y7 v8 o9 n& G, c
Guido Wischrop提供了下面的代码可以读取IDT的所有256项。
7 ?7 `  W: }! B1 z' }3 K: U% s& V9 Z# H, [6 H
UCHAR *mBuffer;
  \/ H- L+ L; LULONG dummy;
( p- O: a6 T3 T4 }……
$ {) u: K! M/ X_asm* ]4 z( s0 F: _. D
{/ r) `; k  s+ R- O* b7 P0 q; y
mov esi,mBuffer 2 ]/ r3 M$ s; p3 z1 G) @% \
sidt [esi] //load IDTR to *mBuffer, G% E- X6 n. B6 V, Q) t
movzx ecx,word ptr [esi] //load size of IDT to ECX
1 R. w8 i- r9 D. }mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX4 j2 ~, {( F* Q1 |
inc ecx
: D! S7 d- g* H1 v1 k7 |# gmov edi,mBuffer //mBuffer is the target& n" Q) L  |# }
mov dummy,ecx //store size in dummy( R3 N. E( O9 I. l; Q8 N
mov esi,ebx //store IDT Base Address to ESI
( V' T7 U' R" @6 eshr ecx,2
4 Q' g6 M# U% h& W. h4 Prep movsd //copy IDT to mBuffer
& V% p- A2 Z4 R: Q( L2 Y. R; w}
& X% }3 [* K+ h; M1 @5 _- z' v5 G. Y& G# l0 Q
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。, b" v' B) F* s
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
* z6 z5 @: R) P' e" K: n5 F% k(1) Windriver---> Driver Wizard---->New Project----->ISA CARD. w& W5 I$ s( n9 \
(2) Interrupts---> New6 \; j2 H7 m9 e5 ^& l
Interrupt Number = 14(或别的) & Edge Triggered & Shared
: _# |9 F6 G4 h5 {% K+ ?+ J(3) Listen to Interrupts, ^0 K; l+ o) K6 X5 }" n
如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
$ m2 P5 X2 P% {6 Y, p' O(4) Generate Code
' v1 i% M- O) U( z(5) Build and Run
% `# k" m% h9 W, }- u(6) Enable Interrupt6 n( I, V: o; C
(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:
2 L9 U- F! s/ r; J; q6 N:intobj
' d9 A5 G3 i  ?Object Service Service Affinity
) o4 C* v: q1 \! i' bAddress Vector Address Context IRQL Mode Mask Symbol
9 a4 O6 H$ J" xFD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+16006 n4 i4 ]4 m. r7 \! C
FD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C- W7 h% x) }0 S1 u5 q
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
% W4 C3 M  v" f0 r' R$ LFD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2: W% x% t9 I! e
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
# d( c! U( X  H; a, q' {- a' _4 QNTICE: Exit32 PID=70 MOD=ps2_diag
9 _6 s% l/ a0 q: |) Y9 I* T% t" p7 q2 T) H
从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
# n* Q# \0 v9 i- u# i, W1 f" O& b8 w$ s+ @$ [  _

# o: S0 @( ]+ a7 O- p5 v
# e5 u: g+ @- H$ p$ ?! H我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
1 U7 a) i! h3 p* B  p" \; k' |1 v+ p  {0 I" h5 Y' @* d; r0 ^
一个问题马上被提出来了
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 09:26 , Processed in 0.604399 second(s), 51 queries .

回顶部