反调试
通用
软断点检测
以 x86 指令集为例, 调试器通过插入指令 INT3 来实现软断点. 若检测发现代码中存在该指令或代码被修改, 则表明已被跟踪.
硬件断点检测
寄存器 DR0/DR1/DR2/DR3 用于设置硬件断点, 若其中有寄存器的值不是 0, 则表明已被跟踪.
执行时长
通过调试器人为干扰代码运行可能导致执行时间显著变长.
Linux
ptrace
由于进程一次只能被一个程序跟踪, 因此可以尝试通过 ptrace 来跟踪自己. 若失败, 则表明已被跟踪.
proc
读取 /proc/self/status
, 其中 TracerPid 的值是跟踪进程的 PID, 若该值不为 0 则表明已被跟踪.
父进程
通过调用 getppid
获取父进程的 PID, 并查询该进程的信息. 若进程是调试器, 则表明已被跟踪.
Windows
IsDebuggerPresent
IsDebuggerPresent()
是一个位于 kernel32.dll 中的函数.
简单的改进方法就是自行实现该函数, 检查 PEB 中 BeingDebugged
的值, 若为 1 则表明已被跟踪.
绕过检测的方法就是将 BeingDebugged
置为 0.
STARTUPINFO
explorer.exe
创建线程时会将 STARTUPINFO 的部分值置为 0, 因此可以获取 STARTUPINFO 的值, 若特定部分不为 0 则表明已被跟踪.
bool is_tracked() noexcept {
STARTUPINFO startupInfo;
GetStartupInfo(&startupInfo);
return si.dwX != 0 || si.dwY != 0 || si.dwFillAttribute != 0 || si.dwXSize != 0 ||
si.dwYSize != 0 || si.dwXCountChars != 0 || si.dwYCountChars != 0;
}
还有下列的等更多方法, 这里不再赘述.
- CheckRemoteDebuggerPresent: 检测指定进程是否被调试.
- NtQueryInformationProcess: 有属性表明指定进程是否被调试.
- NtGlobalFlag: 包含如何创建堆结构的属性, 调试器会修改这个值.
- ProcessHeap: 有属性用于表明堆是否在调试器中创建.
- 父进程.
- 异常处理.
- SeDebugPrivilege: 被调试进程继承了调试器的 SeDebugPrivilege 权限.
- OutputDebugString: 没有被调试时, 该函数会失败.
-
注册表:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug(32位) SOFTWARE\Wow6432Node\Microsoft\WindowsNT\CurrentVersion\AeDebug(64位) 指定程序异常时启动的调试器, 默认值是 Dr.Watson.
除了检测是否正在被跟踪, 还可以直接干扰调式工作.
详情请参考 https://blog.csdn.net/qq_32400847/article/details/52798050.
参见
- BaumFX/cpp-anti-debug: anti debugging library in c++..
- ThomasThelen/Anti-Debugging: A collection of c++ programs that demonstrate common ways to detect the presence of an attached debugger..