飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 1334|回复: 1

[C/C++] 使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2022-2-16 16:53:28 | 显示全部楼层 |阅读模式
    翻译
    原文地址:https://www.x86matthew.com/view_post?id=system_anti_debug
    功能:使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术
    我开发了一种反调试技术,它不加区别地针对用户模式调试器,而不是检测是否有个别进程被调试。



    总的来说,这种方法的工作原理如下:
    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手动关闭这个临时调试句柄。
    下面是完整的程序代码:
    1. #include <stdio.h>
    2. #include <windows.h>

    3. #define SystemExtendedHandleInformation 64
    4. #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

    5. struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
    6. {
    7.     ULONG Object;
    8.     ULONG UniqueProcessId;  
    9.     ULONG HandleValue;  
    10.     ULONG GrantedAccess;
    11.     USHORT CreatorBackTraceIndex;
    12.     USHORT ObjectTypeIndex;
    13.     ULONG HandleAttributes;
    14.     ULONG Reserved;
    15. };

    16. struct SYSTEM_HANDLE_INFORMATION_EX
    17. {
    18.         ULONG NumberOfHandles;
    19.         ULONG Reserved;
    20.         SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleList[1];
    21. };

    22. SYSTEM_HANDLE_INFORMATION_EX *pGlobal_SystemHandleInfo = NULL;
    23. DWORD dwGlobal_DebugObjectType = 0;

    24. DWORD GetSystemHandleList()
    25. {
    26.         DWORD (WINAPI *NtQuerySystemInformation)(DWORD SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
    27.         DWORD dwAllocSize = 0;
    28.         DWORD dwStatus = 0;
    29.         DWORD dwLength = 0;
    30.         BYTE *pSystemHandleInfoBuffer = NULL;

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

    37.         // free previous handle info list (if one exists)
    38.         if(pGlobal_SystemHandleInfo != NULL)
    39.         {
    40.                 free(pGlobal_SystemHandleInfo);
    41.         }

    42.         // get system handle list
    43.         dwAllocSize = 0;
    44.         for(;;)
    45.         {
    46.                 if(pSystemHandleInfoBuffer != NULL)
    47.                 {
    48.                         // free previous inadequately sized buffer
    49.                         free(pSystemHandleInfoBuffer);
    50.                         pSystemHandleInfoBuffer = NULL;
    51.                 }

    52.                 if(dwAllocSize != 0)
    53.                 {
    54.                         // allocate new buffer
    55.                         pSystemHandleInfoBuffer = (BYTE*)malloc(dwAllocSize);
    56.                         if(pSystemHandleInfoBuffer == NULL)
    57.                         {
    58.                                 return 1;
    59.                         }
    60.                 }

    61.                 // get system handle list
    62.                 dwStatus = NtQuerySystemInformation(SystemExtendedHandleInformation, (void*)pSystemHandleInfoBuffer, dwAllocSize, &dwLength);
    63.                 if(dwStatus == 0)
    64.                 {
    65.                         // success
    66.                         break;
    67.                 }
    68.                 else if(dwStatus == STATUS_INFO_LENGTH_MISMATCH)
    69.                 {
    70.                         // not enough space - allocate a larger buffer and try again (also add an extra 1kb to allow for additional handles created between checks)
    71.                         dwAllocSize = (dwLength + 1024);
    72.                 }
    73.                 else
    74.                 {
    75.                         // other error
    76.                         free(pSystemHandleInfoBuffer);
    77.                         return 1;
    78.                 }
    79.         }

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

    82.         return 0;
    83. }

    84. DWORD GetDebugHandleObjectType(DWORD *pdwDebugObjectType)
    85. {
    86.         DWORD dwHandleTypeList[128];
    87.         DWORD dwHandleTypeCount = 0;
    88.         DWORD dwCurrentHandleTypeAlreadyExists = 0;
    89.         DWORD dwDebugObjectType = 0;
    90.         DWORD dwFoundDebugObjectType = 0;

    91.         // get initial handle list
    92.         if(GetSystemHandleList() != 0)
    93.         {
    94.                 return 1;
    95.         }

    96.         // store a list of handle types for this process
    97.         for(DWORD i = 0; i < pGlobal_SystemHandleInfo->NumberOfHandles; i++)
    98.         {
    99.                 // check if this handle is for the current process
    100.                 if(pGlobal_SystemHandleInfo->HandleList[i].UniqueProcessId != GetCurrentProcessId())
    101.                 {
    102.                         continue;
    103.                 }

    104.                 // check if this handle type already exists in the list
    105.                 dwCurrentHandleTypeAlreadyExists = 0;
    106.                 for(DWORD ii = 0; ii < dwHandleTypeCount; ii++)
    107.                 {
    108.                         if(dwHandleTypeList[ii] == pGlobal_SystemHandleInfo->HandleList[i].ObjectTypeIndex)
    109.                         {
    110.                                 dwCurrentHandleTypeAlreadyExists = 1;
    111.                                 break;
    112.                         }
    113.                 }

    114.                 // ignore if this handle type already exists in the list
    115.                 if(dwCurrentHandleTypeAlreadyExists != 0)
    116.                 {
    117.                         continue;
    118.                 }

    119.                 // add this handle type to the list
    120.                 if(dwHandleTypeCount >= (sizeof(dwHandleTypeList) / sizeof(DWORD)))
    121.                 {
    122.                         // not enough space in the list
    123.                         return 1;
    124.                 }
    125.                 dwHandleTypeList[dwHandleTypeCount] = pGlobal_SystemHandleInfo->HandleList[i].ObjectTypeIndex;
    126.                 dwHandleTypeCount++;
    127.         }

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

    130.         // get the latest handle list
    131.         if(GetSystemHandleList() != 0)
    132.         {
    133.                 return 1;
    134.         }

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

    143.                 // check if this handle type already existed before creating the debug handle
    144.                 dwCurrentHandleTypeAlreadyExists = 0;
    145.                 for(DWORD ii = 0; ii < dwHandleTypeCount; ii++)
    146.                 {
    147.                         if(dwHandleTypeList[ii] == pGlobal_SystemHandleInfo->HandleList[i].ObjectTypeIndex)
    148.                         {
    149.                                 dwCurrentHandleTypeAlreadyExists = 1;
    150.                                 break;
    151.                         }
    152.                 }

    153.                 if(dwCurrentHandleTypeAlreadyExists == 0)
    154.                 {
    155.                         // found the debug handle - store the object type
    156.                         dwFoundDebugObjectType = 1;
    157.                         dwDebugObjectType = pGlobal_SystemHandleInfo->HandleList[i].ObjectTypeIndex;

    158.                         // close the debug handle
    159.                         CloseHandle((HANDLE)pGlobal_SystemHandleInfo->HandleList[i].HandleValue);

    160.                         break;
    161.                 }
    162.         }

    163.         // ensure the debug handle type was found
    164.         if(dwFoundDebugObjectType == 0)
    165.         {
    166.                 return 1;
    167.         }

    168.         // store debug object type
    169.         *pdwDebugObjectType = dwDebugObjectType;

    170.         return 0;
    171. }

    172. DWORD CheckForDebuggerProcess(DWORD *pdwFoundDebugger, DWORD *pdwDebuggerPID, HANDLE *phRemoteDebugHandle)
    173. {
    174.         DWORD dwFoundDebugger = 0;
    175.         DWORD dwDebuggerPID = 0;
    176.         HANDLE hRemoteDebugHandle = NULL;

    177.         // get system handle list
    178.         if(GetSystemHandleList() != 0)
    179.         {
    180.                 return 1;
    181.         }

    182.         // check for debug handles
    183.         for(DWORD i = 0; i < pGlobal_SystemHandleInfo->NumberOfHandles; i++)
    184.         {
    185.                 if(pGlobal_SystemHandleInfo->HandleList[i].ObjectTypeIndex == dwGlobal_DebugObjectType)
    186.                 {
    187.                         // found a debugger - store PID
    188.                         dwFoundDebugger = 1;
    189.                         dwDebuggerPID = pGlobal_SystemHandleInfo->HandleList[i].UniqueProcessId;
    190.                         hRemoteDebugHandle = (HANDLE)pGlobal_SystemHandleInfo->HandleList[i].HandleValue;

    191.                         break;
    192.                 }
    193.         }

    194.         // store values
    195.         *pdwFoundDebugger = dwFoundDebugger;
    196.         *pdwDebuggerPID = dwDebuggerPID;
    197.         *phRemoteDebugHandle = hRemoteDebugHandle;

    198.         return 0;
    199. }

    200. int main()
    201. {
    202.         HANDLE hDebuggerProcess = NULL;
    203.         HANDLE hRemoteDebugHandle = NULL;
    204.         HANDLE hClonedDebugHandle = NULL;
    205.         DWORD dwFoundDebugger = 0;
    206.         DWORD dwDebuggerPID = 0;

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

    208.         // find the debug handle object type
    209.         if(GetDebugHandleObjectType(&dwGlobal_DebugObjectType) != 0)
    210.         {
    211.                 return 1;
    212.         }

    213.         // wait for a debugger
    214.         for(;;)
    215.         {
    216.                 // check if a debugger is currently running on the system
    217.                 if(CheckForDebuggerProcess(&dwFoundDebugger, &dwDebuggerPID, &hRemoteDebugHandle) != 0)
    218.                 {
    219.                         return 1;
    220.                 }

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

    226.                         // open debugger process
    227.                         hDebuggerProcess = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDebuggerPID);
    228.                         if(hDebuggerProcess == NULL)
    229.                         {
    230.                                 // failed to open process handle
    231.                                 printf("Failed to open debugger process - PID: %u\n", dwDebuggerPID);
    232.                         }
    233.                         else
    234.                         {
    235.                                 // close debugger handle from remote process and terminate the original handle
    236.                                 if(DuplicateHandle(hDebuggerProcess, hRemoteDebugHandle, GetCurrentProcess(), &hClonedDebugHandle, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE) == 0)
    237.                                 {
    238.                                         // failed to duplicate handle
    239.                                         printf("Failed to kill debugger - PID: %u\n", dwDebuggerPID);
    240.                                 }
    241.                                 else
    242.                                 {
    243.                                         // closed the target handle in the remote process successfully
    244.                                         printf("Killed debugger successfully - PID: %u\n", dwDebuggerPID);

    245.                                         // close local (cloned) debug handle
    246.                                         CloseHandle(hClonedDebugHandle);
    247.                                 }

    248.                                 // close debugger process handle
    249.                                 CloseHandle(hDebuggerProcess);
    250.                         }
    251.                 }

    252.                 // wait 500ms before searching again
    253.                 Sleep(500);
    254.         }

    255.         return 0;
    256. }
    复制代码

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

    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2024-2-17 21:14
  • 签到天数: 1886 天

    [LV.Master]伴坛终老

    发表于 2022-2-19 08:17:09 | 显示全部楼层
    辛苦,,,,感谢分享。。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表