前几天在论坛上看见一篇360HOOK框架的文章,写得不错,其实hookport.sys之前很多人都
逆过了,而且教主写了一套很详细的文章。本人才疏学浅,只是补充一些科普知识,好像一些像我一样
的菜鸟成长起来。这篇文章主要介绍一些360的比较精辟的应用,至于它HOOK了那些函数大家可以去网上
搜索教主那篇文章。其实就是一个结构。
     亮点一:HOOK KiFastCallEntry  科普一下 KiFastCallEntry 快速系统调用SYSENTER
就是说每次系统调用的时候,最终都会通过KiFastCallEntry 
我们来看看KiFastCallEntry函数比较关键代码
8054257d 8bb324010000    mov     esi,dword ptr [ebx+124h] //获得CurrentThread
80542583 ff33            push    dword ptr [ebx]
80542585 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh
8054258b 8b6e18          mov     ebp,dword ptr [esi+18h]
8054258e 6a01            push    1
80542590 83ec48          sub     esp,48h
80542593 81ed9c020000    sub     ebp,29Ch
80542599 c6864001000001  mov     byte ptr [esi+140h],1
805425a0 3bec            cmp     ebp,esp
805425a2 758d            jne     nt!KiFastCallEntry2+0x49 (80542531)
805425a4 83652c00        and     dword ptr [ebp+2Ch],0
805425a8 f6462cff        test    byte ptr [esi+2Ch],0FFh
805425ac 89ae34010000    mov     dword ptr [esi+134h],ebp
805425b2 0f8538feffff    jne     nt!Dr_FastCallDrSave (805423f0)
805425b8 8b5d60          mov     ebx,dword ptr [ebp+60h]
805425bb 8b7d68          mov     edi,dword ptr [ebp+68h]
805425be 89550c          mov     dword ptr [ebp+0Ch],edx
805425c1 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h
805425c8 895d00          mov     dword ptr [ebp],ebx
805425cb 897d04          mov     dword ptr [ebp+4],edi
805425ce fb              sti
805425cf 8bf8            mov     edi,eax //eax=SSDTindex
805425d1 c1ef08          shr     edi,8  //除以256
805425d4 83e730          and     edi,30h //要就是0 要就是0X10为了判断是SSDTSHADOW还是SSDT
805425d7 8bcf            mov     ecx,edi
805425d9 03bee0000000    add     edi,dword ptr [esi+0E0h] //通过esi=KTHREAD->ServiceTable获得
当前线程使用的ServiceTable;
805425df 8bd8            mov     ebx,eax //SSDTID
805425e1 25ff0f0000      and     eax,0FFFh
805425e6 3b4708          cmp     eax,dword ptr [edi+8]
805425e9 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (80542322)
805425ef 83f910          cmp     ecx,10h //这里判断是SSDT还是SSDTSHADOW
805425f2 751b            jne     nt!KiFastCallEntry+0xcf (8054260f)
805425f4 648b0d18000000  mov     ecx,dword ptr fs:[18h]
805425fb 33db            xor     ebx,ebx
805425fd 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
80542603 740a            je      nt!KiFastCallEntry+0xcf (8054260f)
80542605 52              push    edx
80542606 50              push    eax
80542607 ff1548d75580    call    dword ptr [nt!KeGdiFlushUserBatch (8055d748)]
8054260d 58              pop     eax
8054260e 5a              pop     edx
8054260f 64ff0538060000  inc     dword ptr fs:[638h] //使用计数
80542616 8bf2            mov     esi,edx
80542618 8b5f0c          mov     ebx,dword ptr [edi+0Ch]
8054261b 33c9            xor     ecx,ecx
8054261d 8a0c18          mov     cl,byte ptr [eax+ebx]
80542620 8b3f            mov     edi,dword ptr [edi]
80542622 8b1c87          mov     ebx,dword ptr [edi+eax*4]
80542625 e9d69c8d09      jmp     89e1c300   //这个就是360的HOOK了,这个就是360的亮点之处
上面 EDI=SSDTaddr EBX=系统服务地址 EAX=SSDTindex 有了这几个寄存器省了很多麻烦了。
8054262a 8bfc            mov     edi,esp
8054262c 3b3534315680    cmp     esi,dword ptr [nt!MmUserProbeAddress (80563134)]
80542632 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (805427e0)
80542638 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
8054263a ffd3            call    ebx      //服务调用
8054263c 8be5            mov     esp,ebp
     第二步,我们来看看360是怎么HOOK的
                mov     edi, edi
                push    ebp
                mov     ebp, esp
                sub     esp, 18h
                push    ebx
                push    esi
                push    edi
                push    offset aZwsetevent ; "ZwSetEvent"
                lea     eax, [ebp+DestinationString]
                push    eax             
                call    ds:RtlInitAnsiString //初始化
                lea     eax, [ebp+DestinationString]
                push    eax
                call    sub_17A78       
                xor     esi, esi
                cmp     eax, esi
                jz      loc_195B4
                mov     eax, [eax+1]  //获取ZwSetEventINDEXID =DB
                mov     ZwSetEventaddrid, eax
                lea     eax, [ebp+SpinLock]
