QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:29 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:7 G3 h+ j- H8 @
--------------------------------------------------------------------------------: j, b2 {, \# t$ h8 I
作者:suxm < suxm@nsfocus.com >
! q& z- @# F; ?0 W8 m% b( N: y5 H主页:http://www.nsfocus.com/ i* c& n4 o! {# }3 H+ K% _
日期:2001-08-134 v5 L. M/ B2 _0 G  O

2 \( F3 k/ _) h2 s( c几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。' C& b9 x5 |! P& Y7 V( a+ `
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。% a/ d; J: w8 C. G
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。
/ r- y( b2 T1 U) aWin9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),4 l4 L' F' e8 R
- k- M1 _% K6 I6 H, T

" _( s8 J2 Y+ p7 g
+ B+ R8 n7 K2 n8 s  T) R其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。- `: H% q' R; H* j) q9 T, Y
Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。, w: V" t5 s' {3 z
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
! h5 r7 @4 i& z8 }3 Nint51 dw kb_int ;keyboard-handler offset0 v) _. u7 y: J/ R, o7 A' e
dw kb_sel ;keyboard-handler code selector
! G% O' B  s' F+ k0 i4 L& v  Zdb 0 & o$ O1 q6 d' o4 D, ]8 _' }+ V6 f/ P
db 8eh ;386 interrupt-gate1 _. `7 B: a2 T1 X0 D8 S; `" d
dw 0 ;offset is in first 64KB of segment; ]2 y/ ?: v5 L; O: u& Q
是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
( b4 l. \. }+ \/ g, }这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。+ Y2 L2 N/ b5 Y2 x
提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
& T6 ]% J. a( @3 O  C答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。
7 p, H* S, a1 M在单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的情况是大不相同 的。
- ?( r: ?/ S* z$ uAladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook7 t4 A8 G8 t3 y5 I+ R
IRQL
0 l8 K; r" P0 |" N8 g6 S1 3D 3D8 w' a1 L1 B$ S8 j4 @
2 41 41
- D, x: f% \7 J1 c# d/ W3* m( R' r4 H( M. ?, @* d& @. _
4 51 51 51
4 x1 v8 a1 g" I3 D8 L! w5 61 61 61
) v( W+ T' A; V$ X, J6 71 71
. h9 e4 q0 F5 W# w& S) j- Y' O$ o: l7 81/82 81/82 81" H' b- L$ P. d' Q7 Y
8 91/92 91/92 91/92
" |5 o  T: d& d: `# b  F3 k, ^9 A2 A2 A15 A. _6 ~: k" R1 n/ W1 b  d; r8 @
10 B1 B1 B1/B2
; ]" j3 W4 F' n. T% \11
% N* A8 u9 }; ?" ]8 n12 3F ( X, L* k. h4 Q& o5 D  W$ |0 x/ I
13 3E 3E 3E 3E
9 g# Q9 m' B- H( ]140 ?  x& s  F( y8 E% ~
15 3C 3C 3C 3C 3C( @: Z7 l1 X  h9 @
16 3B 3B 3B
, }; X9 d* ~! T17 3A 3A
6 F7 C4 m) G7 h( [# f1 j18 39 39
: p" ?' I8 u/ s( y! Q$ q/ x19
9 u2 F) j! T# Z. [20 37 37 37" k* ^5 \: z+ O, a) M
21 36 36 36 36 36 36
. w* k/ M2 D$ ?5 v5 s8 G22 35 35) w9 c* a. S% ^9 u  s+ y
23 34 34 34 34 34 34) y7 p5 s; e3 t7 c
24 33" F5 l( N  E- r( `; N5 D% i5 [$ h/ p
25
% X0 Y1 V8 z% D- C$ [26 31 31 31 31 31 31
; k6 U, k8 \; |. `' T27 C1 38 C1 38 38 38 38 C1 38: i* {; Z- [3 m/ I* o4 W
28 D1 30 D1 30 30 30 30 D1 30
1 A5 X8 O: `; u& W; N& F29 E1 E1 E1
/ [2 @7 X9 w6 ]/ e30 FE/FD FD/FE FD/FE& R& e1 ?* C: _1 [
31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 323 |; U1 s% o3 Q2 J

: K% ~3 e7 I- H/ T- s# u0 r255 50 50 501 c" |9 Z2 K% n; W
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E# S2 D9 {/ G4 E$ r' g# w+ H

" ]( L0 e$ B8 |. ~; ?0 X机器配置:& A& N* l- x6 D
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
. }- ^' O" L& I5 U* w0 }9 |BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
# m6 |9 w- H$ ~* k9 y: I0 DBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP38 ], E6 R% B" w* l' v  y
Hugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
9 V3 _8 K' V$ W8 oStat_02 - Pentium 166 MHz, NT 4.0 (free) SP33 M4 Z1 h3 a& u; V4 ?
Stat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2
3 V9 I8 ]) T0 w, `' eOTTO - Pentium II 300 MHz, NT 4.0 (free) SP4! y7 k3 O7 u* f$ a
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
) ?" {9 U/ I4 R, Z( N( o  ?  {Notebook - Pentium 200 MHz, NT 4.0 (free), SP3
+ }& @1 l4 [7 M3 K) Q9 A: e( w4 |  [' j0 ~, i! n1 G
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
, f: G4 H% e& N% CWin2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。7 G  K$ {0 E5 F% r% j1 P! Q. r
:idt
% C& S# _+ R# \" Y) t. V3 m: R, IInt Type Sel:Offset Attributes Symbol/Owner
3 n: v' u% J+ T' KIDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit1 H/ x% ]9 ]) I4 g. ~* b
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
7 @  b0 }! ^- N4 E0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0
/ b; o9 W) N, P* A4 V! j……) A* J. X& {1 K: D, m
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
, z! u9 }, ?6 Q( K8 ^, [6 |$ M; e; o! Q) @00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+0924 y4 ~: ^: O( }* W, h% r" \3 p1 g2 v
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
1 o, z; Z! @# K" j* Q% D1 y$ n从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
  C% F* @  n3 L8 {& F在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。& Y$ }  h$ i, I& G& S! |1 A

6 h& y1 _) v* Y! [: `6 x/ A+ T0 a8 z" u& Q  B) c
8 w6 d2 _. f7 i) t+ u  q' g0 q9 x; ^
提问:IDT表的Base Address怎样得到的呢?9 f$ b% i" T; {. i3 _
答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
, h# K- @3 w: `* x0 @# c# Vhttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
9 p) d. s$ ?( M* E( Y. ~SIDT - Store Interrupt Descriptor Table Register
. h$ c" c. C4 n) K2 S& I
2 J$ a- T7 D2 rGuido Wischrop提供了下面的代码可以读取IDT的所有256项。
! Y: I& I( s9 q5 a9 P
! w; g9 Z$ o( }. o; mUCHAR *mBuffer;" V3 f% i  A# z
ULONG dummy;
% D: b" d  k2 A& U……2 _' d8 ^% A7 w6 U5 ]( i, _
_asm
8 Z3 t! O  P0 c/ B$ _' P0 ]( K{
3 H/ ~+ d- a" n% O# cmov esi,mBuffer " p: k; i1 t2 A
sidt [esi] //load IDTR to *mBuffer. u0 T3 n5 e  l( e4 h* V& a( T
movzx ecx,word ptr [esi] //load size of IDT to ECX) k7 B& X  O" T) v. ^
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX. _+ ]6 {7 [3 ]( @9 V$ d3 v
inc ecx
0 z6 B* W& K7 b5 Dmov edi,mBuffer //mBuffer is the target0 l2 M" J2 _5 k4 f0 j
mov dummy,ecx //store size in dummy
; u: ?3 @+ V7 {4 [& k/ kmov esi,ebx //store IDT Base Address to ESI2 U9 q8 W# Z6 m, g5 i. j
shr ecx,2 0 M! d" P. f  y4 c" t
rep movsd //copy IDT to mBuffer0 y/ R6 W0 C( W. \* o1 ], f7 U
}/ @& C0 X( b$ @9 Q2 |0 l
$ ^" L+ v, P- T4 W) V5 f
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。
8 J3 u6 |4 n9 @  p5 e/ O4 Y9 p% z我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
9 q& z" @6 I% K3 |(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
- |" B0 h$ \/ Q: M, h8 Q+ c, l9 I4 \(2) Interrupts---> New: C4 A2 @- W3 Y
Interrupt Number = 14(或别的) & Edge Triggered & Shared; v7 e2 n4 G$ D
(3) Listen to Interrupts
% }% E0 {0 o) X+ e7 H. e6 u如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。( a/ P+ ]$ v5 ~$ d
(4) Generate Code
* B1 `, ]  `. F- o(5) Build and Run% }% |0 c9 K$ ^+ m3 u8 {
(6) Enable Interrupt
1 m/ b! m, {0 S9 b) q9 }(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:- v+ D: a( |7 p6 G
:intobj0 q, s! n' ]" Z1 m; j
Object Service Service Affinity+ A" `) ~# h$ U2 C  b( K( q
Address Vector Address Context IRQL Mode Mask Symbol
5 ?* n: A8 z- A$ k3 [FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
% @) I4 ^8 y! |- [, d5 i6 S, KFD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C" o5 H" e: e& S0 A
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
$ t6 Y3 x1 B2 u9 EFD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2
! q) W/ _9 Y8 g- I. e  lFD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
" B3 n- t3 Q4 K4 |NTICE: Exit32 PID=70 MOD=ps2_diag
7 \- e1 O3 J/ `) T7 @1 ^
/ u- D0 j  n$ \, z! g# J* v9 _从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
5 \6 W, @" b; q) A& z
( y6 ^+ G1 K; ?- n/ L4 [* j2 Y* u# T
- W/ \$ T. K* [3 b1 ^# o
我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
/ b% M' V% e' K
# Z. m% q. G1 Z. J1 Q6 }一个问题马上被提出来了
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-18 19:25 , Processed in 0.330641 second(s), 52 queries .

回顶部