
Инструмент для извлечения информации RTTI из исполняемых файлов Delphi, написанный на чистом Python
Этот инструмент сканирует исполняемый файл на наличие данных Delphi, включая RTTI и виртуальные таблицы методов. Он выводит JSON-файл с информацией об обнаруженных классах и функциях, который можно использовать для дополнительного анализа, например:
Также предоставляется скрипт IDAPython, который может загружать результат в IDA.
Скрипт был написан в дополнение к другим инструментам для реверс-инжиниринга Delphi.
Выпущено как открытое ПО компанией NCC Group Plc - http://www.nccgroup.com/
Разработано Дэвидом Каннингсом (@edeca) [email protected]
http://www.github.com/nccgroup/pythia
Этот проект выпущен под лицензией AGPL. Дополнительную информацию см. в файле LICENSE.
Общий поток выполнения выглядит так:
vftable в Delphi хорошо документированы. Информация для последней версии доступна у Embarcadero. Неофициальная документация доступна для Delphi 2005 (см. здесь).
Исходный код Free Pascal также полезен (зеркало на Github).
Первый элемент vftable — vmtSelfPtr, который указывает на начало виртуальной таблицы методов. Скрипт сканирует каждый сегмент кода в PE-файле на предмет любого места, указывающего вперёд на +0x4C байт. Обратите внимание, что компилятор Delphi выравнивает vftable по границе 4 байта (для оптимизации).
Например, следующий виртуальный адрес 0x0046E1C8 содержит смещение 0x0046E214, которое находится на 0x4C байт впереди текущего местоположения. Как показано в IDA:
.text:0046E1C8 ; Classes::TComponent *vftable_TDCP_misty1
.text:0046E1C8 14 E2 46 00 vftable_TDCP_misty1 dd offset off_46E214
Такой подход может давать ложные срабатывания, поэтому другие поля vftable проверяются на правдоподобные значения. Например, vmtInstanceSize проверяется на чрезмерность, а указатели на функции должны находиться в исполняемой секции. Во время тестирования частота ложных срабатываний была очень низкой, несмотря на метод полного перебора.
Каждая функция, найденная в vftable, проверяется на то, унаследована ли она от родителя или переопределена. Delphi не поддерживает множественное наследование, поэтому это можно определить, сравнив указатель в родительской vftable с тем же смещением.
Если оба указателя ссылаются на одну и ту же функцию, то она унаследована. Если у дочернего класса другой указатель, значит функция переопределена.
Основной результат работы инструмента — JSON-файл, который можно передавать в последующую обработку / другие инструменты. Однако включено несколько дополнительных форматов вывода.
Используйте опцию --save-tree, чтобы сгенерировать файл следующего вида:
TObject (at 0x0040112c)
|-- Exception (at 0x004081f8)
| |-- EAbort (at 0x00408260)
| |-- EAbstractError (at 0x00408ad4)
| |-- EAssertionFailed (at 0x00408a74)
| |-- EBcdException (at 0x004bd110)
| | +-- EBcdOverflowException (at 0x004bd16c)
| |-- EBitsError (at 0x0041ab04)
| |-- EComponentError (at 0x0041abbc)
| |-- EConvertError (at 0x00408850)
| |-- EDCP_cipher (at 0x0046a0ac)
| | +-- EDCP_blockcipher (at 0x0046a29c)
| |-- EDCP_hash (at 0x00469f20)
.. etc ..
PACKAGEINFO или DVCLAL) и настраивать сканирование для разных раскладок vftable.vmtTypeInfo в vftable).call [ecx+3Fh] с методом экземпляра).TComparer<System.Bindings.EvalProtocol.TPair<System.IInterface,System.Pointer>>, которые в IDA выглядят практически нечитаемыми.Пожалуйста, присылайте примеры бинарей, на которых этот инструмент не работает, чтобы его можно было улучшить.