IDA Pro: 11 советов, которые вы (может быть) не знали

от автора

Как скопировать псевдокод в ассемблерный листинг? Как правильно выровнять структуры? Как лучше всего сделать экспорт куска данных для использования в скрипте? В этой статье я покажу компиляцию полезных, как мне кажется, советов для IDA Pro, честно украденных позаимствованных из разных источников и своего опыта.

Выравнивание структур

В изучаемой программе могут использоваться структуры, которые используют "нестандартное" выравнивание, скажем, по одному байту. Такие структуры можно без проблем создать в виде структур (Shift + F9), а в случае использования вида локальных типов нужно воспользоваться директивой pragma, а точнее pragma pack. pragma pack (n) задает выравнивание членов структур (чаще всего по умолчанию используется выравнивание 4 или 8 байт).

Например, если мы имеем дело с такой структурой

struct test_s {   char ch1;   QWORD qword; };

и знаем, что ее члены идут один за другим (т.е. сам экземпляр структуры занимает 5 байт), то при ее наложении на данные получим такую картину:

https://habrastorage.org/webt/mp/74/al/mp74al9nkprcsv7leihgqun6x3m.png

Видно, что между ch1 и qword образовалось неиспользуемое пространство, на месте которого по задумке должен был быть сам qword. Но если перепишем структуру следующим образом:

#pragma pack(1) struct test_s {   char ch1;   QWORD qword; };

то получим корректный результат:

https://habrastorage.org/webt/8l/it/s6/8lits68hs1glqr0g4iatqacxl9a.png

Текстовый поиск

В декомпиляторе нет Ctrl+F, но оказывается, что Alt+T, работающий в окне дизассемблера, точно так же работает и в окне декомпилятора.

https://habrastorage.org/webt/-g/f5/5i/-gf55icmkkhcnsqx1mx4kjgpjxg.png

https://habrastorage.org/webt/qg/5b/cz/qg5bczp6gu-uo0tl1rbiu7vitxq.png

Segments → Rebase

Если вы с первого раза не угадали правильный адрес загрузки прошивки, то можете воспользоваться функцией переноса idb на другой адрес.

Например, мы загрузили прошивку в IDA по нулевому адресу. По адресу 0x04 находится указатель на функцию, который сейчас указывает в область памяти, которой не сопоставлено ни одного сегмента в idb.

https://habrastorage.org/webt/mj/n7/bv/mjn7bvxnomvd0ylscpm11hsusva.png

Зайдем в Edit→Segments→Rebase и перенесем нашу прошивку на адрес 0x8000000.

В результате у нас появился нормальный xref:

https://habrastorage.org/webt/iy/-l/rh/iy-lrhiqnzt7qfotqyo2iysssgi.png

Бряки

В IDA, как и в большинстве отладчиков, можно ставить условные бряки, т.е. они будут срабатывать только если выполняется определенное условие. Условие представляет собой конструкцию на языке IDC или Python, в которой во время отладки доступны глобальные переменные с соответствующими именами для доступа к каждому из регистров.

Также во время отладки таким образом можно менять значения регистров и содержимое памяти.

Выделение участков данных и экспорт (Alt+L — Shift+E)

Для выделения большого сегмента данных можно воспользоваться сочетанием клавиш Alt+L, чтобы начать выделение региона и управлять границами выделяемого региона с помощью мыши или клавиш управления курсором. Выделенные данные можно экспортировать в один их удобных форматов (строка, hex-последовательность, массив байт C) и помощью сочетания клавиш Shift+E.

Удаленная отладка

IDA поддерживает удаленные GDB и Windbg-сервера, но также в ней есть возможность удаленной отладки с помощью своих собственных серверов (находятся в каталоге IDADIR\dbgsrv).

https://habrastorage.org/webt/6s/1h/mh/6s1hmhcrc_icisa4viun1owbrz0.png

Строковые литералы в декомпиляторе

Часто может встречаться ситуация, когда read-only данные перемешаны в одном сегменте с read-write данными (например, при использовании старых компиляторов, компиляторов для RTOS и др.). При этом при использовании декомпилятора можно наблюдать следующее:

