跳转至

反调试

通用

软断点检测

以 x86 指令集为例, 调试器通过插入指令 INT3 来实现软断点. 若检测发现代码中存在该指令或代码被修改, 则表明已被跟踪.

硬件断点检测

寄存器 DR0/DR1/DR2/DR3 用于设置硬件断点, 若其中有寄存器的值不是 0, 则表明已被跟踪.

执行时长

通过调试器人为干扰代码运行可能导致执行时间显著变长.

Linux

ptrace

由于进程一次只能被一个程序跟踪, 因此可以尝试通过 ptrace 来跟踪自己. 若失败, 则表明已被跟踪.

bool is_tracked() noexcept {
    return ptrace(PTRACE_TRACEME, 0, 1, 0) == -1;
}

proc

读取 /proc/self/status, 其中 TracerPid 的值是跟踪进程的 PID, 若该值不为 0 则表明已被跟踪.

父进程

通过调用 getppid 获取父进程的 PID, 并查询该进程的信息. 若进程是调试器, 则表明已被跟踪.

Windows

IsDebuggerPresent

IsDebuggerPresent() 是一个位于 kernel32.dll 中的函数.

bool is_tracked() noexcept {
    return IsDebuggerPresent();
}

简单的改进方法就是自行实现该函数, 检查 PEB 中 BeingDebugged 的值, 若为 1 则表明已被跟踪.

绕过检测的方法就是将 PEB.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.

参见

评论