.               push    eax             ; SpinLock
                call    ds:KeInitializeSpinLock
                mov     edi, ds:KfAcquireSpinLock
.               lea     ecx, [ebp+SpinLock] ; SpinLock
                call    edi ; KfAcquireSpinLock
                mov     cl, al
                push    eax
                push    ebx
                push    edx
               cli
               mov     eax, cr0
               mov     [ebp+var_C], eax
               and     eax, 0FFFEFFFFh
               mov     cr0, eax
               mov     eax, ZwSetEventaddrid //EAX=INDEXID
               mov     edx, KeServiceDescriptorTableaddr//EDX=SSDTADDR
               mov     edx, [edx]
               mov     ebx, [edx+eax*4] //获取ZwSetEventADDR
               mov     ZwSetEventaddr, ebx //保持
               mov     ebx, offset sub_192A8//HOOK
               mov     [edx+eax*4], ebx
               mov     eax, [ebp+var_C]
               mov     cr0, eax
               sti
                pop     edx
               pop     ebx
                 pop     eax
                mov     dl, cl          ; NewIrql
               lea     ecx, [ebp+SpinLock] ; SpinLock
               call    ds:KfReleaseSpinLock
               mov     eax, 288C58F1h  //这个比较关键,主要是确定是不是自己调用
               push    esi             ; PreviousState
               push    eax             ; EventHandle
               mov     dword_1B850, eax //保存
               call    ds:ZwSetEvent
               mov     eax, fanhuiaddrs //调用后返回地址8054263c 
               cmp     eax, esi
                jnz     short loc_19510
                mov     eax, P
                cmp     eax, esi
                jmp     loc_195AB
                 cmp     addbp4addr5, esi//这个是HOOK返回地址8054262a 
                jnz     loc_19629
        
    第三步,我们来看下它的HOOK函数
     mov     edi, edi
