Ghidra или IDA Pro?
В марте 2019 года Агентство национальной безопасности США (NSA) опубликовало инструментарий для реверс-инжиниринга под названием Ghidra. Пару лет назад я уже слышал это название из утечек на сайте WikiLeaks и был весьма заинтересован, чем же пользуются в NSA для реверса. Настала пора удовлетворить любопытство и посмотреть, хороша ли бесплатная «Гидра» в сравнении с зарекомендовавшими себя инструментами.
Проблема доверия
АНБ в рамках программы Technology Transfer Program уже открыло исходные коды 32 проектов (полный список можно посмотреть на GitHub). Конечно, не обходится без шуточек о том, что АНБ будет использовать эти средства для слежения за пользователями. С одной стороны, конечно, код продуктов открыт, а их пользователи достаточно хардкорны, чтобы не полениться провести аудит. С другой — первый же косяк нашелся сразу после релиза Ghidra.
Британский ИБ-эксперт и глава Hacker House Мэттью Хики (Matthew Hickey) заметил, что в отладочном режиме инструмент Ghidra открывает и слушает порт 18001. Это позволяет подключиться к Ghidra удаленно, через JDWP, — разумеется, с целью все той же отладки. Хики отмечает, что исправить проблему совсем несложно — достаточно поменять строку 150 в файле support/launch.sh
со звездочки на 127.0.0.1.
Постепенно всплывают и другие баги. Например, была найдена возможность эксплуатировать XXE при условии, что пользователь Ghidra откроет специально сформированный проект. Так что будь начеку!
Скачать Ghidra можно с официального сайта ghidra-sre.org, но есть небольшая проблема: сайт недоступен из российских сетей (и, по некоторым данным, из канадских). Но я думаю, что это не препятствие для читателей «Хакера». Можно воспользоваться любым VPN или на крайний случай Tor.
Архив Ghidra в распакованном виде
Итак, ты скачал архив ghidra_9.0_PUBLIC_20190228
и распаковал его. Давай немного пробежимся по основным папкам и посмотрим, что в них.
Настоятельно рекомендую заглянуть в папку docs — там много информации о самой Ghidra, о разработке плагинов для нее и обзор основных возможностей в виде слайдов и документов PDF. Вся информация, естественно, на английском.
Далее идут папки с лицензиями — в них ничего интересного. В папке server есть инструментарий для запуска сервера удаленной отладки. В папке support собраны вспомогательные инструменты, без которых программа работать не будет.
В папке Ghidra уже интереснее: в Processors можно ознакомиться со всеми поддерживаемыми архитектурами. Вот их полный список: 6502, 68000, 6805, 8051, 8085, AARCH64, ARM, Atmel, CR16, DATA, JVM, MIPS, PA-RISC, PIC, PowerPC, Sparc, TI_MSP430, Toy, x86, Z80.
Папки с инструкциями для разных архитектур
Настало время смотреть само приложение! Чтобы открыть Ghidra в Windows, запускаем ghidraRun.bat
, в Linux — ghidraRun.sh
. Проект написан в основном на Java, поэтому качай и ставь Java Runtime, если у тебя его нет.
Окно создания проекта
Первым делом нам предлагают создать проект, в который мы добавим нужные бинарные файлы для исследования. После этого становится активной иконка с зеленым драконом, которая и откроет для нас CodeBrowser — основную среду для работы.
Основное окно CodeBrowser
Сначала появляется окно с технической информацией о загружаемом файле, потом приглашение провести анализ и выбрать опции для него. Соглашаемся. Выглядит основной интерфейс довольно непривычно — во всяком случае, для меня.
CodeBrowser
И вот мы оказываемся в заголовке нашего файла. Перед нами структура IMAGE_DOS_HEADER
, а не точка входа. Интересно! Надо сказать, что все поля отображены корректно, да и выглядит все более-менее сносно и информативно.
INFO
При первом запуске приложения я столкнулся с немного неудобным отображением кода и других полей в различных окнах дизассемблера. Но все это можно настроить при помощи специальной кнопки Edit the listing fields в верхнем правом углу каждого окна.
Справа располагается окно декомпилятора, к нему мы еще вернемся. Там же есть вкладка Functions. Давай нажмем на нее.
Вкладка Functions
Здесь видим список функций с их сигнатурами — очень удобно, на мой взгляд. Давай выберем какую-нибудь функцию и посмотрим, что будет.
Начальный код дизассемблированной функции
Это самое начало функции с ее сигнатурой, передаваемые в нее значения и их типы, возвращаемое значение, конвенция вызова и сам дизассемблерный листинг. В самом верху есть кнопка Display Function Graph, я ее выделил на скриншоте. Жмем на нее.
Графическое представление кода в Ghidra
Графическое представление кода в IDA Pro
При наведении на кодовые блоки появляется забавная анимация (видна на скриншоте). Я специально сделал два скриншота одной и той же функции: один в представлении графа в Ghidra, другой — в IDA Pro. Не знаю, как тебе, но, на мой взгляд, информативнее граф в Ghidra. К тому же Ghidra помечает прямо в графе конструкции if… else. Я понимаю, что это все ребячество, но лично для меня графическое представление кода в Ghidra более информативно и удобно, нежели в IDA Pro. Кроме того, графическое представление весьма гибко настраивается.
Также у Ghidra широкие возможности поиска — чтобы увидеть все варианты, достаточно выбрать в меню фреймворка пункт Search и посмотреть выпадающий список. Например, вот так выглядит диалог поиска по строкам.
Окно поиска по строкам
Еще Ghidra прекрасно строит перекрестные ссылки на что угодно — чтобы воспользоваться этой возможностью, нужно выбрать в контекстном меню пункт References, а далее выбирать то, что тебя интересует. Кроме этого, в начале каждой функции Ghidra старается сразу отобразить в комментариях перекрестные ссылки на эту функцию.
В Ghidra есть встроенный шестнадцатеричный просмотрщик. Чтобы его увидеть, нужно открыть меню «Windows → Bytes».
Встроенный HEX-просмотрщик
Ghidra из коробки поддерживает патчинг ассемблерного кода. Чтобы воспользоваться этой функцией, нужно выделить строчку кода и нажать комбинацию Ctrl + Shift + G
либо выбрать соответствующий пункт в контекстном меню. Есть интересная визуальная фишка — если выделить какой-нибудь код в окне декомпилятора, то такой же код автоматически выделяется в окне дизассемблерного листинга.
Выделение кода в Ghidra
Еще одна интересная фишка Ghidra — это Script Manager, набор скриптов на все случаи жизни, поставляющийся из коробки. Если какого-то скрипта не хватает, разумеется, его можно добавить. Все скрипты написаны на Java. Чтобы ты понимал, о чем идет речь, прилагаю полный листинг скрипта CreateExportFileForDll.java
. Что он делает, думаю, понятно из названия!
import generic.jar.ResourceFile; import ghidra.app.script.GhidraScript; import ghidra.app.util.opinion.LibraryLookupTable; public class CreateExportFileForDLL extends GhidraScript { @Override public void run() throws Exception { // Push this .dll into the location of the system .exports files. // Must have write permissions. ResourceFile file = LibraryLookupTable.createFile(currentProgram, false, true, monitor); println("Created .exports file : " + file.getAbsolutePath()); } }
Скрипты можно редактировать во встроенном простеньком редакторе, а можно открывать в IDE Eclipse прямо из контекстного меню. Разумеется, Eclipse должен быть установлен.
Кроме того, есть разные полезные мелочи, типа встроенного диффера, возможности патчить код без всяких дополнительных плагинов, возможности смотреть энтропию кода и строить дерево вызовов в приложении (трассу). Имеется встроенный интерпретатор Python (не требуется его устанавливать отдельно, как в IDA) и другие приятные фишки.
Теперь давай посмотрим на декомпилятор, который также идет в комплекте, а не отдельным плагином, как в IDA. Приведу сначала результат работы декомпилятора Ghidra, а потом и IDA Pro.
Это листинг Ghidra:
undefined8 FUN_1400010b0(void) { ushort uVar1; longlong *plVar2; LPCSTR lpMultiByteStr; ushort *puVar3; longlong *plVar4; longlong in_GS_OFFSET; ushort local_d8 [104]; plVar2 = *(longlong **)(*(longlong *)(*(longlong *)(in_GS_OFFSET + 0x60) + 0x18) + 0x18); lpMultiByteStr = FUN_140001448(&DAT_140003000); MultiByteToWideChar(0,1,lpMultiByteStr,-1,(LPWSTR)local_d8,100); plVar4 = plVar2; do { plVar4 = (longlong *)*plVar4; if (plVar4[6] != 0) { puVar3 = local_d8; while( true ) { uVar1 = *(ushort *)((plVar4[0xc] - (longlong)local_d8) + (longlong)puVar3); if ((uVar1 == 0) && (*puVar3 == 0)) goto LAB_140001140; if ((uVar1 < *puVar3) || (uVar1 >= *puVar3 && uVar1 != *puVar3)) break; puVar3 = puVar3 + 1; } } } while (plVar2 != plVar4); LAB_140001140: return plVar4[6]; }
А это листинг IDA Pro Hex-Rays:
__int64 sub_1400010B0() { unsigned __int64 v0; // rax _QWORD *v1; // rdi _QWORD *v2; // rbx const CHAR *v3; // rax WCHAR *i; // rax WCHAR v5; // cx WCHAR WideCharStr; // [rsp+30h] [rbp-D8h] v0 = __readgsqword(0x60u); v1 = *(_QWORD **)(*(_QWORD *)(v0 + 24) + 24i64); v2 = *(_QWORD **)(*(_QWORD *)(v0 + 24) + 24i64); v3 = (const CHAR *)sub_140001448(&unk_140003000); MultiByteToWideChar(0, 1u, v3, -1, &WideCharStr, 100); while ( 1 ) { v2 = (_QWORD *)*v2; if ( v2[6] ) break; LABEL_9: if ( v1 == v2 ) return v2[6]; } for ( i = &WideCharStr; ; ++i ) { v5 = *(WCHAR *)((char *)i + v2[12] - (_QWORD)&WideCharStr); if ( !v5 && !*i ) break; if ( v5 < *i || v5 > *i ) goto LABEL_9; } return v2[6]; }
Как по мне, так листинг Ghidra читается попроще. Да, я знаю, что вывод Hex-Rays гибко настраивается. Помимо этого, есть плагин HexRaysPyTools, который помогает еще улучшить результат. Но мы-то прежде всего говорим о том, что идет в комплекте, а Hex-Rays еще и стоит отдельных денег.
Так или иначе, модуль декомпиляции в Ghidra могучий и вполне может составить конкуренцию Hex-Rays. А если зайти в папку \Ghidra\Processors
, затем выбрать любую архитектуру и далее зайти в \data\languages
, можно увидеть файлы с расширениями *.slaspec и *.pspec и еще некоторые. Глядя на них, понимаешь, что написать поддержку своей архитектуры — вполне реальная задача. Да, все-таки открытости кода сильно не хватает IDA Pro!
Заключение
Итак, мы рассмотрели фреймворк для реверс-инжиниринга Ghidra. Сможет ли он заменить IDA Pro? Я думаю, что на данном этапе своего существования — нет. Дело в том, что Java в качестве языка для написания подобных программ, на мой взгляд, не лучший выбор. И дело, конечно, в скорости.
Дизассемблер работает небыстро, особенно на тяжелых файлах. Скажу больше: файлы размером свыше 150 Мбайт реверсить на Ghidra — то еще испытание. С другой стороны, Ghidra кросс-платформенна, и для кого-то это может быть важно.
Следующий момент — это количество поддерживаемых архитектур и загрузчиков файлов: у IDA Pro их значительно больше. Еще очень не хватает такой же плотной интеграции с отладчиками, как в IDA Pro. Опять же, открытость кодов (если NSA выполнит обещание) — это хорошо, да и возможность добавлять поддержку других архитектур — по-настоящему крутая фишка. Но пока будет выполнена эта работа (и исправлены баги), пройдут годы.
Вообще, у меня сложилось стойкое впечатление, что Ghidra — это не конечный продукт. В том виде, в котором этот фреймворк доступен сейчас, он тянет на бета-версию с публичным доступом, но никак не на версию под номером девять. Кстати, в названии архива есть слово PUBLIC. Наверняка где-то есть еще и версия PRIVATE.
Безусловно, у Ghidra есть свои сильные стороны, и в чем-то она уже превосходит IDA Pro, но слабых мест пока что намного больше. А вот разработчикам IDA есть что позаимствовать в новом инструменте. Например, мне понравилась повышенная информативность кода, представленного в виде графа. Да и само построение графа кода выглядит более строго и упорядоченно. Есть патчинг инструкций без дополнительных плагинов и без разделения на x64 и x86. Зачем держать два ярлыка на рабочем столе, если достаточно одного? В общем, Ильфаку еще есть куда двигаться!