【游戏逆向】常用反调试技术集合

这篇文章介绍了多种用于检测进程是否被调试器附着的技术,包括检查NtGlobalFlags字段、IsDebuggerPresent函数、CheckRemoteDebuggerPresent函数、rdtsc指令、0xCC中断、异常过滤器以及NtQueryInformationProcess方法。每种方法都涉及不同的系统机制,并且提供了一些示例代码来说明其工作原理。
摘要由CSDN通过智能技术生成

#include

#include

#include //NtSetInformationThreadApproach,NtQueryInformationProcessApproach 需要此头

/*********************************************************************************

*Function:NtGlobalFlags //函数名称

*Description:查询进程环境块(PEB) //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回true时检测到调试器,否则无调试器。 //函数返回值的说明

*Others:Z

NtGlobalFlag字段位于PEB(进程环境块)0x68的偏移处,//其他说明

64位机器则是在偏移0xBC位置.该字段的默认值为0。

当调试器正在运行时, 该字段会被设置为一个特定的值.

绕过这种检测的方法十分简单,调试时将其值置0即可,不建议使用。

**********************************************************************************/

bool NtGlobalFlags()

{

__asm

{

mov eax, fs:[30h]

mov eax, [eax + 68h]

and eax, 0x70

test eax, eax

jne rt_label

jmp rf_label

}

rt_label:

return true;

rf_label:

return false;

}

/*********************************************************************************

*Function:IsDebuggerPresent //函数名称

*Description:查询进程环境块(PEB)IsDebugged标志。//函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回非零时检测到调试器,否则无调试器。 //函数返回值的说明

*Others:破解方法同样调试时将其值置0即可 //其他说明

**********************************************************************************/

BOOL CheckDebug_Is()

{

return IsDebuggerPresent();

}

/*********************************************************************************

*Function:CheckRemoteDebuggerPresent //函数名称

*Description:查询进程环境块(PEB)IsDebugged标志。//函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回非零时检测到调试器,否则无调试器。 //函数返回值的说明

*Others:它不仅可以探测系统其他进程是否被调试, //其他说明

通过传递自身进程句柄还可以探测自身是否被调试。

同IsDebuggerPresent几乎一致。

**********************************************************************************/

BOOL CheckDebug_CRDP()

{

BOOL ret;

CheckRemoteDebuggerPresent(GetCurrentProcess(), &ret);

return ret;

}

/*********************************************************************************

*Function:CheckDebug_rdtsc //函数名称

*Description:使用 rdtsc 指令的时钟检测。 //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回非零时检测到调试器,否则无调试器。 //函数返回值的说明

*Others:被调试时,进程的运行速度大大降低, //其他说明

利用rdtsc指令(操作码0x0F31),它返回至系统重新启动以来的时钟数,

并且将其作为一个64位的值存入EDX:EAX中。恶意代码运行两次rdtsc指令,

然后比较两次读取之间的差值。时间戳如果存在滞后,则可以认为存在调试器。

**********************************************************************************/

BOOL CheckDebug_rdtsc()

{

DWORD time1, time2;

__asm

{

rdtsc

mov time1, eax

rdtsc

mov time2, eax

}

if (time2 - time1 < 0xff)

{

return FALSE;

}

else

{

return TRUE;

}

}

/*********************************************************************************

*Function:CheckDebug_0xCC //函数名称

*Description:触发调试器中断 //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回非零时触发中断成功,否则无调试器。 //函数返回值的说明

*Others:因为调试器使用INT 3来设置软件断点,插入 //其他说明

0xCC(INT 3)欺骗调试器使其认为这些0xCC机器码是自己设置的断点。

**********************************************************************************/

BOOL CheckDebug_0xCC()

{

__try

{

__asm int 3

}

__except (1)

{

return FALSE;

}

return TRUE;

}

/*********************************************************************************

*Function:AD_SetUnhandledExceptionFilter //函数名称

*Description:异常-SetUnhandledExceptionFilter //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:调试中将异常抛给调试器,否则无调试器。 //函数返回值的说明

*Others:已经通过测试,无调试器返回0 //其他说明

**********************************************************************************/

