[原创]利用OD逻辑进行反调试
这几天忽然发现在部分进程的GetMessageA下硬件断点,然后删除断点后再执行,进程抛出STATUS_SINGLE_STEP错误.然后仔细研究下发现这涉及一个OD逻辑问题,可以做为攻击点.
首先是代码
VOID WINAPI CheckThread(LPVOID lp)
{
while (TRUE){
Sleep(3 * 1000);
DWORD dwPorcet;
VirtualProtect((PVOID)0x401000, 5, PAGE_EXECUTE_READWRITE, &dwPorcet);
DWORD dwAdder = *(DWORD*)0x401000; ///保护这个地址
PostMessageA(NULL, NULL, NULL, NULL); ///保护这个函数执行过程
}
}
HANDLE hThread[25];
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 0; i < 25; i++)
{
Sleep(10);
hThread[i] = ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)CheckThread, NULL, NULL, NULL);
}
system("pause");
return 0;
}
代码很简单,线程数量其实也不需要那么多,但是主要的功能就是保护PostMessageA函数执行过程跟0x401000地址不被调试器下执行或者读写硬件断点!
如果存在硬断,那么硬断触发后,删除断点,继续运行.进程将出现TATUS_SINGLE_STEP错误然后崩溃退出.


当初发现这个问题的时候为了弄清这一切,从异常分发内核调试分发整个过程都调试了个遍,最后发现其实是因为调试器OD自己存在逻辑错误导致的!一路可谓兜兜转转.
大致原因是OD在删除硬件断点的时候并没检测是否设置成功.导致OD已经确定删除断点,断点位置OD已经不再处理,但是线程的调试寄存器依然有效,结果存在无人管理的调试寄存器,最后触发STATUS_SINGLE_STEP异常时OD不进行处理而把异常抛给系统,系统又抛给程序,程序拒绝处理,最后导致进程崩溃!
OD删除调试寄存器伪代码如下
signed int __cdecl Deletehardwarebreakpoint(signed int a1)
{
CONTEXT Context; // [sp+1Ch] [bp-2CCh]@14
do{
SuspendThread(*v5);
v4 = dword_ADFC80;
++v1;
v5 += 403;
} while ( v1 < dword_ADFC80 );
do
{
Context.ContextFlags = 0x10010u;
if ( GetThreadContext(*v6, &Context) )
{
Context.Dr0 = dword_AE7240[0];
Context.Dr2 = dword_AE7278;
Context.Dr1 = dword_AE725C;
Context.Dr3 = dword_AE7294;
..................
while ( v9 < 32 );
Context.Dr7 = v7;
SetThreadContext(*v19, &Context);//简单的设置,并没检查是否设置成功
}
}
do{
ResumeThread(*v17);
++v16;
v17 += 403;
} while ( v16 < dword_ADFC80 );
return 0;
}
X64位下测试有效果,其他系统请大家自行测试!
规避这个异常错误可以在设置里把忽略单步异常的勾子去掉,但这样又会导致超原始单步异常检测OD方法的生效!
这个逻辑错误貌似一直存在,可是好像一直无人注意,也从未有人考虑修复这个错误!
这个是DEMO 无花无壳,大家可以随意测试!
MFC版本 反调试测试.rar
控制台版本 控制台版本.rar