.text:000192AA                 push    ebp
.text:000192AB                 mov     ebp, esp
.text:000192AD                 push    ecx
.text:000192AE                 push    ecx
.text:000192AF                 mov     eax, [ebp+arg_0] //获取第一个参数EventHandle
.text:000192B2                 cmp     eax, dword_1B850 //看看是不是自己调用
.text:000192B8                 push    ebx
.text:000192B9                 push    esi
.text:000192BA                 push    edi
.text:000192BB                 jnz     loc_193CB   //如果不是就跳到原服务调用
.text:000192C1                 call    ds:ExGetPreviousMode
.text:000192C7                 test    al, al
.text:000192C9                 jnz     loc_193CB//比较是不是USERMODULE调用是酒跳
.text:000192CF                 push    206B6444h       ; Tag
.text:000192D4                 push    5               ; NumberOfBytes
.text:000192D6                 push    0               ; PoolType
.text:000192D8                 call    ds:ExAllocatePoolWithTag //声请一块5字节内存
.text:000192DE                 test    eax, eax
.text:000192E0                 mov     P, eax    //保存到全局变量
.text:000192E5                 jz      loc_193C7
.text:000192EB                 mov     byte ptr [eax], 0E9h //第一个E9 JMP
.text:000192EE                 mov     eax, ds:NtBuildNumber
.text:000192F3                 cmp     word ptr [eax], 1770h //比较版本号
.text:000192F8                 mov     eax, P
.text:000192FD                 mov     ecx, offset byte_19284
.text:00019302                 jge     short loc_19309
.text:00019304                 mov     ecx, offset byte_19260 //取过滤函数地址
.text:00019309
.text:00019309 loc_19309:                             
.text:00019309                 sub     ecx, eax
.text:0001930B                 sub     ecx, 5
.text:0001930E                 mov     [eax+1], ecx //这几步都懂的,写跳转
.text:00019311                 lea     eax, [ebp+SpinLock]
.text:00019314                 push    eax             ; SpinLock
.text:00019315                 call    ds:KeInitializeSpinLock
.text:0001931B                 lea     ecx, [ebp+SpinLock] ; SpinLock
.text:0001931E                 call    ds:KfAcquireSpinLock
.text:00019324                 mov     bl, al
.text:00019326                 push    eax
.text:00019327                 push    ecx
.text:00019328                 push    edx
.text:00019329                 push    esi
.text:0001932A                 push    edi
.text:0001932B                 cli
.text:0001932C                 mov     eax, cr0
.text:0001932F                 mov     [ebp+arg_0], eax
.text:00019332                 and     eax, 0FFFEFFFFh
.text:00019337                 mov     cr0, eax
.text:0001933A                 mov     eax, KeServiceDescriptorTableaddr
.text:0001933F                 mov     eax, [eax]   //这里先重新写回
.text:00019341                 mov     edx, ZwSetEventaddrid
.text:00019347                 lea     eax, [eax+edx*4]
.text:0001934A                 mov     edx, ZwSetEventaddr
.text:00019350                 mov     [eax], edx
.text:00019352                 mov     eax, [ebp+4] //获取返回地址8054263c 
.text:00019355                 mov     edx, eax
.text:00019357                 mov     fanhuiaddrs, edx//保存返回地址
.text:0001935D
.text:0001935D loc_1935D:                             
.text:0001935D                 mov     edi, eax  //EAX=返回地址
.text:0001935F                 lea     esi, dword_1B680//特征码2be1c1e9 也就是sub esp, ecx shr ecx, 2
查找确定KiFastCallEntryHOOK位置           
    .text:00019365                 mov     ecx, 5
