梦幻的彼岸 发表于 2022-2-16 16:53:28

使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术

翻译
原文地址:https://www.x86matthew.com/view_post?id=system_anti_debug
功能:使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术
我开发了一种反调试技术,它不加区别地针对用户模式调试器,而不是检测是否有个别进程被调试。

static/image/hrline/1.gif

总的来说,这种方法的工作原理如下:
1. 使用带有SystemExtendedHandleInformation的NtQuerySystemInformation检索系统中所有打开的句柄列表。
2. 检查是否有进程包含一个活动的调试句柄。
3. 使用带有DUPLICATE_CLOSE_SOURCE标志的DuplicateHandle终止远程进程中的这个句柄。
4. 循环回到步骤#1。
使上述方法复杂化的一件事是在步骤2中识别调试句柄。每个句柄的类型都是通过NtQuerySystemInformation返回的ObjectTypeIndex字段来识别的,但这个值在不同版本的Windows中并不一致。

我们显然可以在一个查找表中硬编码各种可能的值,但通用的解决方案总是更好的。为了计算出当前操作系统的调试手柄类型索引,我采取了以下步骤:
1. 使用带有SystemExtendedHandleInformation的NtQuerySystemInformation检索系统中所有打开的句柄列表。
2. 为当前进程中发现的每个独特的对象类型设置一个标志(例如文件句柄、进程句柄、注册表键等)。
3. 调用PID为0的DebugActiveProcess。即使目标PID无效,DebugActiveProcess也会在当前进程中创建一个内部调试句柄。即使调用失败,该调试句柄也保持原位。
3. 重复步骤#1。
4. 循环浏览当前进程的最新句柄列表,并寻找在步骤#2中没有标记的对象类型的条目。假设这是一个单线程的应用程序,我们知道这将是之前由DebugActiveProcess创建的调试句柄。我们可以从这个条目的ObjectTypeIndex字段中提取调试句柄类型。
5. 使用CloseHandle手动关闭这个临时调试句柄。
下面是完整的程序代码:
#include <stdio.h>
#include <windows.h>

#define SystemExtendedHandleInformation 64
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
{
    ULONG Object;
    ULONG UniqueProcessId;
    ULONG HandleValue;
    ULONG GrantedAccess;
    USHORT CreatorBackTraceIndex;
    USHORT ObjectTypeIndex;
    ULONG HandleAttributes;
    ULONG Reserved;
};

struct SYSTEM_HANDLE_INFORMATION_EX
{
        ULONG NumberOfHandles;
        ULONG Reserved;
        SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleList;
};

SYSTEM_HANDLE_INFORMATION_EX *pGlobal_SystemHandleInfo = NULL;
DWORD dwGlobal_DebugObjectType = 0;

DWORD GetSystemHandleList()
{
        DWORD (WINAPI *NtQuerySystemInformation)(DWORD SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
        DWORD dwAllocSize = 0;
        DWORD dwStatus = 0;
        DWORD dwLength = 0;
        BYTE *pSystemHandleInfoBuffer = NULL;

        // get NtQuerySystemInformation function ptr
        NtQuerySystemInformation = (unsigned long (__stdcall *)(unsigned long,void *,unsigned long,unsigned long *))GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
        if(NtQuerySystemInformation == NULL)
        {
                return 1;
        }

        // free previous handle info list (if one exists)
        if(pGlobal_SystemHandleInfo != NULL)
        {
                free(pGlobal_SystemHandleInfo);
        }

        // get system handle list
        dwAllocSize = 0;
        for(;;)
        {
                if(pSystemHandleInfoBuffer != NULL)
                {
                        // free previous inadequately sized buffer
                        free(pSystemHandleInfoBuffer);
                        pSystemHandleInfoBuffer = NULL;
                }

                if(dwAllocSize != 0)
                {
                        // allocate new buffer
                        pSystemHandleInfoBuffer = (BYTE*)malloc(dwAllocSize);
                        if(pSystemHandleInfoBuffer == NULL)
                        {
                                return 1;
                        }
                }

                // get system handle list
                dwStatus = NtQuerySystemInformation(SystemExtendedHandleInformation, (void*)pSystemHandleInfoBuffer, dwAllocSize, &dwLength);
                if(dwStatus == 0)
                {
                        // success
                        break;
                }
                else if(dwStatus == STATUS_INFO_LENGTH_MISMATCH)
                {
                        // not enough space - allocate a larger buffer and try again (also add an extra 1kb to allow for additional handles created between checks)
                        dwAllocSize = (dwLength + 1024);
                }
                else
                {
                        // other error
                        free(pSystemHandleInfoBuffer);
                        return 1;
                }
        }

        // store handle info ptr
        pGlobal_SystemHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX*)pSystemHandleInfoBuffer;

        return 0;
}

