QQ登录

只需要一步,快速开始

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

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

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-9 14:30 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
文章内容:
  W2 B) F8 ?+ |# G% W& z, {8 l--------------------------------------------------------------------------------
' b; ^2 p7 a1 v9 `5 S4 W( |作者:suxm < suxm@nsfocus.com >3 d& h) G: W3 Q/ P
主页:http://www.nsfocus.com  i+ Q1 R6 W& K' j4 O
日期:2001-09-10
$ E! C+ O  w' l$ Q2 s5 p5 ~# D, t3 Y
<<接上期>>
3 D1 n) N% ?! G* r( g+ T, s1 ?
& o2 S' y& u! M, @IDT是定义硬件中断映射的表,当硬件中断发生的时候,CPU会直接把控制权交到IDT的相应ISR中去运行,根本不去关心是否有Kernel Interrupt Object(CPU根本不知道Kernel Interrupt Object是什么)。- \5 x( ?0 j4 o% W- Y" m' R& P

  o4 N- x. _' j' D- ^[ 读者小强:啊???!!!想不到Interrupt Object这么不重要???那Interrupt Object在中断发生的过程中扮演着什么角色呢?]
( j& D# K8 H% ^& @& d) W呵呵,别忙,Interrupt Object还是很重要的。当你调用IoConnectInterrupt()的时候,Kernel会构造Interrupt Object. 然后Kernel把Interrupt Object的地址放到IDT的相应表项中。这就是说,当中断发生的时候,CPU会把控制权交到IDT相应表项所对应的ISR中,而这个ISR,就 是Interrupt Object中的代码。现在明白了吧?我们可以这样理解,中断发生的时候,相应的Interrupt Object被调用。
2 e5 e, m/ U) G2 Q# E7 m+ Z& G0 M6 k4 a下面我们将要演练一下如何在NT下hook系统中断,以使读者对以上基础知识理解得更加深刻。
2 I+ |) L& v+ G6 D7 V" {$ `在开始激动人心的练习之前,我们有必要再强调一下上面的几个概念:Trap/Interrupt gate描述符、IDTR、Interrupt Object。' o( O/ {. A# d/ a5 O1 w. g
通过sidt这条汇编指令,可以获得IDTR的内容,由此,可以得到IDT的Base Address(基址)和Limit(最大的长度限制)。一旦得到IDT 的Base Address,我们就可以找到想要hook的中断号,然后@#@!$!@$@#$@#%$^$……,对不起,刚才晕倒了,太激动了。然后,我们改变 那个我们想要替换的IDT表项的Code Segment Selector和Offset,当然,别忘了备份好被替换的Code Segment Selector和Offset。并要确保新 的中断处理函数能正常调用原来的中断处理函数(这就相当于把新的中断处理函数插在了原中断处理函数之前,但是不影响原中断处理函 数的使用)。3 G$ X1 e3 K! u/ W
[ 读者小强:什么是IDT表项的Code Segment Selector和Offset呀?]
0 x( ?4 V# \, Z1 j0 P0 a& ]+ J[ suxm: 去看看上一期月刊的图1 ]
3 ~$ q( P6 ~1 I8 h; E# }下面这些代码出自《Undocumented WindowsNT》,实现上述“搜索IDT、替换并备份IDT表项”的功能。
: [& ^4 T5 u1 S& ]6 x7 |+ Y- a7 J6 A
/* 在Winnt和Win2k下,RTC时钟中断被映射到IDT的第0x38项 */8 V" s) ?  n% i$ D- [3 M) C
#define HOOKINT 0x380 ?' P$ p- s& m6 P
NTSTATUS DriverSpecificInitialization( )
# f- j* k2 W5 T) J{4 w2 q+ ]0 D- G4 L  r& g8 {
PIdtEntry_t IdtEntry;
4 k: W0 m$ _6 M: Z" Q% b! [- Wextern PServiceDescriptorTableEntry_t KeServiceDescriptorTable;
7 [$ n3 o& c$ {5 V- r& U5 J% a2 E5 V7 o: t, u, J; w
NumberOfServices = KeServiceDescriptorTable->NumberOfServices;
3 V4 a( x: |, \9 E; }$ KServiceCounterTableSize = (NumberOfServices+1)*sizeof(int);, |- H/ l8 a& e) M
ServiceCounterTable = ExAllocatePool(PagedPool, ServiceCounterTableSize);
& `8 O+ r8 E+ s, y# j( d" z/ k9 Z+ a- M: s7 o
/* 有必要检查一下,有时候内存不足会导致ExAllocatePool返回NULL */. F3 V4 ~5 h) ?. F
if (!ServiceCounterTable): w$ n. u' j' n6 Q# {& ^4 q2 l
return STATUS_INSUFFICIENT_RESOURCES;
6 |: |1 O+ w+ w9 X4 k
( b: f/ Q* u- u! l$ N4 Zmemset(ServiceCounterTable, 0, ServiceCounterTableSize);5 u6 J- s0 q# B. p. R, J' a0 t
*ServiceCounterTable=NumberOfServices;$ Z  T/ N% T' @# x: Y4 O" Q

( K5 v- @. s) ~& y$ v% P/* 获得IDTR Register 的Base Address和Limit*// Z( U- _0 t8 Z1 I" i0 R* V. G  ?
_asm sidt buffer
2 |" E& p, R, p' y/ Y2 j& IIdtEntry=(PIdtEntry_t)Idtr->Base;, k" u0 t) E4 n5 F# o

6 S4 h9 O0 I' }" e- C8 \8 i/* HOOKINT就是我们想要hook的中断号
, `9 s2 f+ e" l' s这条语句的作用是找到我们要hook的IDT表项,然后备份原来的内容*/! V' P" c( G6 O$ b6 O
OldHandler = ((unsigned int)IdtEntry[HOOKINT].OffsetHigh<<16U)|8 [# N  X) k. X* X1 `- R8 [
(IdtEntry[HOOKINT].OffsetLow);
0 X5 c; r7 v# w
1 a: ^) D. m+ I/* 在IDT表项的相应位置写入新的中断处理函数的地址6 P! h* o: C) |4 D3 c& c& R
用新的中断处理函数替换原中断处理函数 */4 q2 L# V# s# ?6 t! E  N1 Y
_asm cli /* 这里注意,因为中断说不准会在这时候发生,所以要先diable中断 */$ B& d. P7 C& w' S7 n7 R4 Z% ]
IdtEntry[HOOKINT].OffsetLow = (unsigned short)NewHandler;
+ @1 R, G# F3 L  L/ p" H! YIdtEntry[HOOKINT].OffsetHigh = (unsigned short)((unsigned int)NewHandler>16);2 F1 F: ^. G# ]* e) ]& A
_asm sti /* Enable中断请求 */
4 Y4 z3 N3 j: s8 ?: `0 X  u  H: l3 }0 i0 z/ K1 c8 k- U
return STATUS_SUCCESS;7 |/ I- V* E9 C: e  _/ ~
}
; f9 c4 g) c/ H% M) `8 M+ g. s& b  }* H6 \7 w1 ~8 @' f& W6 L
上面是对IDT表项进行hook,我们只是修改了相应表项的Code Segment Offset。经过替换后,新的中断处理函数与原中断处理函数的“性 质相似”,即表项中其余的字段相同。如果读者对这句话不理解,那就请看IDT表项的数据结构。
# U  D. I: x2 H4 Stypedef struct InterruptGate
- R6 C  Z+ X" x" z, o) w{7 X, b% i$ _9 R8 L% |
unsigned short OffsetLow;
# y9 r9 a1 s( {& o- r0 ]unsigned short Selector;
& @3 F8 \# N/ `9 K& [/ @unsigned char Reserved;- g$ P8 C2 T) s+ Q0 h- _" B1 n
unsigned char SegmentType;
) X& ]) i- p# `unsigned char SystemSegmentFlag;( y! L+ I7 H6 A$ N- Z
unsigned char Dpl;1 ]  ?$ C3 S3 H5 C
unsigned char Present;
3 p# n& V2 b* o& [! o+ runsigned short OffsetHigh;9 U6 R- U# R3 w3 f% d: f8 Z
} InterruptGate_t;. J  b7 F* [) \# J; ^( m