.text:0001936A                 repe cmpsb
.text:0001936C                 push    eax
.text:0001936D                 setz    al
.text:00019370                 test    al, al
.text:00019372                 pop     eax
.text:00019373                 jnz     short loc_19381
.text:00019375                 dec     eax
.text:00019376                 push    edx
.text:00019377                 sub     edx, eax
.text:00019379                 cmp     edx, 64h
.text:0001937C                 pop     edx
.text:0001937D                 ja      short loc_193B0
.text:0001937F                 jmp     short loc_1935D
.text:00019381 ; ---------------------------------------------------------------------------
.text:00019381
.text:00019381 loc_19381:                             
.text:00019381                 add     eax, 5     //确定HOOK后返回地址
.text:00019384                 mov     addbp4addr5, eax //保存
.text:00019389                 mov     edx, P
.text:0001938F                 sub     edx, eax
.text:00019391                 lea     eax, byte_1B688
.text:00019397                 mov     [eax+1], edx
.text:0001939A                 mov     edi, addbp4addr5
.text:000193A0                 sub     edi, 5
.text:000193A3                 lea     esi, byte_1B688
.text:000193A9                 mov     ecx, 5
.text:000193AE                 rep movsb        //这一段都知道的,HOOK
.text:000193B0
.text:000193B0 loc_193B0:                              
.text:000193B0                 mov     eax, [ebp+arg_0]
.text:000193B3                 mov     cr0, eax
.text:000193B6                 sti
.text:000193B7                 pop     edi
.text:000193B8                 pop     esi
.text:000193B9                 pop     edx
.text:000193BA                 pop     ecx
.text:000193BB                 pop     eax
.text:000193BC                 mov     dl, bl          ; NewIrql
.text:000193BE                 lea     ecx, [ebp+SpinLock] ; SpinLock
.text:000193C1                 call    ds:KfReleaseSpinLock
.text:000193C7
.text:000193C7 loc_193C7:                              
.text:000193C7                 xor     eax, eax
.text:000193C9                 jmp     short loc_193DF
.text:000193CB 
.text:000193CB
.text:000193CB loc_193CB:                              
.text:000193CB                                         
.text:000193CB                 push    eax
.text:000193CC                 push    [ebp+arg_4]     
.text:000193CF                 push    [ebp+arg_0]     
.text:000193D2                 call    ZwSetEventaddr//这里是确定不是自己调用就调用原服务
.text:000193D8                 mov     [ebp+var_8], eax
.text:000193DB                 pop     eax
.text:000193DC                 mov     eax, [ebp+var_8]
.text:000193DF
.text:000193DF loc_193DF:                             
.text:000193DF                 pop     edi
.text:000193E0                 pop     esi
.text:000193E1                 pop     ebx
.text:000193E2                 leave
.text:000193E3                 retn    8
.text:000193E3 sub_192A8       endp
这段给一段C代码,写得很乱,大家凑合看
HANDLE hand=(HANDLE)0x288C58F1;//这里的几个全局变量大家自己定义,
这里特别标出这个主要是考虑要判断

 NTSTATUS 
  NewZwSetEvent (
     HANDLE  EventHandle,
     PLONG  PreviousState 

    )
{
    NTSTATUS status;
    char *p,*ps;
  char code[5]={0xe9,0,0,0,0}; 
  char code1[5]={0xe9,0,0,0,0};   
  ULONG addr,addr1,addr2;
  KIRQL  Irql; 
    
  if (EventHandle!=hand||ExGetPreviousMode()==UserMode)   //判断一下是不是自己调用

    status= OldZwSetEventEventHandle,PreviousState); 


  else{
  
    _asm{
   mov eax,[ebp+4]
   mov addrss,eax
  }
   DbgPrint("addrs is %08X\n",addrss); 
    p=(ULONG)addrss;
  //2be1c1e902
    ps=(char*)ExAllocatePoolWithTag(0,5,0);//这里判断一下哈,免得失败了 本人很懒
  while(1)
  {
    if(*p==0x2b) //这里大家多判断几个特征,本人很懒
    {
       hookaddrs=(ULONG)p;//HOOK地址
     Ret=(ULONG)p+5;//返回地址
    
     break;
    }
    p--;
  }
    DbgPrint("hookaddrs is %08X\n",hookaddrs);

   addr1=(ULONG)ps;
   addr=(ULONG)addr1-hookaddrs-5; //1个跳转
   addr2=(ULONG)MyHook1-addr1-5; //2个跳转
   *(ULONG*)(code+1)=addr; 
   *(ULONG*)(code1+1)=addr2; 
     WPOFF(); 
     Irql=KeRaiseIrqlToDpcLevel();
     RtlCopyMemory(hookaddrs,code,5); 
     RtlCopyMemory(addr1,code1,5); 
     KeLowerIrql(Irql);
      WPON();
      status=STATUS_SUCCESS; 
   }
   return status;
}
 第4步看下过滤函数
                 pushf
                 pusha
                 push    edi //SSDTADDR
                 push    ebx //服务函数地址
                 push    eax //SSDTINDEX
                 call    sub_191AC //过滤函数
                 mov     [esp+10h], eax
                 popa
                 popf
                 sub     esp, ecx
                 shr     ecx, 2
                 push    addbp4addr5
                 retn
  由于时间和篇幅关系文章先讲这么多先,等那天有空的时候继续写下过滤函数的处理,和360的建自己的
服务表的结构处理,和监控恢复HOOK的处理。此文章只是为了学习交流,如果此文章有错误的希望大牛门
指出和更正。共同学习 共同进步嘛
参考文章 教主的 分析360安全卫士的HOOK