首页
社区
课程
招聘
[翻译]使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术
发表于: 2022-2-16 16:50 16811

[翻译]使用NtQuerySystemInformation和DuplicateHandle的系统级反调试技术

2022-2-16 16:50
16811

翻译

原文地址: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手动关闭这个临时调试句柄。

下面是完整的程序代码:

#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[1];
};

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[128];
	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[i].UniqueProcessId != GetCurrentProcessId())
		{
			continue;
		}

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

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

			// close the debug handle
			CloseHandle((HANDLE)pGlobal_SystemHandleInfo->HandleList[i].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[i].ObjectTypeIndex == dwGlobal_DebugObjectType)
		{
			// found a debugger - store PID
			dwFoundDebugger = 1;
			dwDebuggerPID = pGlobal_SystemHandleInfo->HandleList[i].UniqueProcessId;
			hRemoteDebugHandle = (HANDLE)pGlobal_SystemHandleInfo->HandleList[i].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;
}

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


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 5
支持
分享
最新回复 (2)
雪    币: 345
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
好像在x64环境下会出现问题,不知道怎么解决
2022-3-11 14:43
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
AlphaYang 好像在x64环境下会出现问题,不知道怎么解决
他的那个结构体定义的有问题64位下很多值都要使用ULONG_PTR 而不是 ULONG
2022-5-20 06:54
0
游客
登录 | 注册 方可回帖
返回
//