IoConnectInterrupt . 1
IoConnectInterrupt的内部实现, 看他是如何把ServiceRoutine( ServiceContext ) 设置成IDT中断处理函数的
先看看_KINTERRUPT的结构
kd> dt _KINTERRUPT 817687d8
nt!_KINTERRUPT
+0x000 Type : 22
+0x002 Size : 484
+0x004 InterruptListEntry : _LIST_ENTRY
+0x00c ServiceRoutine : 0xf980467e // 偏移 +0x0c = ServiceRoutine
+0x010 ServiceContext : 0x817c8030 // 偏移 +0x10 = ServiceContext
+0x014 SpinLock : 0
+0x018 TickCount : 0xffffffff
+0x01c ActualLock : 0x81768a3c -> 0
+0x020 DispatchAddress : 0x80546660
+0x024 Vector : 0x162 // 偏移 +0x24 = Vector
+0x028 Irql : 0x5 ''
+0x029 SynchronizeIrql : 0x5 ''
+0x02a FloatingSave : 0 ''
+0x02b Connected : 0x1 ''
+0x02c Number : 0 ''
+0x02d ShareVector : 0 ''
+0x030 Mode : 1 ( Latched ) 中断模式
+0x034 ServiceCount : 0
+0x038 DispatchCount : 0xffffffff
+0x03c DispatchCode : [106] 0x56535554
系统是通过一个模板化的中断处理函数,在其内部去调用这个ServiceRoutine来完成中断处理的,模板结构如下
public _KiInterruptTemplate
_KiInterruptTemplate label byte
public _KiInterruptTemplate2ndDispatch
_KiInterruptTemplate2ndDispatch equ this dword
mov edi,0 // 不同的中断, 内部修改成不同的 mov edi,PKINTERRUPT
public _KiInterruptTemplateObject
_KiInterruptTemplateObject equ this dword
jmp _KeSynchronizeExecution // 这里会被改为, jmp KiInterruptDispatch
public _KiInterruptTemplateDispatch
_KiInterruptTemplateDispatch equ this dword
//
// 下面是 KiInterruptDispatch 函数, 对照上面的`_KINTERRUPT`结构, 看看偏移都是什么值
//
int __stdcall KiInterruptDispatch()
.text:004048CA _KiInterruptDispatch@0 proc near ; DATA XREF: KiGetVectorInfo(x,x)+45o
.text:004048CA inc large dword ptr fs:5C4h
.text:004048D1 mov ebp, esp
.text:004048D3 mov eax, [edi+24h] // 偏移 +0x24 = Vector
.text:004048D6 mov ecx, [edi+29h] // 偏移 +0x29 = SynchronizeIrql
.text:004048D9 push eax
.text:004048DA sub esp, 4
.text:004048DD push esp
.text:004048DE push eax
.text:004048DF push ecx
.text:004048E0 call ds:__imp__HalBeginSystemInterrupt@12 ; HalBeginSystemInterrupt(x,x,x)
.text:004048E6 or eax, eax
.text:004048E8 jz short loc_40492A
.text:004048EA sub esp, 0Ch
.text:004048ED cmp _PPerfGlobalGroupMask, 0
.text:004048F4 mov [ebp+var_C], 0
.text:004048FB jnz short loc_40493E
.text:004048FD
.text:004048FD loc_4048FD: ; CODE XREF: KiInterruptDispatch()+6Ej
.text:004048FD ; KiInterruptDispatch()+7Dj ...
.text:004048FD mov esi, [edi+1Ch]
.text:00404900 lock bts dword ptr [esi], 0
.text:00404905 jb short loc_404932
.text:00404907 mov eax, [edi+10h] // 偏移 +0x10 = ServiceContext
.text:0040490A push eax
.text:0040490B push edi
.text:0040490C call dword ptr [edi+0Ch] // 偏移 +0x0c = ServiceRoutine, 真正的中断处理函数
...
由此我们得知中断处理函数为这个样子
mov edi,PKINTERRUPT
jmp KiInterruptDispatch
函数IoConnectInterrupt内部调用的两个主要函数为KeInitializeInterrupt和KeConnectInterrupt, 首先在KeInitializeInterrupt内部
NormalDispatchCode = &(Interrupt->DispatchCode[0]);
pl = NormalDispatchCode;
for (Index = 0; Index < NORMAL_DISPATCH_LENGTH; Index += 1) {
*NormalDispatchCode++ = KiInterruptTemplate[Index]; // 把上面提到的模板原样拷贝到 Interrupt->DispatchCode
}
//
// The following two instructions set the address of current interrupt
// object the the NORMAL dispatching code.
//
pl = (PULONG)((PUCHAR)pl + ((PUCHAR)&KiInterruptTemplateObject - // KiInterruptTemplateObject 和 KiInterruptTemplate 中间就是
(PUCHAR)KiInterruptTemplate) -4); // mov edi, 0 这条指令, 再 -4,指向的就是edi后面的这个值,
// mov edi, 0 的汇编指令为 “BF 00 00 00 00”
*pl = (ULONG)Interrupt; // 赋值后变为了 mov edi, PKINTERRUPT
...
函数KeConnectInterrupt的内部,通过调用KiConnectVectorAndInterruptObject来完成
...
KiGetVectorInfo ( // 内部得到 InterruptDispatch函数地址
Interrupt->Vector, // DispatchInfo->InterruptDispatch = KiInterruptDispatch;
&DispatchInfo // DispatchInfo->FloatingDispatch = KiFloatingDispatch;
); // DispatchInfo->ChainedDispatch = KiChainedDispatch;
// DispatchInfo->NoDispatch = (PKINTERRUPT_ROUTINE) (((ULONG) &KiStartUnexpectedRange) +
// (IDTEntry - PRIMARY_VECTOR_BASE) * KiUnexpectedEntrySize);
// 根据不同的Type,最后选择不同的 DispatchAddress
if (Type == NoConnect) {
DispatchAddress = DispatchInfo.NoDispatch;
} else {
DispatchAddress = DispatchInfo.ChainedDispatch;
if (Type == NormalConnect) {
DispatchAddress = DispatchInfo.InterruptDispatch;
if (Interrupt->FloatingSave) {
DispatchAddress = DispatchInfo.FloatingDispatch;
}
}
Interrupt->DispatchAddress = DispatchAddress;
//
// Set interrupt objects dispatch code to kernel dispatcher
//
pl = &(Interrupt->DispatchCode[0]); //
pl = (PULONG)((PUCHAR)pl + // KiInterruptTemplateDispatch 和 KiInterruptTemplate 中间就是
((PUCHAR)&KiInterruptTemplateDispatch - // mov edi,0 和 jmp _KeSynchronizeExecution 两条指令
(PUCHAR)KiInterruptTemplate) -4); // 和处理mov edi,0时一样, jmp 的汇编指令为 E9 00 00 00 00
// 目的地址 = (jmp的下面一条指令地址) + (地址偏移)
// DispatchAddress = ( p1 + 4 ) + (地址偏移)
// 我们只要修改成 jmp (地址偏移) ,就能够跳到目的地址
*pl = (ULONG)DispatchAddress-(ULONG)((PUCHAR)pl+4); // 给(地址偏移)赋值, 这样就完成了 jmp KiInterruptDispatch
...
// 把模板都修改完成了,下面把地址设置到IDT里
//
DispatchAddress = (PKINTERRUPT_ROUTINE) &Interrupt->DispatchCode; // 指向我们修改好的模板了
KiSetHandlerAddressToIDT (Interrupt->Vector, DispatchAddress); // #define KiSetHandlerAddressToIDT(Vector, HandlerAddress) {\
// UCHAR IDTEntry = HalVectorToIDTEntry(Vector); \
// ULONG Ha = (ULONG)HandlerAddress; \
// KeGetPcr()->IDT[IDTEntry].ExtendedOffset = HIGHWORD(Ha); \
// KeGetPcr()->IDT[IDTEntry].Offset = LOWWORD(Ha); \
...

浙公网安备 33010602011771号