实现原理:
inlinehook内核文件ntosknl.exe的内部函数KeInitializeApc,对相关参数进行检测,若发现不符合规则的APC插入动作则进行拦截。

拦截实现方式:

将KAPC结构中的参数Thread修改成自身的某一KThread结构指针,达到"挂入A,实际却挂到B的效果",从而使该APC失去效用。
若关键函数sub_130A4返回为1,则修改KAPC结构中的Thread参数,进行拦截;若返回为0,则放行此次插入APC动作。(见红色代码部分)

InlineHook位置:
蓝色代码部分


检测规则:

1)进程自身内的APC全部予以放过
2)进程间的用户APC互插,仅允许system进程的孙子进程(即csrss.exe winlogin.exe)和某一特定用户进程
3)拦截非正规调用KeInitializeApc进行用户APC插入的动作
详见sub_130A4 函数分析,里面的函数一环套另一环,比较多,只帖出了主函数部分

代码:
nt!KeInitializeApc:                               ;
mov     edi,edi                                   ;
push    ebp                                       ;
mov     ebp,esp                                   ;
mov     eax,dword ptr [ebp+8]                     ;[ebp+8]: Apc
mov     edx,dword ptr [ebp+10h]                   ;[ebp+10h]: TargetEnvironment
cmp     edx,2                                     ;
mov     ecx,dword ptr [ebp+0Ch]                   ;[ebp+0Ch]: Thread
mov     word ptr [eax],12h                        ;Apc->Type = 0x12
mov     word ptr [eax+2],30h                      ;Apc->Size = 0x30
jne     nt!KeInitializeApc+0x24 (804fd3c2)        ;若TargetEnvironment != CurrentApcEnvironment则跳转
mov     dl,byte ptr [ecx+165h]                    ;[ecx+165h]:Thread->ApcStateIndex,表示当前线程的环境值
---------------------------------------------------
nop                                               ;inline Hook部分:仅对Apc->Thread进行了处理
call    xyz12345+0x333c (ba27b33c)                ;处理函数
---------------------------------------------------
mov     dword ptr [eax+14h],ecx        ;
mov     ecx,dword ptr [ebp+18h]                   ;
mov     byte ptr [eax+2Ch],dl                     ;
mov     dword ptr [eax+18h],ecx                   ;
mov     ecx,dword ptr [ebp+1Ch]                   ;
xor     edx,edx                                   ;
cmp     ecx,edx                                   ;
mov     dword ptr [eax+1Ch],ecx                   ;
je      nt!KeInitializeApc+0x50 (804fbaa6)        ;
mov     cl,byte ptr [ebp+20h]                     ;
mov     byte ptr [eax+2Dh],cl                     ;
--------------------------------------------------;
在进入处理函数之前,堆栈空间内容:
|Context            |
|Mode               |
|NormalRoutine      |
|RundownRoutine     |
|KernelRoutine      |
|TargetEnvironment  |
|Thread             |
|Apc                |
|KeInitializeApc.Ret|
|KeInitializeApc.Ebp|


b2a7033c:                                        ;
mov     edi, edi                                  ;
pusha                                             ;
pushf                                             ;
lock inc dword_16AC0                              ;多核同步
mov     eax, dword_16B44                          ;dword_16B44:PsExitSpecialApc函数地址
test    eax, eax                                  ;
jnz     short loc_1338A                           ;
mov     ebx, [ebp+14h]                            ;[ebp+14h]:KernelRoutine
mov     ecx, [ebp+20h]                            ;[ebp+20h]:NormalRoutine
mov     edx, [ebp+10h]                            ;[ebp+10h]:TargetEnvironment
mov     esi, [ebp+0Ch]                            ;[ebp+0Ch]:Thread
mov     eax, Object                               ;Object: 进程的ETHREAD结构指针
cmp     eax, esi                                  ;
jnz     short loc_133B5                           ;若当前线程不是Object代表的线程则跳转
test    ecx, ecx                                  ;
jnz     short loc_133B5                           ;若NormalRoutine!= NULL 则跳转
test    edx, edx                                  ;
jnz     short loc_133B5                           ;若TargetEnvironment != OriginalApcEnvironment则跳转
mov     edi, dword_16A7C                          ;dword_16A7C: ntoskln.exe模块的Base
cmp     ebx, edi                                  ;
jb      short loc_133B5                           ;若KernelRoutine 低于dword_16A7C 则跳转
mov     eax, dword_16AA0                          ;dword_16AA0: ntoskln.exe模块的Size
add     edi, eax                                  ;
cmp     ebx, edi                                  ;
jg      short loc_133B5                           ;若KernelRoutine 高于dword_16A7C + dword_16AA0 则跳转
mov     dword_16B44, ebx                          ;
jmp     short loc_133B5                           ;
--------------------------------------------------;
                                                  ;
