gdb запуск программы с параметрами
Шпаргалка полезных команд GDB
Для кого она нужна?
1) начинающих реверсеров, знающих особенности обратного проектирования, и желающих изучить такой отладчик как GDB
2) как подсказка тем кто постоянно работает с IDA, Ghidra или любым другим мощным и надежным инструментом, но в силу тех или иных обстоятельств решить задачу проще и быстрее с помощью GDB, и не очень хочется залезать в официальную документацию и снова все вспоминать
Основные команды
Запуск
Общий синтаксис выбора исполняемого файла для анализа
Запустить выполнение программы
Присоединиться к gdbserver
Присоединиться к процессу, отключиться от него
Статический анализ
Выбрать синтаксис ассемблера
Просмотреть информацию об архитектуре, секциях
Получение списка функций
Получение asm-листинга функции
Динамический анализ
Установить аргументы для каждого запуска программы и посмотреть их
Распределение виртуальной памяти
Отладка
Шаг с заходом в функцию
Шаг с прыжком через вызываемую подпрограмму
Выполнить до нужной строки, адреса
Информация об аргументах функции, локальных переменных (для файлов, содержащих отладочную информацию) и фрейме текущей функции
Просмотреть список процессов и выбрать интересующий
Способы расстановки breakpoints
Посмотреть список точек останова, включить или отключить, удалить breakpoint
Продолжить выполнение до следующего breakpoint-а
Для отображения значения по указанному адресу используется команда x, где через «/» указывается формат вывода
а также размер вывода
Передача аргумента командной строки
Для передачи значений функциям ввода
Gdb Сервер
Запустить сервер gdb для отладки
Reverse Debug
Все мы проходили через этот неловкий момент когда во время отладки мы проскочили интересующую нас функцию, и теперь снова надо перезапускать отладчик, проходить тот же путь на CFG и т.п. Чтобы избежать этого, в gdb есть такая фишка как Reverse Debug, позволяющая сохранить состояние программы и обратно отладить до него.
Для этого, после запуска отладчика укажем gdb, что хотим начать использовать reverse debug и стоит сохранять состояния программы
После этого станут доступны следующие команды
Создание дампа
Сдампить участок памяти ( часто необходимо при работе с распаковщиками )
Настройка для работы
Для того чтобы закрепить вывод команды, скажем просмотр инструкций во время отладки и отображения регистров можно воспользоваться командой display
Делаем жизнь проще с GEF
Для эффективного использования gdb лучше воспользоваться плагином gef, он уже включает в себя удобный закрепленный вывод, используемый при динамическом анализе, а также набор собственных команд расширяющий возможности нашего универсального отладчика. Рассмотрим некоторые наиболее полезные.
Посмотреть состояние aslr, включить/отключить
Для проверки исполняемого файла на наличие ASLR, Canary, PIE и т.д.
Находясь в функции можем получить значение канарейки и адрес, где она расположена
Чуть более удобный вывод, чем info proc mappings
Просмотр регистра флагов и изменение их
Помощь для поиска уязвимостей форматной строки (установка на них точек останова, информация по найденным функциям)
Создание паттерна и его поиск
Поиск строк по шаблону
Печать массива в формате удобном для копирования в python код. Параметр b должен быть 8/16/32/64, l контролирует длину массива
Краткий гайд по использованию GDB
В этом коротком туториале мы рассмотрим базовые приёмы работы с GDB, а также посмотрим как можно (и нужно) подготавливать файлы к отладке для GDB.
GDB — переносимый отладчик проекта GNU, который работает на многих UNIX-подобных системах и умеет производить отладку многих языков программирования, включая Си, C++, Free Pascal, FreeBASIC, Ada, Фортран, Python3, Swift, NASM и Rust.
Почему именно GDB? Всё легко, он уже установлен на многих UNIX-подобных системах, лёгок в использовании и поддерживает много языков. Работа с ним оказывается очень лёгкой, а также его можно подключить к VSCode и другим редакторам кода (Включая Vim, NeoVim (ясное дело), Emacs, Atom и далее)
Подготовка файлов
Для примера мы возьмём файлы .cpp и будем проходиться по ним вдоль и поперёк.
Для того чтобы нам пройтись по такому файлу нам нужно скомпилировать его с помощью G++ с использованием флага -g (это действительно важно, без этого флага, программа не будет корректно работать в GDB).
Python-файл вы можете продебажить с помощью этой команды:
Для Java вы просто можете использовать jdb, который уже идёт в комплекте c JDK.
Также, если вам не хочется компилировать всё ручками, вы можете просто использовать сайт OnlineGDB, там просто нужно вставить код и нажать debug, а затем внизу откроется консоль, где вы сможете писать команды.
Использование GDB
Как только мы зашли в GDB нам выводится следующее сообщение:
Последняя строка говорит о том, нормально ли запустился файл.
Далее запускаем программу с помощью комманды r :
Также вы можете включить TUI, с помощью комбинации клавиш
Для того, чтобы посмотреть на какой мы сейчас строке, нужно написать f :
Для того, чтобы сделать шаг, нужно нажать n (от слова next):
Как мы видим GDB сразу пропускает пустые строки (или строки с комментариями) и переходит к следующей строке.
Предположим, что у нас есть функция, при нажатии n наш отладчик быстро пройдет функцию, не заходя в неё, чтобы зайти в функцию нужно сделать «шаг внутрь» (step-in) или просто клавиша s :
(В примере нет функции, однако шаг step-in все равно будет работать и с обычными инициализациями, условиями и циклами)
Чтобы узнать какие переменные (локальные) сейчас инициализированны в программе нужно написать комманду info locals :
Чтобы вывести только одну переменную, нужно написать print имя_переменной :
Мы можем также изменить переменную с помощью set :
Мы можем также следить за переменными с помощью watch :
Также, если нужно можно посмотреть что в данный момент находится в регистрах ( info registers ):
Чтобы посмотреть какие в данный момент есть breakpoints (точки останова) нужно написать info breakpoints :
Чтобы удалить точку останова del breakpoint_num :
Чтобы прыгнуть к следующей точке останова нужно нажать c :
Мы можем вызывать функции из программы (локальные) с помощью call :
Чтобы продолжить выполнение функции и остановить программу когда она (функция) завершится нужно написать finish или fin :
Стоит уточнить, что нельзя использовать finish в главном методе.
Чтобы завершить выполнение программы, нужно написать kill :
Также можно написать help в любой момент и получить краткую справку, как пользоваться отладчиком
Основы консольного отладчика GDB
Введение
Его используют как непосредственно из командной строки, так и из специальных графических оболочек (frontends)
Компиляция
Перед отладкой необходимо скомпилировать программу с ключом -g или -gdb:
Есть также возможность использовать несколько уровней полноты отладочной информации (от 0 до 3):
Запуск
Для запуска программы под отладчиком используют следующие команды:
в этом случае после старта GDB мы увидим служебную информацию и результат чтения символьной таблицы из программы, например:
позволяет запустить программу в отладчике без лишней информации
предназначена для передачи исследуемой программе параметров командной строки
Выход
Выход из отладчика осуществляется командами q или quit
Запуск команд shell
Находяcь внутри отладчика можно запустить команду shell:
Запуск программы под отладчиком
После загрузки программы мы можем запустить её с помощью run и выполнить всю, а также с помощью start и выполнить её по шагам.
Пример выполнения программы:
Это другой пример выполнения программы (используется start и n (next) для пошагового выполнения:
Точки останова
устанавливает точку останова на строке с номером N. Если запустить программу с помощью run, то выполнение остановится на N-ой строке.
в любой момент выводит на экран список точек останова
Точки останова могут содержать условные выражения
Следующая команда заставит остановиться на 25 строке, если значение переменной age больше 15:
Точки просмотра
Точки просмотра нужно задавать, находясь в области видимости исследуемых переменных. То есть для локальных переменных необходимо сначала войти в блок, где переменная объявлена
Продолжить выполнение программы можно командой c (continue)
Кроме команды watch есть аналогичная rwatch, позволяющая задать точку просмотра для переменной, из которой читаются данные.
Точки останова и просмотра можно сделать неактивными с помощью команды disable
Листинг программы
Команда list позволяет просмотреть исходный код программы вместе с номерами строк, не покидая отладчик
Просмотр и изменение переменных
Команды print и set используются для просмотра и изменения значений переменных
Пример с set
Можно просмотреть содержимое локальных переменных с помощью
Как пользоваться gdb
В сегодняшней статье мы рассмотрим как пользоваться gdb для отладки и анализа выполнения программ, написанных на Си. Попытаемся разобраться с основными возможностями программы.
Как пользоваться gdb
1. Установка gdb
Обычно, отладчик устанавливается вместе с другими инструментами для сборки программного обеспечения. Для установки всего необходимого в Ubuntu или Debian достаточно выполнить:
sudo apt install build-essential
Для того чтобы установить отладчик отдельно, выполните:
sudo apt install gdb
В CentOS или Fedora команда установки будет выглядеть следующим образом:
sudo dnf install gdb
А для Arch Linux надо выполнить:
Теперь отладчик gdb установлен и вы можете его использовать.
2. Компиляция программы
Для того чтобы получить максимум полезной информации во время отладки, например, имена переменных и номера строк кода программу следует скомпилировать особым образом. Для примеров из этой статьи мы будем использовать такую небольшую программу на Си, в процессе будем её изменять, но начнём с этого:
#include
int main() <
int var1 = 0;
int var2 = 2;
char greeting[] = «Hello from losst\n»;
printf(«%s», greeting);
>
Затем вы можете её выполнить:
3. Запуск отладчика
Для того чтобы запустить программу достаточно передать путь к ней отладчику. Какие-либо опции указывать не обязательно:
После запуска отладчика вы попадаете в его командный интерфейс. Программа ещё не запущена, запущен только отладчик, в котором вы можете ею управлять с помощью специальных команд. Вот основные команды gdb:
4. Запуск программы
Для того чтобы запустить программу надо воспользоваться командой run в консоли gdb. Просто выполните:
И программа будет запущена и выполнена. Если вам надо передать программе какие-либо аргументы, то следует их передать команде run, например:
Если программа завершилась с ошибкой, вы можете вывести стек вызовов функций для того чтобы узнать в какой именно функции возникла ошибка:
Программа сообщает на какой строчке исходного кода возникла проблема. Чтобы посмотреть весь исходник выполните команду list:
Для того чтобы вызвать ошибку Segmentation Fault и проверить как это работает можете добавить в программу такие строки и перекомпилировать её:
char *buffer = malloc(sizeof(char) * 10);
while(1) <
*(++buffer) = ‘c’;
>
Тут мы выделяем из памяти массив символов размером 10 элементов и заполняем его и память, которая находится за ним символами «с», пока программа не упадёт.
5. Точки останова
По умолчанию команда выводит первые десять строк. Ей можно передать в качестве аргумента номер строки, строки возле которой надо отобразить или имя функции, например:
Например, давайте установим точку останова на восьмой строчке исходника:
Теперь, когда вы запустите программу на выполнение она остановиться в указанной точке:
Для того чтобы выполнить следующую строчку без входа в функцию используйте команду next:
Тогда выполнится следующая строка кода в программе. Если надо войти в функцию и посмотреть что в ней происходит следует использовать команду step:
Для отладки циклов можно устанавливать точки останова на основе условия, например, на 11-той строке, если значение переменной var1 будет 20:
(gdb) break 11 if var1==20
Чтобы этот пример заработал добавьте в код цикла следующую строчку, как на снимке:
Посмотреть все установленные точки останова можно такой командой:
6. Вывод информации
А для вывода значений аргументов функции:
Вывести значение определённой переменной можно с помощью print:
Интересно, что с помощью print можно выполнять арифметические операции и их результат не только выводится на экран, но и присваивается внутренней переменной, таким образом его можно будет вывести ещё раз позже или использовать в других вычислениях. Например:
Таким образом вы можете анализировать состояние программы, на каждой точке останова и искать ошибки.
7. Изменение информации
С помощью команды set можно изменить значение переменной прямо во время выполнения программы. Например:
(gdb) break 7
(gdb) run
(gdb) set var2 = 20
(gdb) print var2
8. Вывод типа
С помощью команды ptype вы можете вывести тип переменной. Например:
(gdb) break 7
(gdb) run
(gdb) ptype var2
9. Просмотр адресов
Ещё интереснее исследовать как программы на Си работают с памятью. Команда print может выводить не только выводить значения переменных, но и их адреса в памяти. Приведите программу к такому виду и перекомпилируйте её:
#include
#include
#include
int main(int argc, char *argv[]) <
int var1 = 0;
int var2 = 2;
char *buffer = malloc(sizeof(char) * 10);
while(var1
Запустите отладчик и установите точку останова на девятой строке и запустите программу:
Теперь вы можете вывести адреса всех переменных в памяти с помощью символа &. Например:
(gdb) print &argc
(gdb) print &var1
(gdb) print &buffer
(gdb) print buffer
10. Просмотр памяти
С помощью команды x или eXamine можно посмотреть содержимое памяти, по определённому адресу. Например, смотрим содержимое переменной var2:
Если вы не знаете адрес переменной, можно передать её имя с оператором &, он извлечет её адрес. Программа выводит шеснадцатиричное значение, и оно обычно мало о чём нам может сообщить. Для того чтобы улучшить ситуацию можно воспользоваться опциями форматирования. Можно указать тип выводимых данных с помощью таких модификаторов:
Также можно указать размер выводимого блока:
Мы пытались вывести переменную типа int. Она занимает обычно четыре байта. Для её корректного вывода используйте такие параметры:
Ещё можно указать количество блоков, которые надо выводить, например два:
Но поскольку там уже не наша переменная, эти данные не имеют смысла. Аналогично всё работает с строками, символами и другими значениями. Только обратите внимание, что если вы будете выводить переменную не одним блоком, то на результат повлияет порядок расположения байт. Значение будет выводиться задом на перед.
11. Справка по программе
Мы рассмотрели основные возможности отладчика gdb. Но если этого вам не достаточно, вы можете посмотреть справку по любой команде программы в самой программе. Для этого используйте команду help. Например, для команды exemine:
Выводы
Теперь вы знаете как пользоваться gdb для отладки своих программ. Обычно, для отладки намного удобнее использовать графический интерфейс среды программирования, но консоль дает больше возможностей и больше гибкости.
Gdb запуск программы с параметрами
Прежде чем выполнять программу под управлением GDB, при компиляции вы должны сгенерировать отладочную информацию.
Для эффективной отладки программы, при компиляции вы должны сгенерировать отладочную информацию. Эта отладочная информация сохраняется в объектном файле; она описывает тип данных каждой переменной или функции, и соответствие между номерами строк исходного текста и адресами в выполняемом коде.
Чтобы запросить генерацию отладочной информации, укажите ключ `-g’ при вызове компилятора.
Многие компиляторы Си не могут обрабатывать ключи `-g’ и `-O’ вместе. Используя такие компиляторы, вы не можете создавать оптимизированные выполняемые файлы, содержащие отладочную информацию.
run r Используйте команду run для запуска вашей программы под управлением GDB. Сначала вы должны задать имя программы (кроме как на VxWorks) с параметрами GDB (see section Вход и выход из GDB), или используя команды file или exec-file (see section Команды для задания файлов).
Если вы запускаете вашу программу в среде выполнения, поддерживающей процессы, run создает подчиненный процесс, и этот процесс выполняет вашу программу. (В средах, не поддерживающих процессы, run выполняет переход на начало вашей программы.)
Если время модификации вашего символьного файла изменилось с того момента, когда GDB последний раз считывал символы, он уничтожает свою символьную таблицу и считывает ее заново. При этом GDB старается сохранить ваши текущие точки останова.
В не-Unix системах, программу обычно запускает непосредственно GDB, который эмулирует перенаправление ввода-вывода через соответствующие системные вызовы, и символы шаблонов раскрываются кодом запуска, а не оболочкой.
По умолчанию, программа, которую вы запускаете под управлением GDB, осуществляет ввод и вывод на тот же терминал, что и GDB. Для взаимодействия с вами, GDB переключает терминал в свой собственный терминальный режим, но он записывает терминальные режимы, которые использовала ваша программа, и переключается назад к ним, когда вы продолжаете выполнение программы. info terminal Отображает информацию, записанную GDB о терминальных режимах, которые использует ваша программа.
Явное перенаправление в run замещает эффект команды tty для устройств ввода-вывода, но не ее воздействие на управляющий терминал.
Эта команда полезна, если вы хотите отладить дамп памяти, а не выполняющийся процесс. GDB игнорирует любые дампы памяти, пока ваша программа выполняется.
В некоторых операционных системах, таких как HP-UX и Solaris, одна программа может иметь несколько нитей выполнения. Точная семантика нитей меняется от одной операционной системы к другой, но в общем, нити одной программы сродни нескольким процессам—за исключением того, что они разделяют одно адресное пространство (то есть, все они могут исследовать и модифицировать одни и те же переменные). С другой стороны, каждая нить имеет свои собственные регистры и стек выполнения, и, возможно, свои собственные участки памяти.
Для отладочных целей, GDB присваивает свои собственные номера нитей—небольшие целые, присваиваемые в порядке создания нитей— каждой нити в вашей программе.
Когда GDB останавливает вашу программу, вследствие точки останова или по сигналу, он автоматически выбирает нить, в которой появилась точка останова или сигнал. GDB предупреждает вас о переключении контекста сообщением в форме `[Switching to сист-тег ]’ для идентификации нити.
See section Остановка и запуск многонитевых программ, для дополнительной информации о поведении GDB, когда вы останавливаете и запускаете многонитевую программу.
See section Установка точек наблюдения, для информации о точках наблюдения в многонитевых программах.
По умолчанию, когда программа ветвится, GDB будет продолжать отладку родительского процесса, а дочерний процесс будет выполняться беспрепятственно.