87 lines
2.4 KiB
C
87 lines
2.4 KiB
C
/**
|
|||
|
|
* evasion_anti_debug.c — Anti-debugging checks
|
||
|
|
*
|
||
|
|
* Checks:
|
||
|
|
* 1. IsDebuggerPresent()
|
||
|
|
* 2. NtQueryInformationProcess (ProcessDebugPort)
|
||
|
|
* 3. Timing check (RDTSC delta)
|
||
|
|
* 4. NtGlobalFlag in PEB
|
||
|
|
*
|
||
|
|
* If a debugger is detected, calls ExitProcess(0) silently.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <windows.h>
|
||
|
|
#include <winternl.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
|
||
|
|
#include "api_resolve.h"
|
||
|
|
|
||
|
|
#ifdef EVASION_ANTI_DEBUG
|
||
|
|
|
||
|
|
static void exit_if_debugged(void) {
|
||
|
|
g_api.pExitProcess(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Basic API check */
|
||
|
|
static void check_is_debugger_present(void) {
|
||
|
|
if (g_api.pIsDebuggerPresent()) {
|
||
|
|
exit_if_debugged();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* NtQueryInformationProcess — ProcessDebugPort (class 7) */
|
||
|
|
static void check_debug_port(void) {
|
||
|
|
if (!g_api.pNtQueryInformationProcess) return;
|
||
|
|
|
||
|
|
DWORD_PTR debug_port = 0;
|
||
|
|
NTSTATUS status = g_api.pNtQueryInformationProcess(
|
||
|
|
g_api.pGetCurrentProcess(), 7 /* ProcessDebugPort */,
|
||
|
|
&debug_port, sizeof(debug_port), NULL);
|
||
|
|
if (status == 0 && debug_port != 0) {
|
||
|
|
exit_if_debugged();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Timing check: debugger single-stepping causes large RDTSC deltas */
|
||
|
|
static void check_timing(void) {
|
||
|
|
LARGE_INTEGER freq, t1, t2;
|
||
|
|
if (!g_api.pQueryPerformanceFrequency(&freq)) return;
|
||
|
|
g_api.pQueryPerformanceCounter(&t1);
|
||
|
|
|
||
|
|
/* Do some trivial work */
|
||
|
|
volatile int x = 0;
|
||
|
|
for (int i = 0; i < 100; i++) x += i;
|
||
|
|
|
||
|
|
g_api.pQueryPerformanceCounter(&t2);
|
||
|
|
/* If more than 500ms elapsed for trivial work, likely being debugged */
|
||
|
|
double elapsed_ms = (double)(t2.QuadPart - t1.QuadPart) / freq.QuadPart * 1000.0;
|
||
|
|
if (elapsed_ms > 500.0) {
|
||
|
|
exit_if_debugged();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* NtGlobalFlag in PEB — set when process is created under a debugger */
|
||
|
|
static void check_nt_global_flag(void) {
|
||
|
|
#ifdef _WIN64
|
||
|
|
/* PEB is at GS:[0x60], NtGlobalFlag at offset 0xBC */
|
||
|
|
PPEB peb = (PPEB)__readgsqword(0x60);
|
||
|
|
DWORD flags = *(DWORD *)((uint8_t *)peb + 0xBC);
|
||
|
|
#else
|
||
|
|
PPEB peb = (PPEB)__readfsdword(0x30);
|
||
|
|
DWORD flags = *(DWORD *)((uint8_t *)peb + 0x68);
|
||
|
|
#endif
|
||
|
|
/* FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS */
|
||
|
|
if (flags & 0x70) {
|
||
|
|
exit_if_debugged();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void evasion_anti_debug_init(void) {
|
||
|
|
check_is_debugger_present();
|
||
|
|
check_debug_port();
|
||
|
|
check_timing();
|
||
|
|
check_nt_global_flag();
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* EVASION_ANTI_DEBUG */
|