跳转至

极其重要的技术手段

函数检测

通过Windows自带的或者是未公开的函数直接检测进程是否处在调试状态

IsDebuggerPresent

最简单的调试器函数

C
BOOL WINAPI IsDebuggerPresent(void);
通过查询进程环境块(PEB)中的Beingbugged标志,如果处在调试的上下文中, 返回非0值, 否则返回0值

C
#include<windows>
#include<stdio.h>

int main(){
    int is = IsDebuggerPresent();
    if (is){
    }
    else{
    }
}

CheckRemoteDebuggerPresent

用于检测一个远程进程是否处于被调试状态

C
BOOL WINAPI CheckRemoteDebuggerPresent(
 _IN_ HANDLE hProcess,
 _Inout_ PBOOL pbDebuggerPresent
);

NtQueryInformationProcess

原型

C
typedef NTSTATUS (NTAPI *PNtQueryInformationProcess)(
    _In_ HANDLE ProcessHandle,                  // 输入:目标进程句柄
    _In_ PROCESSINFOCLASS ProcessInformationClass, // 输入:想要查询的信息类型
    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, // 输出:返回信息
    _In_ ULONG ProcessInformationLength,        // 输入:缓冲区大小
    _Out_opt_ PULONG ReturnLength               // 输出:实际写入的字节数,可选
);

C
PROCESS_BASIC_INFORMATION pbi;
ULONG len;
NTSTATUS status = NtQueryInformationProcess(
    GetCurrentProcess(),
    ProcessBasicInformation,
    &pbi,
    sizeof(pbi),
    &len
);
if (NT_SUCCESS(status)) {
    printf("Parent PID: %lu\n", (ULONG)(ULONG_PTR)pbi.InheritedFromUniqueProcessId);
}

GetLastError

得知错误

DeleteFiber

给缓冲区传递无效参数会抛出异常, 通过验证LastError()来判断

数据检测

BeingDebugged

C
BOOL checkdebug(){
    int BeingDebug = 0;
    _asm{
        mov eax,dword ptr fs:[30h] ;指向PEB的基址
        movzx eax , byte ptr [eax + 2]
        mov BeingDebug, eax
    }
    return BeingDebug != 0;
}

NTGlobalFlag

  • PEB 中的偏移
    • x86: PEB 偏移 0x68
    • x64: PEB 偏移 0xBC

C
_asm{
    mov eax,dword ptr fs:[30h];
    mov eax,dword ptr [eax + 68h]
    and eax,0x70 
    mov BeingDbg,eax
}
进程是0x70说明是出于调试中

进程监测

监测当前的桌面是否存在特定的进程, 检测是否有调试

特征码检测

时间检测

通过处于调试时和未处于调试时的时间差异来判断是否处于调试状态 rdtsc指令GetTickCout

C
int bedebug = 0;
_asm{
    rdstc
    mov ecx,edx
    rdtsc
    sub edx,ecx
    mov bedebug,edx
}
if(bedebug > 2)

断点检测

  • 通过是否修改代码指令为INT3(机器码0xcc)触发软件异常
  • 通过硬件调试寄存器设置硬件断点 检测系统扫描重要区域, 判断是否存在多以的INT3

其他

挖坑