实现用句柄表反调试

句柄

句柄可以说是Windows编程的核心,当一个进程创建或者打开一个内核对象时,就会获得一个句柄,通过这个句柄可以访问内核对象

为什么要有句柄

句柄存在的目的是为了避免在应用层直接修改内核对象,句柄也就是内核对象中的一个索引,而内核对象存放在句柄表中

句柄表的位置

在_EPROCESS中,有一个成员叫ObjectTable,offset为c4

 

 

其指向了一个_HANDLE_TABLE结构体

ntdll!_HANDLE_TABLE
   +0x000 TableCode        : Uint4B
   +0x004 QuotaProcess     : Ptr32 _EPROCESS
   +0x008 UniqueProcessId  : Ptr32 Void
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : Ptr32 _HANDLE_TRACE_DEBUG_INFO
   +0x02c ExtraInfoPages   : Int4B
   +0x030 FirstFree        : Uint4B
   +0x034 LastFree         : Uint4B
   +0x038 NextHandleNeedingPool : Uint4B
   +0x03c HandleCount      : Int4B
   +0x040 Flags            : Uint4B
   +0x040 StrictFIFO       : Pos 0, 1 Bit

在offset 为0的地方 他指向的就是句柄表

句柄表结构

而这个指针的值,最后两位代表的是多少等级的句柄表,也就是如下

 

 句柄表中,句柄大小是4字节,但是却需要占8个字节(Windows就是这么设计的),如果是0级句柄表,那就是512个条目,如果是1级句柄表,那就是512*1024,因为一个句柄表大小为4k,然候0级句柄表的每个条目指向的也是一个句柄表,此时的0级句柄表的条目只需要4个字节,因为当成了索引

句柄表项

由于句柄大小为8字节,在内存中我们通过Handle/4得到句柄在句柄表中的序号,然后在通过TableCode+(Handle/4)*8得到其句柄表项,其中句柄表项的属性如下

 

 也就是说,当我们有一个进程打开了一个进程时,他的句柄表中,会有另一个进程的句柄,此时我们遍历所有进程的句柄表,查看是否有自身,即可验证自己是否被调试

遍历句柄表实现反调试

我们已经知道句柄表了,那么如果调试器要调试程序,就肯定要打开那个程序,通过OpenProcess来获取程序的句柄,那么其对应的句柄表,肯定有这个值,所以我们可以根据这个特性来反调试

所以思路是:遍历所有其他进程句柄表,看哪个进程的句柄表中保护自己的进程,如果有,说明正在被调试。

这里我监视的是notepad.exe是否有调试程序

#include <ntddk.h>
#include <ntstatus.h>

ULONG GetProcessEprocess(char* ProcessName)
{
    PEPROCESS pEprocess,pCurEProcess;
    //获取进程的EProcess
    __asm
    {
        mov eax,fs:[0x124]
        mov eax,[eax+0x220]
        mov pEprocess,eax
    }

    pCurEProcess=pEprocess;
    do
    {
        PCHAR ImageFileName=(PCHAR)pCurEProcess+0x174;
        if(strcmp(ImageFileName,ProcessName)==0)
        {
            return (ULONG)pCurEProcess;
        }
        pCurEProcess=(PEPROCESS)(*(PULONG)((ULONG)pCurEProcess+0x88)-0x88);
    }while(pCurEProcess!=pEprocess);
    return 0;
}

BOOLEAN CheckProcessDebug(ULONG CheckedProcess)
{
    PEPROCESS pEprocess,pCurEProcess;
    PULONG table;
    PEPROCESS eps;
    ULONG ObTable;
    int i,j,k;
    //获取进程的EProcess
    __asm
    {
        mov eax,fs:[0x124]
        mov eax,[eax+0x220]
        mov pEprocess,eax
    }
    DbgPrint("开始检查\n");
    pCurEProcess=pEprocess;
    do
    {
        PCHAR ImageFileName=(PCHAR)pCurEProcess+0x174;
        ULONG ObjectTable=*(PULONG)((ULONG)pCurEProcess+0xc4);

        if(ObjectTable!=0)
        {
            DbgPrint("[%s]\t[%s]\t[%x]\t[%x]\n",ImageFileName,((PCHAR)CheckedProcess+0x174),ObjectTable,CheckedProcess);
            ObTable=(ULONG)ObjectTable;
            switch(ObTable&0x3)
            {
            case 0:
                table=(PULONG)((*(PULONG)ObTable)&0xfffffffc);
                for(i=0;i<512;i+=2)
                {
                    eps=(PEPROCESS)((table[i]&0xfffffff8)+0x18);
                    //DbgPrint("程序正在被 [%x] 检查!\n", (ULONG)eps);
                    if(strcmp(ImageFileName,"csrss.exe")!=0&&eps==(PEPROCESS)CheckedProcess)
                    {
                        DbgPrint("程序正在被 [%s] 调试!\n", ImageFileName);
                        return TRUE;
                    }
                }

                break;
            case 1:
                for(i=0;i<1024;i++)
                {
                    table=(PULONG)(*(PULONG)ObTable)+i;
                    if(MmIsAddressValid((PVOID)table))
                    for(j=0;j<512;j++)
                    {
                        eps=(PEPROCESS)((ULONG)(table+j*2)&0xfffffff8+0x18);
                        DbgPrint("程序正在被 [%s] 检查!\n", (PCHAR)eps+0x174);
                        if(eps==(PEPROCESS)CheckedProcess)
                        {
                            DbgPrint("程序正在被 [%s] 调试!\n", ImageFileName);
                            return TRUE;
                        }
                    }
                }
                break;
            case 2:
                for(i=0;i<1024;i++)
                {
                    table=(PULONG)(*(PULONG)ObTable)+i;
                    if(MmIsAddressValid((PVOID)table))
                    for(j=0;j<1024;j++)
                    {
                        table=(PULONG)(*(PULONG)ObTable)+j;
                        if(MmIsAddressValid((PVOID)table))
                        for(k=0;k<512;k++)
                        {
                            eps=(PEPROCESS)((ULONG)(table+k*2)&0xfffffff8+0x18);
                            DbgPrint("程序正在被 [%s] 检查!\n", (PCHAR)eps+0x174);
                            if(eps==(PEPROCESS)CheckedProcess)
                            {
                                DbgPrint("程序正在被 [%s] 调试!\n", ImageFileName);
                                return TRUE;
                            }
                        }
                    }
                }
                break;
            default:
                DbgPrint("No Pass");
            }

        }
        pCurEProcess=(PEPROCESS)(*(PULONG)((ULONG)pCurEProcess+0x88)-0x88);
    }while(pCurEProcess!=pEprocess);
    DbgPrint("Processing is not debug");
    return FALSE;
}
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
    DbgPrint("Driver unloaded.\n");
    
}



NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
    ULONG addr;
    pDriver->DriverUnload = DriverUnload;
    //获取需要保护的进程的EProcess
    addr=GetProcessEprocess("notepad.exe");
    DbgPrint("程序正在被 [%d] 调试!\n", addr);
    CheckProcessDebug(addr);
    return STATUS_SUCCESS;
}

 

posted @ 2021-01-14 15:05  PYozo_free  阅读(271)  评论(0编辑  收藏  举报