.text:0001338A loc_1338A:                         ;
mov     eax, [ebp+0Ch]                            ;[ebp+0Ch]:Thread
push    eax                                       ;
mov     eax, [ebp+14h]                            ;[ebp+14h]:KernelRoutine
push    eax                                       ;
mov     eax, [ebp+4]                              ;[ebp+4]: KeInitializeApc.Ret
push    eax                                       ;
call    sub_130A4                                 ;关键函数
test    al, al                                    ;
jz      short loc_133B5                           ;
popf                                              ;
popa                                              ;
mov     ecx, Object                               ;
mov     [eax+8], ecx                              ;Apc->Thread = Object
mov     ecx, [ebp+14h]                            ;
lock dec dword_16AC0                              ;
retn                                              ;
-----------------------------                     ;
.text:000133B5 loc_133B5:                         ;
popf                                              ;
popa                                              ;
mov     [eax+8], ecx                              ;
mov     ecx, [ebp+14h]                            ;
lock dec dword_16AC0                              ;
retn                                              ;
代码:
char __stdcall sub_130A4(unsigned int a1, int a2, void *a3)
//(KeInitializeApc.Ret, KernelRoutine, Thread)
{
  ...
  v4 = PsGetCurrentProcessId();//获得当前进程的进程ID
  v21 = sub_126D2(v5);//由Ethread指针返回此线程所属进程的进程ID(非挂靠进程)
  if ( Object && !(unsigned __int8)sub_12CEC(v4) && v4 != (HANDLE)v21 && v21 != -1 )
  //当前进程不是插入APC目标线程的所属进程,目标线程所属进程不是NtCurrentProcess(),当前进程不在自身的私有结构链表中
  {
    if ( !(unsigned __int8)sub_12CEC((PVOID)v21) )
  //若目标线程所属进程id不在私有结构链表中,则返回
      return v3;
    v3 = 1;
  //捕获1)非正规调用KeInitializeApc 2)用户空间APC(用户空间APC的KernelRoutine为PsExitSpecialApc)
    if ( a1 <= dword_16A7C || a1 >= dword_16AA0 + dword_16A7C || a2 == dword_16B44 )
  //a1 <= ntosknl.exe.Base || a1 >= ntosknl.exe.Base + ntosknl.exe.Size || a2 == PsExitSpecialApc
    {
      if ( a2 <= (unsigned int)dword_16A7C || a2 >= (unsigned int)(dword_16A7C + dword_16AA0) )
      {//若a2不在ntosknl.exe模块势力范围,则打印可疑信息
        if ( a2 != dword_16B44 )
          goto LABEL_37;
      }
      else
      {//若a2在ntosknl.exe模块势力范围,但不等于PsExitSpecialApc则跳过此次处理
        if ( a2 != dword_16B44 )
          return 0;
      }
      v12 = KeGetCurrentThread();
      if ( !(unsigned __int8)sub_12F12(v12) )
      {//排除某一用户程序的插APC行为
        if ( (_WORD)NtBuildNumber <= 3790 ) //windows xp 64-bit Edition Version 2003
        {
          v14 = IoGetCurrentProcess();
          v6 = sub_12660(v14);//返回当前进程的父进程的Eprocess结构
          VirtualAddress = (PVOID)v6;
          if ( v6 )
          {
            v7 = sub_12660((PVOID)v6);//返回当前进程的爷进程的Eprocess结构
            VirtualAddress = (PVOID)v7;
            if ( v7 )
            {
              v8 = sub_11944(v7);//获得爷进程ID
              if ( (_WORD)NtBuildNumber != 2195 ) //若系统版本不是 windows 2000
                v9 = v8 == 4;//确认爷进程是否为4,即是否为 system进程
              else
                v9 = v8 == 8;
              if ( v9 )
                return 0;
                //若某个进程的爷进程为system进程,则允许Apc插入
            }
          }
        }
        else
        {
        ......

          v10 = sub_1268A(v5);//返回Thread所属进程的Eprocess结构指针

          VirtualAddress = (PVOID)v10;
          if ( v10 )
          {
            *(_DWORD *)(dword_1684C + v10) &= 0xFFFFFFF7;//dword_1684C = 0x248
            //清除Eprocess.Flags的ProcessDelete位
            *(_DWORD *)((char *)v5 + dword_16AE8) &= 0xFFFFFFFE;//dword_16AE8 = 0x248 
            //清除Ethread.CrossThreadFlags的Terminated位

          }
        }
        v3 = 1;
LABEL_37:
         ...
        return v3;
      }
    }
    return 0;
  }
  return 0;
}
不对之处,望海涵!并请帮忙指出