DWORD GetDebugHandleObjectType(DWORD *pdwDebugObjectType)
{
        DWORD dwHandleTypeList;
        DWORD dwHandleTypeCount = 0;
        DWORD dwCurrentHandleTypeAlreadyExists = 0;
        DWORD dwDebugObjectType = 0;
        DWORD dwFoundDebugObjectType = 0;

        // get initial handle list
        if(GetSystemHandleList() != 0)
        {
                return 1;
        }

        // store a list of handle types for this process
        for(DWORD i = 0; i < pGlobal_SystemHandleInfo->NumberOfHandles; i++)
        {
                // check if this handle is for the current process
                if(pGlobal_SystemHandleInfo->HandleList.UniqueProcessId != GetCurrentProcessId())
                {
                        continue;
                }

                // check if this handle type already exists in the list
                dwCurrentHandleTypeAlreadyExists = 0;
                for(DWORD ii = 0; ii < dwHandleTypeCount; ii++)
                {
                        if(dwHandleTypeList == pGlobal_SystemHandleInfo->HandleList.ObjectTypeIndex)
                        {
                                dwCurrentHandleTypeAlreadyExists = 1;
                                break;
                        }
                }

                // ignore if this handle type already exists in the list
                if(dwCurrentHandleTypeAlreadyExists != 0)
                {
                        continue;
                }

                // add this handle type to the list
                if(dwHandleTypeCount >= (sizeof(dwHandleTypeList) / sizeof(DWORD)))
                {
                        // not enough space in the list
                        return 1;
                }
                dwHandleTypeList = pGlobal_SystemHandleInfo->HandleList.ObjectTypeIndex;
                dwHandleTypeCount++;
        }

        // DebugActiveProcess will create a debug handle for this process, even if the pid is invalid
        DebugActiveProcess(0);

        // get the latest handle list
        if(GetSystemHandleList() != 0)
        {
                return 1;
        }

        // compare against the old list to find the newly created debug handle type
        for(i = 0; i < pGlobal_SystemHandleInfo->NumberOfHandles; i++)
        {
                // check if this handle is for the current process
                if(pGlobal_SystemHandleInfo->HandleList.UniqueProcessId != GetCurrentProcessId())
                {
                        continue;
                }

                // check if this handle type already existed before creating the debug handle
                dwCurrentHandleTypeAlreadyExists = 0;
                for(DWORD ii = 0; ii < dwHandleTypeCount; ii++)
                {
                        if(dwHandleTypeList == pGlobal_SystemHandleInfo->HandleList.ObjectTypeIndex)
                        {
                                dwCurrentHandleTypeAlreadyExists = 1;
                                break;
                        }
                }

                if(dwCurrentHandleTypeAlreadyExists == 0)
                {
                        // found the debug handle - store the object type
                        dwFoundDebugObjectType = 1;
                        dwDebugObjectType = pGlobal_SystemHandleInfo->HandleList.ObjectTypeIndex;

                        // close the debug handle
                        CloseHandle((HANDLE)pGlobal_SystemHandleInfo->HandleList.HandleValue);

                        break;
                }
        }

        // ensure the debug handle type was found
        if(dwFoundDebugObjectType == 0)
        {
                return 1;
        }

        // store debug object type
        *pdwDebugObjectType = dwDebugObjectType;

        return 0;
}

DWORD CheckForDebuggerProcess(DWORD *pdwFoundDebugger, DWORD *pdwDebuggerPID, HANDLE *phRemoteDebugHandle)
{
        DWORD dwFoundDebugger = 0;
        DWORD dwDebuggerPID = 0;
        HANDLE hRemoteDebugHandle = NULL;

        // get system handle list
        if(GetSystemHandleList() != 0)
        {
                return 1;
        }

        // check for debug handles
        for(DWORD i = 0; i < pGlobal_SystemHandleInfo->NumberOfHandles; i++)
        {
                if(pGlobal_SystemHandleInfo->HandleList.ObjectTypeIndex == dwGlobal_DebugObjectType)
                {
                        // found a debugger - store PID
                        dwFoundDebugger = 1;
                        dwDebuggerPID = pGlobal_SystemHandleInfo->HandleList.UniqueProcessId;
                        hRemoteDebugHandle = (HANDLE)pGlobal_SystemHandleInfo->HandleList.HandleValue;

                        break;
                }
        }

        // store values
        *pdwFoundDebugger = dwFoundDebugger;
        *pdwDebuggerPID = dwDebuggerPID;
        *phRemoteDebugHandle = hRemoteDebugHandle;

        return 0;
}

int main()
{
        HANDLE hDebuggerProcess = NULL;
        HANDLE hRemoteDebugHandle = NULL;
        HANDLE hClonedDebugHandle = NULL;
        DWORD dwFoundDebugger = 0;
        DWORD dwDebuggerPID = 0;

        printf("SystemAntiDebug - www.x86matthew.com\n\n");

        // find the debug handle object type
        if(GetDebugHandleObjectType(&dwGlobal_DebugObjectType) != 0)
        {
                return 1;
        }

        // wait for a debugger
        for(;;)
        {
                // check if a debugger is currently running on the system
                if(CheckForDebuggerProcess(&dwFoundDebugger, &dwDebuggerPID, &hRemoteDebugHandle) != 0)
                {
                        return 1;
                }

                // check if a debugger was found
                if(dwFoundDebugger != 0)
                {
                        // found a debugger
                        printf("Found debugger - PID: %u\n", dwDebuggerPID);

                        // open debugger process
                        hDebuggerProcess = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDebuggerPID);
                        if(hDebuggerProcess == NULL)
                        {
                                // failed to open process handle
                                printf("Failed to open debugger process - PID: %u\n", dwDebuggerPID);
                        }
                        else
                        {
                                // close debugger handle from remote process and terminate the original handle
                                if(DuplicateHandle(hDebuggerProcess, hRemoteDebugHandle, GetCurrentProcess(), &hClonedDebugHandle, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE) == 0)
                                {
                                        // failed to duplicate handle
                                        printf("Failed to kill debugger - PID: %u\n", dwDebuggerPID);
                                }
                                else
                                {
                                        // closed the target handle in the remote process successfully
                                        printf("Killed debugger successfully - PID: %u\n", dwDebuggerPID);

                                        // close local (cloned) debug handle
                                        CloseHandle(hClonedDebugHandle);
                                }

                                // close debugger process handle
                                CloseHandle(hDebuggerProcess);
                        }
                }

                // wait 500ms before searching again
                Sleep(500);
        }

        return 0;
}
由于反调试程序在后台运行,调试器将无法附加到任何其他进程:

雷破天 发表于 2022-2-19 08:17:09

辛苦,,,,感谢分享。。
页: [1]
查看完整版本: 使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术