Шпаргалка полезных команд GDB

    Для кого она нужна?


    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

    Комментарии 11

      0
      Может посоветуете по такому вопросу… Пытаюсь отладить некоторую программу, запускаю ее по команде run. Она стартует и потом выскакивает segfault.
      Казалось бы я могу посмотреть backtrace и понять в какой функции произошло и посмотреть весь стек вызовов. Однако происходит что-то странное — в стеке вызовов например одна функция memcpy() откуда вызвана не понятно, предыдущих функций в списке нет.
      Или бывает другое — показана функция в которой сегфаулт, но она по идее вообще никогда не должна вызываться. Такое впечатление, что программа просто улетает неизвестно куда…

      Один случай я таки смог понять и отловить. Очень странное дело. Обнаружил, что если есть C функция объявленная как int func(), но программист не делает return result (не возвращает никакого значения), то такой код может оказывается валить программу, происходит переход по случайному адресу. Это происходит иногда при компиляции с gcc8.

      Думаю в моем случае еще что-то такое происходит… но как найти с помощью gdb?
      Когда случается segfault, то уже видимо поздно.
      Отлаживать от старта программы по шагам вряд ли получится, так как там в программе много асинхронных потоков.

        +3
        По описанию похоже на битый стек.
        Я бы посоветовал погонять с ASAN/MSAN/TSAN, а если только в gdb — то, возможно, record и обратное исполнение что-нибудь покажут. Ну или руками попытаться раскрутить стек, глядишь, что получится.
          +1

          Выглядит как оптимизированный бинарник, нужно компилировать с -O0.

            0
            в стеке вызовов например одна функция memcpy() откуда вызвана не понятно, предыдущих функций в списке нет.

            Вы собираете release версию, в которой отсутствует debug информация. Для ее добавления компилируйте с "-g".
              0
              Флаг -g используется.
                0

                Значит падение происходит в сторонней/системной библиотеке, которая собрана без отладочной информации. Установите соотвествующие -dev пакеты или пересоберите библиотеки

                  0

                  Обычно в -dev пакеты кладут заголовки, отладочные символы отдельно пакуются в -dbg.

                  0

                  1) "-g" не отменяет оптимизацию, нужно чтобы явно был выставлен уровень -O0.


                  2) Отладочные символы для сторонних библиотек ставятся в пакетах -dbg. Для Ubuntu и Debian эти пакеты лежат в отдельных репозиториях, которые нужно подключать.

                    0
                    1) Даже на -O3 при наличии -g можно проводить отладку. Да, будут скакать строки, но смотреть\править workflow никто не мешает.
                    2) Да, тут не прав, имел в виду -dbg.
                      0

                      Отладку проводить можно, и строки будут скакать, и еще половина переменных будет показываться как "".  @Slekdzhov, если все это есть, то дело точно в оптимизации.

              +4

              Еще полезного:


              set print elements 0
              При печати массивов показывает все элементы


              set print repeats 0
              Печатает элементы без указания "повторяется N раз"


              set print pretty on
              Печатает элементы структуры выравнивая поля


              p выражение
              Умеет не только показывать содержимое переменных но и вызывать функции, меняя данные в процессе. Например, если приложение щависоо в цикле но нужно чтобы оно доработало без перезапуска:


              ps aux | grep program # ищем пид
              456 program


              grep -p 456 # полключаемся по пид


              $ stopped at "while (flag == 5)" # остановлено на проверке
              $ p flag = 6 # пользуемся свойством языка что присваивание возвращает результат операции
              $ quit # выходим из процесса продолжая его выполнение

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое