众所周知,在进行内核Inline Hook的时候,如果需要Patch的字节数少于等于8,我们可以借助CMPXCHG8B或者Interlockedcompareexchange64大法进行原子挂钩(这两个函数会申请总线锁和缓存锁,达到多核同步的效果);但是如果字节数大于8怎么办呢?我们可以使用DPC播报(KeInsertQueueDpc或者KeGenericCallDpc(XP未导出))完成,将所有核挂入DPC,然后由一个核实现挂钩,最早的安全软件们都是这么做的。但是,如果在申请DPC的过程中,有一个核因为某些原因处于DIRQL状态,无法执行DPC,最后就会导致系统挂死,高版本系统会触发DPC_WATCHDOG_VIOLATION(0x133)蓝屏。
所以鉴于以上原因,我们发现了另外一个新函数:KiIpiGenericCall,这个函数会把所有核提到IPI Level,这个IRQL甚至已经高过了时钟中断,这种级别可以打断几乎所有IRQL的例程,强行将CPU提升至IPI。不过遗憾的是,这个函数在XP并未导出。
下列提出两种比较WORK-AROUND的方式供大家选择:
.text:8050C6B4 ; --------------------------------------------------------------------------- .text:8050C6B9 90 90 90 90 90 db 5 dup(90h) .text:8050C6BE ; Exported entry 621. KeSetTargetProcessorDpc .text:8050C6BE .text:8050C6BE ; =============== S U B R O U T I N E ======================================= .text:8050C6BE .text:8050C6BE ; Attributes: bp-based frame .text:8050C6BE .text:8050C6BE ; void __stdcall KeSetTargetProcessorDpc(PRKDPC Dpc, CCHAR Number) .text:8050C6BE public _KeSetTargetProcessorDpc@8 .text:8050C6BE _KeSetTargetProcessorDpc@8 proc near ; CODE XREF: PopInvokeSystemStateHandler(x,x)+1B2↓p .text:8050C6BE ; PoInitializePrcb(x)+48↓p ... .text:8050C6BE .text:8050C6BE Dpc = dword ptr 8 .text:8050C6BE Number = byte ptr 0Ch .text:8050C6BE .text:8050C6BE 8B FF mov edi, edi .text:8050C6C0 55 push ebp .text:8050C6C1 8B EC mov ebp, esp .text:8050C6C3 8A 45 0C mov al, [ebp+Number] .text:8050C6C6 8B 4D 08 mov ecx, [ebp+Dpc] .text:8050C6C9 04 20 add al, 20h ; ' ' .text:8050C6CB 88 41 02 mov [ecx+2], al .text:8050C6CE 5D pop ebp .text:8050C6CF C2 08 00 retn 8 .text:8050C6CF _KeSetTargetProcessorDpc@8 endp .text:8050C6CF .text:8050C6CF ; --------------------------------------------------------------------------- .text:8050C6D2 90 90 90 90 90 db 5 dup(90h) .text:8050C6D7 .text:8050C6D7 ; =============== S U B R O U T I N E ======================================= .text:8050C6D7 .text:8050C6D7 ; Attributes: bp-based frame .text:8050C6D7 .text:8050C6D7 ; __stdcall KiIpiGenericCall(x, x) .text:8050C6D7 _KiIpiGenericCall@8 proc near ; CODE XREF: KiRestoreFastSyscallReturnState()+36↓p .text:8050C6D7 ; KiAdjustInterruptTime(x,x)+3F↓p ... .text:8050C6D7 .text:8050C6D7 arg_0 = dword ptr 8 .text:8050C6D7 arg_4 = dword ptr 0Ch .text:8050C6D7 .text:8050C6D7 ; FUNCTION CHUNK AT .text:8051EA7C SIZE 0000000A BYTES .text:8050C6D7 .text:8050C6D7 8B FF mov edi, edi .text:8050C6D9 55 push ebp .text:8050C6DA 8B EC mov ebp, esp .text:8050C6DC 53 push ebx .text:8050C6DD 56 push esi .text:8050C6DE 8B 35 7C 86 4D 80 mov esi, ds:__imp__KeGetCurrentIrql@0 ; KeGetCurrentIrql() .text:8050C6E4 FF D6 call esi ; KeGetCurrentIrql() ; KeGetCurrentIrql() .text:8050C6E6 6A 02 push 2 .text:8050C6E8 59 pop ecx ; NewIrql .text:8050C6E9 3A C1 cmp al, cl .text:8050C6EB 0F 83 8B 23 01 00 jnb loc_8051EA7C .text:8050C6F1 .text:8050C6F1 loc_8050C6F1: ; CODE XREF: KiIpiGenericCall(x,x)+123AA↓j .text:8050C6F1 FF 15 74 86 4D 80 call ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x) .text:8050C6F7 FF 75 0C push [ebp+arg_4] .text:8050C6FA 8A D8 mov bl, al .text:8050C6FC FF 55 08 call [ebp+arg_0] .text:8050C6FF 8A CB mov cl, bl ; NewIrql .text:8050C701 8B F0 mov esi, eax .text:8050C703 FF 15 9C 86 4D 80 call ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x) .text:8050C709 8B C6 mov eax, esi .text:8050C70B 5E pop esi .text:8050C70C 5B pop ebx .text:8050C70D 5D pop ebp .text:8050C70E C2 08 00 retn 8 .text:8050C70E _KiIpiGenericCall@8 endp .text:8050C70E