1.IsDebuggerPresent 检测是否在函数头有普通断点,或是否被挂钩
2.CheckRemoteDebuggerPresent(ProcessDebugPort)
3.NtGlobalFlags,测试发现直接运行工程会提示有调试器,windbg初始附加运行提示有调试器,但windbg中间附加不会提示有调试器,测试失败,但可用.
0:000> dt _PEB -y NtGlobalFlag @$peb
test1!_PEB
+0x068 NtGlobalFlag : 0x40000
DbgToolType AD_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 DBGTOOL_CUSTOM;
rf_label:
return DBGTOOL_NO;
}
4.通过列举运行的应用程序的窗口,并于常用调试相关工具比对(但调试器不一定附加在自己进程)
DbgToolType AD_FindDbgToolWindow()
{
if (::FindWindow(_T("ollydbg"),NULL)
|| ::FindWindow(_T("pe--diy"),NULL))//oLLYICE的类名叫pe--diy
{
MyOutputDebugString(_T("[AD_FindDbgToolWindow] DBGTOOL_OD"));
return DBGTOOL_OD;
}
if (::FindWindow(_T("WinDbgFrameClass"),NULL))
{
MyOutputDebugString(_T("[AD_FindDbgToolWindow] DBGTOOL_WINDBG"));
return DBGTOOL_WINDBG;
}
return DBGTOOL_NO;
}
5.通过列举运行的应用程序的进程名,并于常用调试相关工具比对(但调试器不一定附加在自己进程)
DbgToolType AD_FindDbgToolProcess()
{
HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap)
{
return DBGTOOL_NO;
}
PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
if (!Process32First(hProcSnap, &pe32))
{
CloseHandle(hProcSnap);
return DBGTOOL_NO;
}
do
{
if (0 == _tcsicmp(pe32.szExeFile, _T("OLLYICE.EXE"))
|| 0 == _tcsicmp(pe32.szExeFile, _T("OLLYDBG.EXE")))
{
return DBGTOOL_OD;
}
if (0 == _tcsicmp(pe32.szExeFile, _T("WINDBG.EXE")))
{
return DBGTOOL_WINDBG;
}
} while (Process32Next(hProcSnap, &pe32));
CloseHandle(hProcSnap);
return DBGTOOL_NO;
}
6.如果程序处于调试器中,那么在PEB结构中有个beingDegug标志会被设置6.如果程序处于调试器中,那么在PEB结构中有个beingDegug标志会被设置6.如果程序处于调试器中,那么在PEB结构中有个beingDegug标志会被设置
DbgToolType AD_BeingDebuggedFlag()
{
__asm
{
mov eax, fs:[30h] ;EAX = TEB.ProcessEnvironmentBlock
inc eax
inc eax
mov eax, [eax]
and eax, 0x000000ff ;AL = PEB.BeingDebugged
test eax, eax
jne rt_label
jmp rf_label
}
rt_label:
return DBGTOOL_CUSTOM;
rf_label:
return DBGTOOL_NO;
}
7.当一个进程获得SeDebugPrivilege,它就获得了对CSRSS.EXE的完全控制,这种特权也会被子进程继承, 也就是说一个被调试的程序如果获得了CSRSS.EXE的进程ID,它就可以使用openprocess操作CSRSS.EXE,加壳后发现提示有调试器,暂不用此方式
DbgToolType AD_SeDebugPrivilege()
{
return DBGTOOL_NO;
// 枚举进程,找到CSRSS.exe进程
HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap)
{
return DBGTOOL_NO;
}
PROCESSENTRY32 pe32 ={sizeof(PROCESSENTRY32)};
if (!Process32First(hProcSnap, &pe32))
{
CloseHandle(hProcSnap);
return DBGTOOL_NO;
}
DWORD PID_csrss;
bool findflag = false;
do
{
if (0 == _tcsicmp(pe32.szExeFile, _T("csrss.exe")))
{
PID_csrss = pe32.th32ProcessID;
findflag = true;
}
} while (Process32Next(hProcSnap, &pe32) && !findflag);
if (findflag)
{
HANDLE hCrssPro = OpenProcess(PROCESS_QUERY_INFORMATION,false,PID_csrss);
if (hCrssPro)
{
CloseHandle(hProcSnap);
CloseHandle(hCrssPro);
return DBGTOOL_CUSTOM;
}
}
CloseHandle(hProcSnap);
return DBGTOOL_NO;
}
8.:给CloseHandle()函数一个无效句柄作为输入参数,在无调试器时,将会返回一个错误代码,而有调试器存在时,将会触发一个EXCEPTION_INVALID_HANDLE (0xc0000008)的异常
DbgToolType AD_ExceptionCloseHandle()
{
__try
{
CloseHandle(HANDLE(0x00001234));
return DBGTOOL_NO;
}
__except(1)
{
return DBGTOOL_CUSTOM;
}
}
9.Window创建进程的时候会把STARTUPINFO结构中的值设为0,windbg启动程序,不会报,但OD启动它,会报有调试器,测试失败.但可用.
DbgToolType AD_CheckStartupInfo()
{
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
GetStartupInfo(&si);
if ((si.dwX != 0)
|| (si.dwY !=0)
|| (si.dwXCountChars != 0)
|| (si.dwYCountChars !=0 )
|| (si.dwFillAttribute != 0)
|| (si.dwXSize != 0)
|| (si.dwYSize != 0))
{
return DBGTOOL_CUSTOM;
}
else
{
return DBGTOOL_NO;
}
}
10.护页异常”是一个简单的反调试技巧。当应用程序尝试执行保护页内的代码时,将会产生一个EXCEPTION_GUARD_PAGE(0x80000001)异常,但如果存在调试器,调试器有可能接收这个异常,并允许该程序继续运行,事实上,在OD中就是这样处理的,OD使用保护页来实现内存断点
DbgToolType AD_OD_Exception_GuardPages()
{
SYSTEM_INFO sSysInfo;
LPVOID lpvBase;
BYTE * lptmpB;
GetSystemInfo(&sSysInfo);
DWORD dwPageSize = sSysInfo.dwPageSize;
DWORD flOldProtect;
lpvBase = VirtualAlloc(NULL,dwPageSize,MEM_COMMIT,PAGE_READWRITE);
if (lpvBase == NULL)
{
return DBGTOOL_NO;
}
lptmpB = (BYTE *)lpvBase;
*lptmpB = 0xc3;//retn
VirtualProtect(lpvBase, dwPageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &flOldProtect);
__try
{
__asm call dword ptr[lpvBase];
VirtualFree(lpvBase, 0, MEM_RELEASE);
return DBGTOOL_CUSTOM;
}
__except(1)
{
VirtualFree(lpvBase, 0, MEM_RELEASE);
return DBGTOOL_NO;
}
}
DbgToolType AD_OD_Exception_GuardPages()
{
SYSTEM_INFO sSysInfo;
LPVOID lpvBase;
BYTE * lptmpB;
GetSystemInfo(&sSysInfo);
DWORD dwPageSize = sSysInfo.dwPageSize;
DWORD flOldProtect;
lpvBase = VirtualAlloc(NULL,dwPageSize,MEM_COMMIT,PAGE_READWRITE);
if (lpvBase == NULL)
{
return DBGTOOL_NO;
}
lptmpB = (BYTE *)lpvBase;
*lptmpB = 0xc3;//retn
VirtualProtect(lpvBase, dwPageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &flOldProtect);
__try
{
__asm call dword ptr[lpvBase];
VirtualFree(lpvBase, 0, MEM_RELEASE);
return DBGTOOL_CUSTOM;
}
__except(1)
{
VirtualFree(lpvBase, 0, MEM_RELEASE);
return DBGTOOL_NO;
}
}