LPVOID g_pOrgFilter = 0;

LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS pExcept)

{

SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)g_pOrgFilter);

// 8900 MOV DWORD PTR DS:[EAX], EAX

// FFE0 JMP EAX

pExcept->ContextRecord->Eip += 4;

return EXCEPTION_CONTINUE_EXECUTION;

}

BOOL AD_SetUnhandledExceptionFilter()

{

//SetUnhandledExceptionFilter()来注册新的Top Level Exception Filter回调函数。

//触发异常时,系统在前面没有处理异常的情况下,会调用Kernel32.dll中的

//UnhandledExceptionFilter()函数。UnhandledExceptionFilter()会利用

//ntdll.dll中的NtQueryInformationProcess()来判断是否被调试,

//若判断在被调试,异常给调试器(调试器无法处理异常,进程终止)。

//若判断未被调试,则调用Top Level Exception Filter回调函数。

g_pOrgFilter = (LPVOID)SetUnhandledExceptionFilter(

(LPTOP_LEVEL_EXCEPTION_FILTER)ExceptionFilter);

__asm {

xor eax, eax;

mov dword ptr[eax], eax

jmp eax

}

return FALSE;

}

/*********************************************************************************

*Function:NtQueryInformationProcessApproach //函数名称

*Description: 检查进程调试 //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:进程被调试返回 -1 值端口,否则非。 //函数返回值的说明

*Others:已经通过测试,非公开函数。 //其他说明

它的第二个参数可以用来查询进程的调试端口,需要

使用LoadLibrary和GetProceAddress的方法获取调用地址

**********************************************************************************/

typedef NTSTATUS(WINAPI *NtQueryInformationProcessPtr)(

HANDLE processHandle,

PROCESSINFOCLASS processInformationClass,

PVOID processInformation,

ULONG processInformationLength,

PULONG returnLength);

bool NtQueryInformationProcessApproach()

{

int debugPort = 0;

HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll "));

NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hModule, “NtQueryInformationProcess”);

if (NtQueryInformationProcess(GetCurrentProcess(), (PROCESSINFOCLASS)7, &debugPort, sizeof(debugPort), NULL))

printf(“[ERROR NtQueryInformationProcessApproach] NtQueryInformationProcess failed\n”);//调用失败

else

return debugPort == -1;

return false;

}

/*********************************************************************************

*Function:CloseHandleException //函数名称

*Description: 仅在调试器下运行时产生无效句柄 //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return:返回非零为调试器存在。 //函数返回值的说明

*Others:已经通过测试,查找传递给CloseHandle() //其他说明

的无效句柄。CloseHandle将自动终结程序

(调试器产生无效句柄)

**********************************************************************************/

BOOL CloseHandleException(void)

{

HANDLE hInvalid = (HANDLE)0xDEADBEEF; // 无效句柄

DWORD found = FALSE;

__try

{

CloseHandle(hInvalid);

}

__except (EXCEPTION_EXECUTE_HANDLER)

{

found = TRUE;

}

if (found)

{

return TRUE;

}

else

return FALSE;

}

int main(void)

{

if (NtGlobalFlags())

{

printf(“NtGlobalFlags()检测到调试\n”);

}

if (CheckDebug_Is())

{

printf(“IsDebuggerPresent()检测到调试\n”);

}

if (CheckDebug_CRDP())

{

printf(“CheckRemoteDebuggerPresent()检测到调试\n”);

}

if (CheckDebug_0xCC())

{

printf(“CheckDebug_0xCC()检测到调试\n”);//让调试器中断

}

if (CheckDebug_rdtsc())

{

printf(“CheckDebug_rdtsc()检测到调试\n”);//检测时钟时间异常

}

if (NtQueryInformationProcessApproach())

{

printf(“NtQueryInformationProcessApproach()检测到调试\n”);//检测到调试器

}

if (CloseHandleException())

{

printf(“CloseHandleException()检测到调试\n”);

}

if (AD_SetUnhandledExceptionFilter())

{

printf(“AD_SetUnhandledExceptionFilter()已终结调试\n”);//抛出异常给调试器

}

getchar();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

douluo998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值