发新话题
打印

[病毒杀软] [原创]hook KeAttachProcess防简单内存清0

[原创]hook KeAttachProcess防简单内存清0

信息来源:邪恶八进制信息安全团队(www.eviloctal.com
文章作者:asm(http://www.sbasm.cn/)

好久没写文章了,写篇简单的文章科普一下,大牛飘过 ^.^   

一个进程在运行的时候,很有可能另外一些程序挂靠,因此小小的hook一下KeAttachProcess,即可让挂靠无效,可防止一些内存清零来结束进程的办法。当然,KeAttachProcess-->KiAttachProcess,很多人不一定用KeAttachProcess,用KiAttachProcess也可以,但是出于方便,快捷,相信很多人会使用KeAttachProcess而不去使用一个没有导出的函数KiAttachProcess。当然还有很多更猥琐的内存清0的办法,那些办法已经不属于科普了
复制内容到剪贴板
代码:
lkd> u KeAttachProcess
nt!KeAttachProcess:
804f25a5 8bff            mov     edi,edi
804f25a7 55              push    ebp
804f25a8 8bec            mov     ebp,esp
804f25aa 56              push    esi
804f25ab 57              push    edi
804f25ac 64a124010000    mov     eax,dword ptr fs:[00000124h]  ; eax = 当前线程(ETHREAD)
804f25b2 8b7d08          mov     edi,dword ptr [ebp+8]         ; edi = 要切换的目标进程的(EPROCESS)
804f25b5 8bf0            mov     esi,eax

lkd> u 804f25b5
nt!KeAttachProcess+0x10:
804f25b5 8bf0            mov     esi,eax                     

;保存当前线程(ETHREAD)到 esi ,ETHREAD是个结构体,44h偏移刚好是: struct _KPROCESS *Process 也就是当前进程的EPROCESS

804f25b7 397e44          cmp     dword ptr [esi+44h],edi  ;如果是当前进程,就跳到返回处
804f25ba 7437            je      nt!KeAttachProcess+0x46 (804f25f3)


lkd> u 804f25ec
nt!KeAttachProcess+0x3f:
804f25ec 57              push    edi
804f25ed 56              push    esi
804f25ee e8defeffff      call    nt!KiAttachProcess (804f24d1)
804f25f3 5f              pop     edi                    <---------------------- 如果(804f25ba)处的判断无效的话,会跳到 (804f25f3),也就是挂靠失败。
804f25f4 5e              pop     esi
804f25f5 5d              pop     ebp
804f25f6 c20400          ret     4
804f25f9 90              nop
通过WRK看KeAttachProcess的源代码,也可以证实这点:
复制内容到剪贴板
代码:
VOID
KeAttachProcess (
    __inout PRKPROCESS Process
    )
/*++

Routine Description:

    This function attaches a thread to a target process' address space
    if, and only if, there is not already a process attached.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

Return Value:

    None.

--*/

{

    KLOCK_QUEUE_HANDLE LockHandle;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // If the target process is not the current process, then attach the
    // target process.
    //

    Thread = KeGetCurrentThread();
    if (Thread->ApcState.Process != Process) {

    .........................
    }

    return;
}
所以,我们做手脚的地方是:

804f25b5 8bf0            mov     esi,eax                     
804f25b7 397e44          cmp     dword ptr [esi+44h],edi

核心代码:
复制内容到剪贴板
代码:
欢迎光临我的小站:http://www.sbasm.cn/
__declspec(naked)void PatchCode()
{
        _asm
        {
                pushfd ;
                pushad ;            //保存所有寄存器,这里执行的原因是因为要加入下面3行代码,防止寄存器的值被改变

                mov  eax,Protection;
                cmp eax,edi;     //要切换的目标进程的EPROCESS是否跟我要保护的一样
                jnz No;
                popad;                                    //恢复所有寄存器,相当于原来函数当时的情况一样。
                popfd;
                mov     esi,eax;       //是我要保护的进程,替换为当前进程自己
                mov eax,dword ptr [esi+44h];
                cmp     dword ptr [esi+44h],eax;
                jmp [lpRet];       
No:                       //不是我要保护的进程,可以正常执行
                popad;           //恢复!
                popfd;
                mov     esi,eax;
                cmp     dword ptr [esi+44h],edi;
                jmp [lpRet];

        }

};

BOOL HookKeAttachProcess(BOOL bHook)
{
        BYTE jmpCode[5]={0xe9,0x00,0x00,0x00,0x00};
        BYTE oldCode[5]={0x8b,0xf0,0x39,0x7e,0x44};           //要patch的特征码,从这里得到地址
        BYTE *functionAddress;
        int i;
        KIRQL  oldirql;        //自旋锁用到的
        KIRQL  CurrentIRQL;        //基本上算是个临时变量,当前级别

        //申请自旋锁要在DISPATCH_LEVEL以下
        CurrentIRQL = KeGetCurrentIrql();
        if(CurrentIRQL <= DISPATCH_LEVEL)
        {        KeAcquireSpinLock(&WriteMyHook, &oldirql);        //自旋锁
        }

        RtlInitUnicodeString(&uProcessName,L"KeAttachProcess");
        functionAddress = MmGetSystemRoutineAddress(&uProcessName);  //因为KeAttachProcess被导出,所以直接MmGetSystemRoutineAddress就可以得到地址
        if (functionAddress == NULL)
        {
                DbgPrint("Get KeAttachProcess Address failed\n");
        }
        DbgPrint("KeAttachProcess Address is 0x%x\n",functionAddress);
       
        if(bHook)
        {
                for(i=0;i<264;i++)       //搜索
                {
                        if(memcmp(&functionAddress[i],oldCode,5) == 0)        //要patch的是否一样
                        {
                                patchAddress=(DWORD)&functionAddress[i];       //得到要patch的地址,即:804de980   
                                KdPrint(("patch address:%X\n",patchAddress));
                                break;
                        }
                }
                if(i==264)           //如果 i = 264的话,就说明没有搜索到 !
                {
                        if(CurrentIRQL <= DISPATCH_LEVEL)
                        {        KeReleaseSpinLock(&WriteMyHook, oldirql);//自旋锁释放
                        }
                        return FALSE;
                }

                *(DWORD*)&jmpCode[1]=(DWORD)PatchCode-(patchAddress+5);
                lpRet=(PVOID)(patchAddress+5);   //返回地址!
                _asm
                {
                        CLI  ;                 
                        MOV    EAX, CR0  ;   
                        AND EAX, NOT 10000H ;
                        MOV    CR0, EAX;        
                }
                memcpy((PVOID)patchAddress,jmpCode,5);
                _asm
                {
                        MOV    EAX, CR0;        
                        OR    EAX, 10000H;            
                        MOV    CR0, EAX ;              
                        STI;                    
                }

        }
        else        //卸载驱动的时候,恢复原来的函数
        {
                _asm
                {
                        CLI  ;                 
                        MOV    EAX, CR0  ;   
                        AND EAX, NOT 10000H ;
                        MOV    CR0, EAX;        
                }
                memcpy((PVOID)patchAddress,oldCode,5);
                _asm
                {
                        MOV    EAX, CR0;        
                        OR    EAX, 10000H;            
                        MOV    CR0, EAX ;              
                        STI;                    
                }

        }
         
        if(CurrentIRQL <= DISPATCH_LEVEL)
        {        KeReleaseSpinLock(&WriteMyHook, oldirql);//自旋锁释放
        }
        return TRUE;

}
函数被hook后,用windbg查看的效果:
复制内容到剪贴板
代码:
lkd> u KeAttachProcess
nt!KeAttachProcess:
804f25a5 8bff            mov     edi,edi
804f25a7 55              push    ebp
804f25a8 8bec            mov     ebp,esp
804f25aa 56              push    esi
804f25ab 57              push    edi
804f25ac 64a124010000    mov     eax,dword ptr fs:[00000124h]
804f25b2 8b7d08          mov     edi,dword ptr [ebp+8]
804f25b5 e9c6fc5877      jmp     f7a82280

lkd> u 804f25b5
nt!KeAttachProcess+0x10:
804f25b5 e9c6fc5877      jmp     f7a82280
804f25ba 7437            je      nt!KeAttachProcess+0x46 (804f25f3)
804f25bc 80be6501000000  cmp     byte ptr [esi+165h],0
804f25c3 0f8570030300    jne     nt!KeAttachProcess+0x4c (80522939)
804f25c9 64a194090000    mov     eax,dword ptr fs:[00000994h]
804f25cf 85c0            test    eax,eax
804f25d1 0f8562030300    jne     nt!KeAttachProcess+0x4c (80522939)
804f25d7 33c9            xor     ecx,ecx

lkd> u f7a82280
f7a82280 9c              pushfd
f7a82281 60              pushad
f7a82282 a10427a8f7      mov     eax,dword ptr ds:[F7A82704h]
f7a82287 3bc7            cmp     eax,edi
f7a82289 7510            jne     f7a8229b
f7a8228b 61              popad
f7a8228c 9d              popfd
f7a8228d 8bf0            mov     esi,eax

lkd> u f7a8228d
f7a8228d 8bf0            mov     esi,eax
f7a8228f 8b4644          mov     eax,dword ptr [esi+44h]
f7a82292 394644          cmp     dword ptr [esi+44h],eax
f7a82295 ff250827a8f7    jmp     dword ptr ds:[0F7A82708h]
f7a8229b 61              popad
f7a8229c 9d              popfd
f7a8229d 8bf0            mov     esi,eax
f7a8229f 397e44          cmp     dword ptr [esi+44h],edi

lkd> u f7a8229f
f7a8229f 397e44          cmp     dword ptr [esi+44h],edi
f7a822a2 ff250827a8f7    jmp     dword ptr ds:[0F7A82708h]
f7a822a8 cc              int     3
f7a822a9 cc              int     3
f7a822aa cc              int     3
f7a822ab cc              int     3
f7a822ac cc              int     3
f7a822ad cc              int     3
完整代码见压缩包 :)

思路扩展:是否能通过上级导出函数,定位下级未导出函数的地址  - -!
   
    还是这个例子中,因为:KeAttachProcess-->KiAttachProcess,所以上级导出函数为KeAttachProcess,下级未导出函数为KiAttachProcess。
    在KeAttachProcess的反汇编代码中,我们得知最终会调用到KiAttachProcess:
复制内容到剪贴板
代码:
lkd> u 804f25ec
nt!KeAttachProcess+0x3f:
804f25ec 57              push    edi
804f25ed 56              push    esi
804f25ee e8defeffff      call    nt!KiAttachProcess (804f24d1)
804f25f3 5f              pop     edi
804f25f4 5e              pop     esi
804f25f5 5d              pop     ebp
804f25f6 c20400          ret     4
804f25f9 90              nop
所以,只要以KeAttachProcess的地址为基址,根据特征码 BYTE Signature[5]={0xe8,0xde,0xfe,0xff,0xff};  即可搜索到即将调用KiAttachProcess函数的地址,即Call KiAttachProcess,然后根据Call KiAttachProcess来取得KiAttachProcess来取得KiAttachProcess的地址。。
欢迎光临我的小站:http://www.sbasm.cn/


PS:通过本文的科普内容,大家可以尝试弄一下inline hook KeStackAttachProcess来防止ReadProcessMemory等函数。

附件

HookKeAttachProcess.rar (48.77 KB)

2009-9-15 22:41, 下载次数: 838

本帖最近评分记录

TOP

单位不让上网,只能拿手机浏览一下,小屏幕看得眼疼,真郁闷。
众人都在假装正经,我唯有假装不正经了。

TOP

多日不见,asm功力增长神速啊。

TOP

好文章啊,收藏了~~~

TOP

发新话题