使用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;
}
由于反调试程序在后台运行,调试器将无法附加到任何其他进程:
辛苦,,,,感谢分享。。
页:
[1]