, Z; A2 w* C) T* i3 F在上面的例子中,OffsetLow和OffsetHigh被改写了,从而hook了中断。让我们思考这样一个问题:如果IDT的相应表项没有内容呢,也就 是说,如果我们想让IDT的空表项指向我们的中断处理函数,又该怎么办呢?# c# w+ S6 C$ M5 Z1 r7 [& X  O
/ a) q( G! K# t' b: V# Z: [
[ 读者小强:Winnt和2K的IDT中有空表项吗?]
+ n- h& z$ t+ Y/ N1 a! f是的,比如说,在Winnt下,IDT表项的第22h---29h就是空表项。 这就是说我们可以给Winnt加入新的中断。但是,这里有了新的难度, 我们必须认真理解和填写上面数据结构InterruptGate中的所有字段。% W7 _+ J2 q+ Q
下面这些代码出自《Undocumented WindowsNT》,实现上述“搜索IDT、填写IDT表项所有字段”的功能。6 T) {& U; Z2 C" {
NTSTATUS AddInterrupt()
+ X' l- V$ M4 c3 i, ?: w8 _{) i2 X; S) O: G$ q1 v" a0 f: f
PIdtEntry_t IdtEntry;& S2 K$ ]# a1 L* J5 ^1 C

, q& K2 ~2 O4 v$ P$ K/* 获得IDTR Register 的Base Address和Limit*/
* f! q0 }- \* Z7 k" C3 k$ G) N_asm sidt buffer
- e; R' b, u0 m* A" ~, h2 iIdtEntry=(PIdtEntry_t)Idtr->Base;% L% p  V7 s% E" }3 U
if((IdtEntry[ADDINT].OffsetLow!=0)||(IdtEntry[ADDINT].OffsetHigh!=0))% {* ~2 y  Y. f# `
return STATUS_UNSUCCESSFUL;+ v. n  r$ t7 M4 H! Y6 {
2 G  {- T! [+ W8 E3 H' i3 F1 I
_asm cli6 R, B9 g0 \8 O# Z

+ D8 ~( ^# W2 S. h/* 填写IDT表项的所有字段,使新的IDT表项指向我们的中断处理函数 */
# o$ Z9 K$ y4 ?9 H' v& `5 `IdtEntry[ADDINT].OffsetLow=(unsigned short)InterruptHandler;
, E6 ^# R' x/ _: I2 V9 Q! PIdtEntry[ADDINT].Selector=8;
/ V% y0 R0 I7 T* ]IdtEntry[ADDINT].Reserved=0;& E3 P& Z2 e# u* S
IdtEntry[ADDINT].Type=0xE;
: N# v) Y" w" pIdtEntry[ADDINT].Always0=0;
6 \+ E) z6 g8 Q. S1 M% B. p, ~  ZIdtEntry[ADDINT].Dpl=3;
4 C( I" |3 @) ~* z  [* W/ N4 c3 {IdtEntry[ADDINT].Present=1;
, E% [) S% m/ z+ [IdtEntry[ADDINT].OffsetHigh=1 {% v$ M; b+ q! |
(unsigned short)((unsigned int) InterruptHandler>16);% s' W& x" `: N' P) z# N2 e% k
_asm sti! k3 V3 v" k: i7 o! p# |
9 G% n+ L% k& H7 D6 L
return STATUS_SUCCESS;
% d- ]2 U; ~# j}
2 y3 d. x8 N" R( h: f+ L: H2 G+ f
  V; G8 O$ o/ B) V让我们就上面的代码提一些问题。
  |/ D" H8 \, {1 ?7 b1 t. x; e8 lQ: 上面的代码IdtEntry[ADDINT].Selector=8; 这是怎么回事?
( X/ V( ?& d8 ?A:按Ctrl+D进到Softice里,你会发现,所以的system代码,都存在于一个段中。这
# w# S- J% [, s1 L" ^1 M( u个段的名称就是8(CS=8)。- @& |2 g( v9 ?: s! a$ k8 o9 \( n

" @- X8 N9 U' f+ x& IQ: 上面的代码IdtEntry[ADDINT].Dpl=3; 这是怎么回事?" u& _8 q4 o% g- Y; t
A:问得好,小强。这说明,这个中断可以在应用程序中,通过int xxx的形式触发。因为) d1 x( R& r* g
应用程序的DPL=3,所以,可以直接触发这个中断。1 C6 x) k/ }6 y; \
, l3 j' s# H0 V( z1 Y
Q: 上面的代码IdtEntry[ADDINT].Type=0xE; 这是怎么回事?* b# l) k4 P: M
A:按Ctrl+D进到Softice里,然后敲入指令idt。输出如下1 |. q0 a. m& i. P  H. I, m, s  q1 ^
:idt" m; N$ I' j/ n' v) q
Int Type Sel:Offset Attributes Symbol/Owner1 U9 r2 M& S6 _" N4 K! I' f
IDTbase=80036400 Limit=07FF5 ~9 g7 J, L9 |' p. R7 ]
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
# E, u- v/ o( _7 T0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E02 b" p5 t- A5 M# O' n
……
9 A1 [( l/ a) f3 y, l可见,0xE表示IntG32。
& g+ C! A9 c% c. S1 O
7 r$ w( ?: g5 ^* n2 N+ ]终于快到下课的时间了,让我再多说几句好吗?
# i( B- [$ W& |7 l2 I/ |通过对Winnt/2k IDT的分析,我们对IDT有了一些基本认识。上面介绍的通过修改IDT来hook中断的方法,是很危险的。笔者强烈建议读 者尽量通过Winnt/2k DDK官方资料提供的API来实现hook中断的功能。
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 03:46 , Processed in 0.369045 second(s), 52 queries .

回顶部