Отладчики вглубь: gdb, x64dbg, точки останова
Статический анализ показывает, что программа может делать; отладчик показывает, что она делает на самом деле — прямо сейчас, с конкретными данными.
Отладчик (debugger) — инструмент, который запускает программу под своим контролем: умеет приостанавливать её в выбранных точках, показывать и менять регистры, память и стек, выполнять код по одной инструкции. Для аналитика это «замедленное кино» работы бинарника.
Чтение дизассемблера — это разбор статичного текста: вы видите инструкции, но не видите, какие значения по ним проходят. Отладчик снимает это ограничение. Он позволяет остановить выполнение ровно там, где интересно, и заглянуть внутрь: что лежит в регистрах, что на стеке, по какой ветке пошёл код. Для исследователя вредоносного ПО или участника CTF это основной способ понять логику, которую невозможно вычислить «на бумаге» — например, значение, расшифрованное только в рантайме.
Зачем это знать аналитику и защитнику
Многое в современном ПО раскрывается лишь во время работы: ключи расшифровываются на лету, конфигурация собирается из кусков, проверки зависят от окружения. Статически такой код выглядит как «шум». Отладчик превращает шум в наблюдаемые факты: вы ставите точку останова после расшифровки и просто читаете готовую строку из памяти. Для защитника это рабочий инструмент анализа подозрительного образца в изолированной лаборатории: понять, что делает семпл, какие данные он формирует, по каким условиям ветвится.
Два инструмента: gdb и x64dbg
Под Linux стандарт — gdb, консольный отладчик. Под Windows для реверса популярен x64dbg — графический, с окнами регистров, стека, дампа памяти и дизассемблера. Принципы у них одинаковые, отличается только интерфейс: то, что в gdb набирается командой, в x64dbg делается мышью или горячей клавишей.
| Действие | gdb (команда) | x64dbg |
| Точка останова по адресу/функции | break *0x401000 / break main | F2 на строке дизассемблера |
| Запуск / продолжить | run / continue | F9 |
| Шаг с заходом в вызов | stepi | F7 |
| Шаг без захода (через call) | nexti | F8 |
| Показать регистры | info registers | окно Registers |
Точки останова (breakpoints)
Точка останова — пометка «останови выполнение, когда дойдёшь сюда». Это базовый приём: вы помечаете интересный адрес (начало функции проверки, место после расшифровки строки), запускаете программу, и она замирает на этом месте, отдавая вам управление. Технически программный брейкпоинт реализуется подменой одного байта инструкции на специальный код-ловушку, по которому процессор передаёт управление отладчику; перед продолжением отладчик прозрачно возвращает оригинальный байт. Знать этот механизм важно — на нём же строятся некоторые приёмы анти-отладки из третьего урока.
(gdb) break main # остановиться на входе в main
(gdb) run # запустить программу
(gdb) info registers rax # прочитать один регистр
(gdb) x/8xb $rsp # 8 байт памяти со стека в hex
Вотчпоинты (watchpoints)
Иногда вопрос не «где выполнение», а «кто изменил это значение». Тут помогает вотчпоинт — точка останова не на коде, а на данных: программа замирает, как только указанная ячейка памяти или переменная меняется. Это незаменимо, когда надо найти, в каком месте кода присваивается флаг или портится буфер.
(gdb) watch counter # стоп при изменении переменной counter
(gdb) rwatch secret # стоп при чтении secret
(gdb) continue # бежим, пока значение не тронут
Под капотом вотчпоинты обычно используют отладочные регистры процессора (hardware breakpoints): CPU сам следит за обращением к адресу, поэтому такой брейк не замедляет программу и не меняет её байты.
Регистры и стек в рантайме
Главная ценность отладчика — возможность читать состояние процессора в любой момент паузы. Регистры (rax, rbx, rsp, rip и др.) хранят аргументы, промежуточные значения и адрес текущей инструкции; стек хранит локальные переменные и адреса возврата. Остановившись в нужной точке, вы буквально видите, что программа держит «в руках».
Чтобы прочувствовать, как из «сырых» байтов получается осмысленное значение, разберём, как читается little-endian-число — именно так регистры и память показываются в отладчике:
# Байты в памяти (little-endian) -> целое число, как делает отладчик
raw = bytes([0x2a, 0x00, 0x00, 0x00]) # как лежит в памяти 4-байтное число
value = int.from_bytes(raw, "little")
print("hex в памяти:", raw.hex())
print("значение:", value)
Вывод:
hex в памяти: 2a000000 значение: 42
Понимание порядка байтов критично: в дампе памяти число 42 выглядит как 2a 00 00 00, и без этого знания легко неверно прочитать значение из стека или регистра.
Как это работает под капотом
Отладчик и отлаживаемая программа — два процесса, связанных механизмом ОС. На Linux это системный вызов ptrace: он позволяет одному процессу читать и менять регистры и память другого, ставить точки останова и получать управление при остановках. На Windows аналогичную роль играет Debugging API (события отладки, DebugActiveProcess, доступ к памяти через ReadProcessMemory). Важный вывод: отлаживаемая программа в принципе может заметить, что находится под наблюдением, — потому что присоединение отладчика оставляет следы в состоянии процесса. Именно это используют техники анти-отладки.
Как защититься
В контексте reverse-engineering «защита» имеет два смысла. Со стороны аналитика важна безопасность лаборатории: запускайте незнакомый бинарник только в изолированной ВМ без доступа к ценным данным и сети, делайте снимок (snapshot) до запуска, чтобы откатиться. Со стороны разработчика, который не хочет лёгкого анализа своего ПО, помогают (с оговоркой, что от мотивированного исследователя они лишь поднимают планку): сборка без отладочных символов, обфускация, контроль целостности кода. Но опираться на «секретность через сложность» как на единственную защиту нельзя — настоящие секреты (ключи, пароли) не должны быть зашиты в клиентский бинарник вообще.
Юридическое напоминание: отлаживать и анализировать допустимо своё ПО, программы со свободной лицензией, учебные crackme и образцы в рамках легального исследования. Обход технических средств защиты и анализ чужого ПО в нарушение лицензии могут быть незаконны (см. УК РФ ст. 272/273 — неправомерный доступ и вредоносное ПО). Работайте на своих файлах и в разрешённых лабораториях.
Итоги
- Отладчик запускает программу под контролем: пауза в нужной точке, чтение и изменение регистров, памяти и стека, пошаговое выполнение.
- Точки останова ловят момент по адресу/функции; вотчпоинты — по обращению к данным (часто через аппаратные отладочные регистры).
- gdb (Linux, консоль) и x64dbg (Windows, GUI) различаются интерфейсом, но реализуют одни и те же приёмы.
- Под капотом — ptrace на Linux и Debugging API на Windows; присоединение отладчика оставляет следы, что и эксплуатирует анти-отладка.
- Безопасность аналитика — изолированная ВМ и снапшоты; настоящие секреты не зашивают в клиентский бинарник.