Реверсим Delphi без IDR

Ещё в группе «Общее»
- Операция Chewbacca
В конце июня команда PT ESC в ходе расследования инцидентов обнаружила новую группу, нацеленную как минимум…
- Din, din — кто там?
Din, din — кто там? 🔔 Группа киберразведки экспертного центра безопасности Positive Technologies обнаружила новую группировку,…
- Enterprise-grade validation system with schema support
Enterprise-grade validation system with schema support (c) Автор десятка троянов, забывший добавить "Enterprise-grade" обфускацию Мы обнаружили…
- Минус один пернатый вор — плюс сто очков рейтинга!
Минус один пернатый вор — плюс сто очков рейтинга! 😵 Команда Threat Intelligence экспертного центра безопасности…
- DragonDoll: матрешка в мире Android-шпионов
DragonDoll: матрешка в мире Android-шпионов 🪆 В начале этой весны специалисты PT ESC обнаружили неизвестный ранее…
Когда активно занимаешься реверсом, рано или поздно возникает ситуация, когда на твоем пути появляется исполняемый файл на Delphi. Анализ объектов в Delphi требует особого подхода, и вручную это делать сложно. Однако такой анализ можно значительно ускорить с помощью автоматизации, если знать, как именно устроена структура объектов.
🕵️ Первый шаг при анализе Delphi — не забыть переключить параметр компилятора в
Options → Compiler Options → Compiler, тогда IDA будет лучше обрабатывать вызовы функций.Классы в Delphi создаются через функцию
ClassCreate, которая получает на вход указатель на структуру класса и вызывает в нем функцию Tobject_NewInstance путем вычитания оффсета из указателя на VMT. 👀 Сама структура класса в Delphi выглядит следующим образом (пример на скриншоте 1):
struct DelphiClassInternal
{
DWORD* vmt;
DWORD* InterfaceTable; используется только для интерфейсов
DWORD* PAutoTable;
DWORD* PInitTable;
DWORD* TypeInfo;
DWORD* FieldTable;
DWORD* MethodTable;
DWORD* DynamicMethodTable;
}
Code language: plaintext (plaintext)💼 Рассмотрим содержимое полей
TypeInfo, MethodTable и FieldTable подробнее, поскольку в них больше всего полезной для анализа информации.➡️ TypeInfo
В Delphi каждый тип объекта имеет свой идентификатор. Как видно на скриншоте 2, для нашего объекта выставлен идентификатор 7 — тип
Class. В зависимости от этого типа, для объекта указывается соответствующий контекст. Для классов это информация о Property и указатель на родительский тип. Зная имя Property, нетрудно понять и разметить Get/Set-функции. Восстановление этих имен позволяет сильно упростить восприятие некоторых блоков кода. Пример на скриншоте 3.➡️ MethodTable
Внимательный читатель заметит, что на скриншоте 1 присутствуют имена некоторых методов. Достать их можно, заглянув в таблицу опубликованных (Published) методов (текущего и родительского классов). Delphi не хранит информацию о других типах методов: приватных, защищенных и публичных. Помимо имени, там приводятся: возвращаемый тип, количество аргументов, их типы и имена.
Псевдоструктуру метода можно представить так (пример на скриншоте 4):
struct CMArg
{
DWORD* TypeInfo;
WORD UNK;
BYTE NameLen;
char Name[];
BYTE UNK2[3];
}
struct ClassPubMethod
{
WORD EntrySize;
DWORD* MethodPtr;
BYTE NameLen;
char Name[];
WORD W_UNK1;
DWORD* ReturnType;
WORD W_UNK2;
BYTE ArgCount;
CMArg Args[];
}
Code language: plaintext (plaintext)Из-за механизма наследования методов в Delphi восстановление даже части имен методов имеет большую пользу, если сделать это глобально, для всех классов. Затем это можно использовать среди прочего и для генерации структуры VMT класса с осмысленными именами. Пример — на скриншоте 5.
➡️ FieldTable
Заглянув в
Class → FieldTable, можно найти большое количество информации о переменных (пример на скриншоте 6). Представлена она может быть в двух вариантах: 1. В виде имени, оффсета и номера типа переменной (из таблицы типов). Первые два байта в
FieldTable — количество элементов в этой таблице, следующие четыре — указатель на таблицу типов.2. В виде имени, оффсета и указателя на тип переменной (таблица начинается сразу после таблицы из п. 1).
Структура переменных имеет следующий вид:
struct VarTypeTable
{
WORD Count;
DWORD* Entries[];
}
struct ClassVar
{
DWORD* TypeInfo;
WORD VarOffset;
WORD UNK;
BYTE NameLen;
char Name[];
}
struct TableClassVar
{
WORD VarOffet;
WORD UNK;
WORD TableTypeNum;
BYTE NameLen;
char Name[];
}
Code language: plaintext (plaintext)Исходя из полученной информации о переменных можно составить структуру класса (нужно не забыть, что переменные также наследуются из родительских классов). Пример — на скриншоте 7.
🤔 Резюме: в Delphi присутствует большое количество RTTI-информации, за счет которой можно относительно просто разметить большое количество функций или восстановить структуру классов для упрощения статического анализа.






#TI #Delphi #Reverse
@ptescalator
Ещё в группе «Общее»
- Операция Chewbacca
В конце июня команда PT ESC в ходе расследования инцидентов обнаружила новую группу, нацеленную как минимум…
- Din, din — кто там?
Din, din — кто там? 🔔 Группа киберразведки экспертного центра безопасности Positive Technologies обнаружила новую группировку,…
- Enterprise-grade validation system with schema support
Enterprise-grade validation system with schema support (c) Автор десятка троянов, забывший добавить "Enterprise-grade" обфускацию Мы обнаружили…
- Минус один пернатый вор — плюс сто очков рейтинга!
Минус один пернатый вор — плюс сто очков рейтинга! 😵 Команда Threat Intelligence экспертного центра безопасности…
- DragonDoll: матрешка в мире Android-шпионов
DragonDoll: матрешка в мире Android-шпионов 🪆 В начале этой весны специалисты PT ESC обнаружили неизвестный ранее…