Как мы видим, вместо строковых литералов подставляются названия переменных. Это отрицательно сказывается на читабельности псевдокода. Для исправления этой неурядицы можем изменить тип строковых переменных с char на const char.

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

Второй вариант — это настроить декомпилятор на отображение всех строк как литералов (а не только неизменяемых). Для этого убираем галку "Print only constant strings literals" в настройках декомпилятора.

В результате получаем красивый вывод:

Код little endian, а данные big endian

Иногда встречается Little Endian код для ARM, в то время, как данные имеют формат Big Endian. В этом случае для корректного отображения данных надо зайти в General options → Analysis → Processor specific analysis options → Edit ARM architecture options и поставить галку "BE-8 code (ARMB)".

Бряки и gdbserver

То ли я работаю с такими версиями gdbserver, то ли лыжи не едут, но включенная по умолчанию в IDA "single stepping support" у меня не работает, и из-за этого при отладке не срабатывают вообще никакие бряки, кроме самой первой. В этом случае я захожу в настройки отладчика, выбираю "Set specific options" и убираю галку "Use stepping support".

Эта настройка не сохраняется в idb, и для того, чтобы не делать этого каждый раз, в конфигурационном файле dbg_gdb.cfg необходимо исправить параметр SINGLE_STEP.

И еще про gdbserver

И еще поворчу про работу с gdbserver (в этот раз — в случае присоединения к удаленному процессу). Если на целевой машине включен ASLR, то у IDA может не получиться понять реальное расположение образа отлаживаемого файла в памяти. В результате IDA будет пытаться работать с адресами, которые указывают в какое-то невалидное пространство памяти. Для борьбы с этим можно еще до присоединения к удаленному процессу сделать rebase idb на актуальный адрес, и только потом присоединяться к процессу.

Сбор мусора в IDAPython

Интерпретатор Python, встроенный в IDA работает всегда и не закрывается до закрытия самой IDA. Поэтому сущности вашего Python-скрипта или плагина не будут автоматически удаляться. Кроме очевидных последствий вроде внезапных для автора утечек памяти, это может привести и к более забавным побочным эффектам, как, например, во время использования модуля logging.

Если написать такой скрипт

import logging  def main():     logger = logging.getLogger('test1-script')     logger.setLevel(logging.DEBUG)     formatter = logging.Formatter('[TEST 1] %(name)s - %(message)s')     ch = logging.StreamHandler()     ch.setFormatter(formatter)     logger.addHandler(ch)     logger.debug("Log message!")  if __name__ == "__main__":     main()

и запустить его два раза подряд, увидим такой вывод:

https://habrastorage.org/webt/cq/mj/am/cqmjamal8rb0l5cfeit8tll53wu.png

Происходит это потому, что функция getLogger либо создает, либо получает из глобального кэша уже существующий объект класса Logger. Далее к полученному инстансу логгера (одинаковому при каждом запуске скрипта) добавляется еще один хэндлер. Проверить это можно просто: выводим кэш (словарь) логгеров и список хэндлеров:

https://habrastorage.org/webt/kf/4t/ni/kf4tnigeguq6rnaga8n7v4tnoig.png

Есть как минимум два способа бороться с этим:

logging.Logger.manager.loggerDict.clear()

или

reload(logging)

И последнее

Минутка внимания еще нескольким трюкам:

  1. Начиная с версии 7.4, объявления локальных переменных в декомпиляторе могут быть "слохпнуты" по умолчанию — это настраивается в файле hexrays.cfg.
  2. Также в этой версии можно "прыгать" между фигурными скобками в псевдокоде по клавише "%" (Shift+5).
  3. С помощью горячей клавиши "/" можно скопировать псевдокод в ассемблерный листинг в виде комментариев.

Источники

  1. Друзья-коллеги
  2. IDA Pro Book
  3. https://twitter.com/idatips
  4. Release Notes
  5. И другие.

ссылка на оригинал статьи https://habr.com/ru/post/439740/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *