Привет:3 Сегодня разберем одну из техник антиотладки.
При анализе вредоносов достаточно часто без бутылки пива динамического анализа не разобраться. Поэтому запустить бинарь под отладчиком — это база. Очевидно, что малварщики это тоже знают. Поэтому они используют различные методы защиты от отладки. Все это называется красивым словом — 🙌антиотладка🙌.
Одной из самых простых техник обнаружения отладчика является Debugger Evasion. Обнаружив факт отладки, вредонос может изменить свое поведение, чтобы не палиться)
Сегодня рассмотрим простые примеры данной техники.
Linux
У данного метода следующая логика — eсли к запущенному процессу есть подключение через ptrace(), значит к нему подключен дебаггер. Почему это работает? В Linux к одному процессу может подключиться для отслеживания только один процесс. Если при попытке подключения для отладки происходит ошибка, значит этот процесс уже был запущен под отладкой.
ptrace()
ptrace() — это системный вызов, который позволяет трассировать или отлаживать выбранный процесс.
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
request— это действие, которое необходимо осуществить;pid— PID;addrиdata— зависят отrequest.
В поле request можно передать следующие команды:
PTRACE_SINGLESTEP— позволяет запущенному процессу выполнить ровно одну инструкцию, а потом автоматически остановиться, чтобы отладчик мог проверить состояние;PTRACE_SYSCALL— продолжает выполнение процесса до того момента, когда он войдёт в системный вызов или выйдет из него, что даёт возможность посмотреть аргументы вызова или возвращаемое значение;PTRACE_ATTACH— отладчик присоединяется к уже работающему процессу, отправляет ему сигналSIGSTOP, чтобы приостановить, и затем может управлять этим процессом;
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
perror("ptrace_attach");
exit(EXIT_FAILURE);
}
PTRACE_PEEKTEXT— позволяет прочитать данные из адресного пространства другого процесса;PTRACE_POKETEXT— позволяет записать данные в адресное пространство другого процесса;
size_t data_len = strlen(data);
uint64_t *data_p = (uint64_t *)data;
for (size_t i = 0; i < data_len; i += 8, data_p++) {
if (ptrace(PTRACE_POKETEXT, pid, address + i, *data_p) < 0) {
perror("ptarce_poketext");
exit(EXIT_FAILURE);
}
}
PTRACE_GETREGS— читает текущее состояние регистров процесса. Для хранения регистров используется структура user_regs_struct;
struct user_regs_struct old_regs;
if (ptrace(PTRACE_GETREGS, target_pid, NULL, &old_regs) < 0) {
perror("ptrace_getregs");
exit(EXIT_FAILURE);
}
PTRACE_SETREGS— записывает состояние регистров процесса;
struct user_regs_struct regs;
memcpy(®s, &old_regs, sizeof(struct user_regs_struct));
regs.rip = target_address;
if (ptrace(PTRACE_SETREGS, target_pid, NULL, ®s) < 0) {
perror("ptrace_setregs");
exit(EXIT_FAILURE);
}
PTRACE_CONT— продолжает выполнение отлаживаемого процесса;
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
perror("ptrace_cont");
exit(EXIT_FAILURE);
}
Пример
#include <stdio.h>
#include <sys/ptrace.h>
int main()
{
if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
printf("Debugging Dedected.\n");
return 1;
}
ptrace(PTRACE_DETACH, 0, 1, 0);
printf("Normal Execution.\n");
return 0;
}
Запуск:

Windows
В Windows существуют стандартные методы для проверки, запущен ли процесс под отладчиком. Среди них IsDebuggerPresent(), который проверяет текущий процесс, и CheckRemoteDebuggerPresent(), позволяющий определить, присутствует ли отладчик в другом процессе.
IsDebuggerPresent()
IsDebuggerPresent() возвращает значение True, если к процессу подключен отладчик. Это позволяет программе самостоятельно определять, находится ли она под отладкой, и при необходимости изменять поведение или предпринимать защитные меры.
#include <stdio.h>
#include <windows.h>
int main() {
BOOL isDebuggerPresent = IsDebuggerPresent();
if (isDebuggerPresent) {
printf("Debugger detected\n");
} else {
printf("Debugger not detected\n");
}
return 0;
}
CheckRemoteDebuggerPresent
CheckRemoteDebuggerPresent() — это расширенный вариант проверки отладки, который позволяет определить, подключён ли отладчик к другому процессу, а не только к текущему.
#include <stdio.h>
#include <windows.h>
int main() {
BOOL isDebuggerPresent = FALSE;
HANDLE currentProcess = GetCurrentProcess();
BOOL isRemoteDebuggerPresent = FALSE;
CheckRemoteDebuggerPresent(currentProcess, &isRemoteDebuggerPresent);
if (isRemoteDebuggerPresent) {
printf("Debugger detected\n");
} else {
printf("Debugger not detected\n");
}
return 0;
}
Практика
Для того, чтобы самим посмотреть на данную технику, можно попробовать решить следующую задачку: SimpleCrackMe.exe.