要检测自己是否被调试主要有调用API和获取PEB标志
PEB标志主要检测BeingDebugged 和NtGlobalFlag ,当然检测一个就行了,一般来说如果一个被调试器的反检测调试功能修改那另外的一般也跑不了,对于x86 PEB读取 fs[0x30]即可,对于x64读取gs[0x60]即可,BeingDebugged的偏移为固定的0x002,NtGlobalFlag因为两者结构不一样所以偏移也不一样x86:0x68 x64:0xbc。NtGlobalFlag如果被调试其值为0x70。
而API有多个API可以检测,下面代码使用CheckRemoteDebuggerPresent。当然因为现在的反反调试做得比较全,基本上的检测方法都会失效。所以通常可以结合多种方式来检测是否被调试,用加壳来提高自己被静态反编译的难度。常见的方法还有获取自己的父进程,通常来说自己都应该是资源管理器来打开自己的,如果是其它程序则基本可以判定是调试器,另外调试一般会暂停你的程序,那么使用定时器间隔如果和合理值偏差较大则基本也可以判定为自己被调试。另外通过信号量或其它一些方法来确定反调试线程是否存活。等等方法结合起来就算不能100%防止被调试,但是也能在很大程度阻止恶意破解,但是有利也有弊,如果检测方法太多太杂不利于自己调试和后期维护。
#include <intrin.h>
class CDebugChecker
{
inline void* GetCurrentPEB() {
#ifdef _M_X64
return (void*)(__readgsqword(0x60));
#elif _M_IX86
return (void*)(__readfsdword(0x30));
#else
#error "This architecture is currently unsupported"
#endif
}
public:
bool CheckPEB_BegingDebugged()
{
void *PEB = GetCurrentPEB();
BYTE BeingDebugged = *(BYTE*)((BYTE*)PEB + 0x002);// NtGlobalFlag 偏移 x86:0x68 x64:0xbc
return (bool)BeingDebugged;
}
bool CheckDebuggerPresent()
{
//0xffffffff
BOOL bDebuggerPresent=0;
if (CheckRemoteDebuggerPresent(
GetCurrentProcess(),
&bDebuggerPresent
))
{
return bDebuggerPresent == 0xffffffff;
}
return true;
}
};