欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

APC主动防御逆向分析

来源:转载 作者:佚名 时间:2010-05-09 TAG: 我要投稿
1.实现原理:
                  inlinehook内核文件ntosknl.exe的内部函数KeInitializeApc,对相关参数进行检测,若发现不符合规则的APC插入动作则进行拦截

2.拦截实现方式:

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

3.InlineHook位置:
                蓝色代码部分


4.检测规则:

             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;
}
【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载