Для кого она нужна?
1) начинающих реверсеров, знающих особенности обратного проектирования, и желающих изучить такой отладчик как GDB
2) как подсказка тем кто постоянно работает с IDA, Ghidra или любым другим мощным и надежным инструментом, но в силу тех или иных обстоятельств решить задачу проще и быстрее с помощью GDB, и не очень хочется залезать в официальную документацию и снова все вспоминать
Основные команды
Запуск
Общий синтаксис выбора исполняемого файла для анализа
gdb program_name
Запустить выполнение программы
run | r
Присоединиться к gdbserver
target remote host:port
Присоединиться к процессу, отключиться от него
attach PID / detach
Выйти из gdb
quit | q
CTRL + D
Статический анализ
Выбрать синтаксис ассемблера
set disassembly-flavor intel/att
Просмотреть информацию об архитектуре, секциях
info file
Получение списка функций
info functions | i func
Получение asm-листинга функции
disas func_name
disas address
Если у вас есть исходники (можем собрать с опцией -g3 для gcc) или исследуемая программа содержит отладочную информацию, можем посмотреть листинг ее исходного кода
list func_name
Динамический анализ
Установить аргументы для каждого запуска программы и посмотреть их
set args
show args
Распределение виртуальной памяти
info proc mappings
Просмотр регистров
registers
Отладка
Шаг с заходом в функцию
step | s
Шаг с прыжком через вызываемую подпрограмму
next | n
Выполнить до нужной строки, адреса
until | u number_of_list_string
until | u *func_name+offset
until | u *address
Информация об аргументах функции, локальных переменных (для файлов, содержащих отладочную информацию) и фрейме текущей функции
info args
info locals
info frame
Просмотреть список процессов и выбрать интересующий
info threads
thread number
Способы расстановки breakpoints
b func_name
b *func_name+offset
b *address
Посмотреть список точек останова, включить или отключить, удалить breakpoint
info break
disable/enable breakpoint_number
delete breakpoint_number
ignore breakpoint_number n // остановится на этой точке пройдя ее n раз
Продолжить выполнение до следующего breakpoint-а
continue | c
Просмотр стека
telescope
telescope $rsp+64
Для отображения значения по указанному адресу используется команда x, где через "/" указывается формат вывода
x/i - инструкция
x/x - hex
x/s - строка
x/a - адрес
а также размер вывода
x/b - 8-bit
x/h - 16-bit
x/w - 32-bit
x/g - 64-bit
Пример
x/64bx
x/i $pc
Передача аргумента командной строки
run $(python -c "print('A'*32 + '\xde\xad')")
run $(echo "asdf\\xde\xad")
Для передачи значений функциям ввода
run <<< $(python -c "print('A1'*3)")
run <<< $(echo "asdf\xde\xad")
Gdb Сервер
Запустить сервер gdb для отладки
gdbserver host:port program
Reverse Debug
Все мы проходили через этот неловкий момент когда во время отладки мы проскочили интересующую нас функцию, и теперь снова надо перезапускать отладчик, проходить тот же путь на CFG и т.п. Чтобы избежать этого, в gdb есть такая фишка как Reverse Debug, позволяющая сохранить состояние программы и обратно отладить до него.
Для этого, после запуска отладчика укажем gdb, что хотим начать использовать reverse debug и стоит сохранять состояния программы
record
После этого станут доступны следующие команды
reverse-step
reverse-next
Создание дампа
Сдампить участок памяти ( часто необходимо при работе с распаковщиками )
dump memory output_file start_addr end_addr
Настройка для работы
Для того чтобы закрепить вывод команды, скажем просмотр инструкций во время отладки и отображения регистров можно воспользоваться командой display
display/5i $pc
display/g $rax
display/g $rbx
display/g $rcx
Делаем жизнь проще с GEF
Для эффективного использования gdb лучше воспользоваться плагином gef, он уже включает в себя удобный закрепленный вывод, используемый при динамическом анализе, а также набор собственных команд расширяющий возможности нашего универсального отладчика. Рассмотрим некоторые наиболее полезные.
Посмотреть состояние aslr, включить/отключить
aslr
aslr on/off
Для проверки исполняемого файла на наличие ASLR, Canary, PIE и т.д.
checksec
Посмотреть чанки
heap chunks
Находясь в функции можем получить значение канарейки и адрес, где она расположена
canary
Чуть более удобный вывод, чем info proc mappings
vmmap
Просмотр регистра флагов и изменение их
flags
flags -Flag_name +Flag_name
Помощь для поиска уязвимостей форматной строки (установка на них точек останова, информация по найденным функциям)
format-string-helper
Создание паттерна и его поиск
pattern create 128
pattern search 0x61616167
pattern search $rbp
Поиск строк по шаблону
search-pattern pattern
Патчинг
patch byte/word/dword/qword address value
Печать массива в формате удобном для копирования в python код. Параметр b должен быть 8/16/32/64, l контролирует длину массива
Пример
print-format -b 64 -l 1 $rsp
Для поиска шеллкода по шаблону
shellcode search pattern
shellcode get shellcode_number
Ксорим значения в памяти и регистрах
xor display address/register size xor_key
xor patch address/register size xor_key
nckma
Может посоветуете по такому вопросу… Пытаюсь отладить некоторую программу, запускаю ее по команде run. Она стартует и потом выскакивает segfault.
Казалось бы я могу посмотреть backtrace и понять в какой функции произошло и посмотреть весь стек вызовов. Однако происходит что-то странное — в стеке вызовов например одна функция memcpy() откуда вызвана не понятно, предыдущих функций в списке нет.
Или бывает другое — показана функция в которой сегфаулт, но она по идее вообще никогда не должна вызываться. Такое впечатление, что программа просто улетает неизвестно куда…
Один случай я таки смог понять и отловить. Очень странное дело. Обнаружил, что если есть C функция объявленная как int func(), но программист не делает return result (не возвращает никакого значения), то такой код может оказывается валить программу, происходит переход по случайному адресу. Это происходит иногда при компиляции с gcc8.
Думаю в моем случае еще что-то такое происходит… но как найти с помощью gdb?
Когда случается segfault, то уже видимо поздно.
Отлаживать от старта программы по шагам вряд ли получится, так как там в программе много асинхронных потоков.
win32asm
По описанию похоже на битый стек.
Я бы посоветовал погонять с ASAN/MSAN/TSAN, а если только в gdb — то, возможно, record и обратное исполнение что-нибудь покажут. Ну или руками попытаться раскрутить стек, глядишь, что получится.
void_one
Выглядит как оптимизированный бинарник, нужно компилировать с -O0.
staticmain
Вы собираете release версию, в которой отсутствует debug информация. Для ее добавления компилируйте с "-g".
nckma
Флаг -g используется.
staticmain
Значит падение происходит в сторонней/системной библиотеке, которая собрана без отладочной информации. Установите соотвествующие -dev пакеты или пересоберите библиотеки
vyo
Обычно в -dev пакеты кладут заголовки, отладочные символы отдельно пакуются в -dbg.
void_one
1) "-g" не отменяет оптимизацию, нужно чтобы явно был выставлен уровень -O0.
2) Отладочные символы для сторонних библиотек ставятся в пакетах -dbg. Для Ubuntu и Debian эти пакеты лежат в отдельных репозиториях, которые нужно подключать.