справочник по плагинам API

Общий интерфейс обратного вызова для пользовательских нативных плагинов.

DE Decompiler использует общий ABI плагинов VB Decompiler. Имена экспортируемых функций сохраняют префикс VBDecompilerPlugin. Общие идентификаторы компиляторов и исторические имена команд VB/FRX относятся к API и не определяют поддерживаемые продуктом входные форматы. Для каждой операции проверяйте данные, доступные в текущем проекте DE Decompiler.

Данная документация описывает интерфейс плагина, общий для VB Decompiler и DE Decompiler. Система плагинов позволяет анализировать, изменять или расширять декомпилированный код и внутренние структуры приложения с помощью общей библиотеки (DLL).
1. Обзор архитектуры
Система плагинов работает на основе модели обратных вызовов:
  • Хост-декомпилятор загружает ваш DLL-плагин.
  • Он вызывает ваши экспортируемые функции для получения имени плагина и информации об авторе.
  • Вызывается VBDecompilerPluginLoad, передавая указатель на его внутренний Движок обратных вызовов (Callback Engine).
  • Ваш плагин взаимодействует с хостом, вызывая функции этого Движка с использованием конкретных идентификаторов действий (vlType ).
2. Экспортируемые функции
Ваша DLL должна экспортировать следующие stdcall функции:
VBDecompilerPluginName
Вызывается хостом для получения отображаемого имени вашего плагина.
void __stdcall VBDecompilerPluginName( HWND VBDecompilerHWND, // Дескриптор главного окна HWND RichTextBoxHWND, // Дескриптор окна редактора кода char* Buffer, // Целевой буфер (100 байт, ANSI) int Reserved // Зарезервировано );
Пример использования: Скопируйте стандартную ASCII-строку (максимум 100 символов) с именем вашего плагина в Buffer.
VBDecompilerPluginAuthor
Вызывается для получения контактной информации автора.
void __stdcall VBDecompilerPluginAuthor( HWND VBDecompilerHWND, HWND RichTextBoxHWND, char* Buffer, // Целевой буфер (ANSI) int Reserved );
Пример использования: Скопируйте строку вида "Author Name, email@domain.com" в Buffer.
VBDecompilerPluginLoad
Основная точка входа, где выполняется логика вашего плагина.
void __stdcall VBDecompilerPluginLoad( HWND VBDecompilerHWND, HWND RichTextBoxHWND, char* Buffer, // Зарезервировано/Буфер void* PluginEngine // <--- Указатель на функцию обратного вызова );
Пример использования: Сохраните PluginEngine указатель. Вы будете использовать его для вызова команд GetValue / SetValue (см. раздел «Движок обратного вызова» ниже).
3. Движок обратного вызова
Взаимодействие с хостом осуществляется через единственный указатель функции обратного вызова, предоставляемый в PluginEngine.
Сигнатура функции:
typedef wchar_t* (__stdcall *TVBDPluginEngine)( int vlType, // Идентификатор команды (действие) int vlNumber, // Первичный индекс (идентификатор формы/модуля) int vlFnNumber, // Вторичный индекс (идентификатор функции) char* vlNewValue // Значение для установки (строка ANSI) или NULL для команд получения );
Примечание: Движок принимает строки ANSI (char*) для входных данных, но возвращает строки Unicode (wchar_t*) для результатов.
4. Справочник по командам (vlType)
Следующие константы используются в качестве vlType аргумента для выполнения конкретных действий.
Глобальные команды проекта
Операции, связанные с файлом проекта или глобальными настройками. vlNumber и vlFnNumber обычно соответствуют 0.
IDКонстантаОписание
1GetVBProjectПолучить полный текст декомпилированного файла проекта.
2SetVBProjectЗаменить содержимое файла проекта.
3GetFileNameПолучить полный путь к анализируемому файлу.
4IsNativeCompilationВозвращает "1", если целевой файл скомпилирован в нативный код, и "0" для P-Code.
5ClearAllBuffersОчищает внутренние структуры декомпилятора. Используйте этот метод, если ваш плагин реализует полную пользовательскую декомпиляцию для нового языка.
6GetCompilerВозвращает тип компилятора: 1=VB, 2=.NET, 3=Delphi, 4=Неизвестно.
7IsPackedВозвращает "1", если файл упакован/сжат, и "0" в противном случае.
56GetVBDecompilerPathВозвращает путь к исполняемому файлу DE Decompiler.
100UpdateAllПрименяет изменения и обновляет графический интерфейс (GUI). Обязательно после установки значений, чтобы пользователь увидел изменения.
64GetProductNameНеобязательная загруженная идентичность хоста, независимая от анализируемого компилятора; см. SDK 26.6 ниже.
Элементы управления интерфейсом
Управление элементами интерфейса DE Decompiler.
IDКонстантаОписание
8SetStackCheckBoxValueУстановить «Парсить парам. из стека» (Parse stack parameters) состояние флажка. "1" = отмечен, "0" = не отмечен.
9SetAnalyzerCheckBoxValueУстановить «Анализ и оптимизация кода» (Procedure analyzer and optimizer) состояние флажка. "1" = отмечен, "0" = не отмечен.
50GetActiveTextПолучить текст, отображаемый в активном окне кода.
51SetActiveTextУстановить текст в активном окне кода.
52GetActiveDisasmTextПолучить сырой текст дизассемблирования окна дизассемблера.
53SetActiveDisasmTextУстановить сырой текст дизассемблирования в окно дизассемблера.
54SetActiveTextLineПрокрутить или перейти к указанному номеру строки (передаётся как строка в vlNewValue).
55GetActiveModuleCoordinatsПолучить идентификаторы активного представления. Перед использованием проверьте возвращаемое значение.
58SetStatusBarTextОтобразить пользовательское сообщение в строке состояния приложения.
Формы
Операции с восстановленными формами. vlNumber: индекс формы (на основе 0).
IDКонстантаОписание
10GetVBFormNameПолучить имя формы.
11SetVBFormNameПереименовать форму.
12GetVBFormПолучить декомпилированные свойства формы.
13SetVBFormУстановить свойства формы.
14GetVBFormCountВозвращает общее количество форм в проекте.
Модули
Операции со стандартными модулями (.bas) или модулями классов (.cls). vlNumber: Индекс модуля (на основе 0).
IDКонстантаОписание
30GetModuleNameПолучить имя модуля.
31SetModuleNameПереименовать модуль.
32GetModuleПолучить заголовок с декомпилированными объявлениями модуля.
33SetModuleУстановить заголовок с декомпилированными объявлениями модуля.
34GetModuleStringReferencesПолучить список ссылок на строки, используемые в данном модуле.
35SetModuleStringReferencesУстановить ссылки на строки.
36GetModuleCountВозвращает общее количество модулей.
Процедуры / Функции
Операции с конкретными функциями внутри модуля.
vlNumber: Индекс модуля.
vlFnNumber: Индекс функции (на основе 0) в пределах данного модуля.
IDКонстантаОписание
20GetSubMainПолучить код точки входа (Sub Main). (Аргументы индекса игнорируются).
21SetSubMainУстановить код точки входа.
40GetModuleFunctionNameПолучить имя конкретной функции.
41SetModuleFunctionNameПереименовать функцию.
42GetModuleFunctionAddressПолучить виртуальный адрес (VA) функции в памяти.
43SetModuleFunctionAddressУстановить адрес функции.
44GetModuleFunctionПолучить декомпилированный код функции.
45SetModuleFunctionУстановить код функции.
46GetModuleFunctionStrRefПолучить строковые ссылки, специфичные для данной функции.
47SetModuleFunctionStrRefУстановить строковые ссылки для данной функции.
48GetModuleFunctionCountВозвращает количество функций в указанном модуле.
57GetModuleFunctionCodeПолучить код функции в режиме «Быстрая декомпиляция» (если данная функция в данный момент не обрабатывается).
70GetModuleFunctionDisasmПолучить дизассемблирование (ASM) функции.
71SetModuleFunctionDisasmУстановить дизассемблирование функции.
Ресурсы (FRX)
Доступ к ресурсам в бинарном формате (иконки/изображения). vlNumber: Индекс иконки.
IDКонстантаОписание
60GetFrxIconCountКоличество зарегистрированных оригинальных изображений (индексы с нуля), включая нативные растровые листы ImageList.
61GetFrxIconOffsetУстаревший скорректированный офсет: фактический офсет изображения минус 8. Перед чтением прибавьте 8.
62GetFrxIconSizeУстаревший скорректированный размер: фактическое количество байт изображения плюс 8. Перед чтением вычтите 8.
63GetFrxImageListInfoНеобязательные метаданные IL1 для зарегистрированного нативного цветного растрового изображения DFM ImageList; см. ниже SDK 26.6.
5. Нативные изображения и необязательные команды SDK 26.6
Эта общая ревизия SDK реализована через VB Decompiler 26.6 и DE Decompiler 26.6. Команды 63 и 64 являются необязательными, только для чтения геттерами. Подпись обратного вызова, экспортируемые символы и существующие номера команд не изменены. Вызывайте обратный вызов в основном потоке хост-приложения.
Зарегистрированные изображения: команды 60–62
Индексы изображений отсчитываются с нуля. GetFrxIconCount возвращает количество зарегистрированных оригинальных изображений, а не количество логических иконок внутри ImageLists. Читайте их исходные байты из исполняемого файла или DLL, возвращаемой GetFileName (команда 3).
Для изображения с фактическим офсетом в файле P и фактивным количеством байт N, команда 61 возвращает P - 8 , а команда 62 возвращает N + 8. Прибавьте 8 к возвращённому офсету и вычтите 8 из возвращённого размера:
Offset := GetInteger(GetFrxIconOffset, ImageIndex);
Size := GetInteger(GetFrxIconSize, ImageIndex);
FileStream.Position := Offset + 8;
ImageStream.CopyFrom(FileStream, Size - 8);
Проверьте индекс, скорректированный диапазон и сигнатуру полезной нагрузки перед чтением. Эти унаследованные корректировки не подразумевают наличия физического заголовка FRX в исполняемом файле Delphi. Полученная полезная нагрузка начинается с её сигнатуры BMP, PNG, JPEG, GIF, ICO или CUR; префиксы свойства DFM и заголовки контейнера ImageList исключены.
DE Decompiler регистрирует изображения во время декодирования двоичных значений формы DFM. Независимо закодированные изображения коллекции имеют отдельные записи. Оригинальное цветное растровое изображение и необязательная маска нативного ImageList остаются обычными записями растровых изображений, поэтому существующие плагины могут продолжать отображать или экспортировать полные листы.
63 — GetFrxImageListInfo
Передайте существующий индекс изображения в vlNumber; передайте ноль для vlFnNumber и нулевой указатель ввода. Для распознанного нативного цветного растрового изображения DFM ImageList текущий ответ:
IL1;<Count>;<Width>;<Height>;<Flags>;<MaskOffset>;<MaskSize>
ПолеЗначение
CountКоличество логических изображений, исключая резервную ёмкость.
Width, HeightРазмеры ячейки в пикселях.
FlagsИсходные флаги ImageList. Бит 0 указывает на наличие маски; формат цвета $20 указывает ILC_COLOR32.
MaskOffsetФактическое смещение файла сигнатуры растрового изображения маски. Не добавляйте 8.
MaskSizeФактное количество байт маски. Не вычитайте 8.
Числовые поля представлены в десятичном формате и разделены точками с запятой. Оба поля маски равны нулю, если маска отсутствует. Цветные данные по-прежнему используют команды 61–62 и их унаследованную корректировку. Команда 63 возвращает только метаданные: она не изменяет индексы, не растеризует ячейки и не дублирует данные изображений в хосте.
Текущая IL1 реализация распознаёт нативную версию потока $0101 с растровыми листами BMP. Обычное изображение, неподдерживаемый поток или более старшая версия хоста могут вернуть пустую строку; недействительные индексы возвращают Error. Рассматривайте пустые ответы, ошибки, некорректные данные и ответы с неизвестной версией как неподдерживаемые и сохраняйте обработку целого изображения везде, где доступна исходная запись изображения.
Для индекса ячейки K, используйте логические координаты верхнего левого угла:
Columns := ColorBitmap.Width div CellWidth;
X := (K mod Columns) * CellWidth;
Y := (K div Columns) * CellHeight;
Требовать 0 <= K < Count. Проверить геометрию и диапазоны файлов, а также учесть DIB-сканлайны с нижним началом. Применить соответствующую однобитовую маску или предварительно умноженный альфа-канал. В более старых 32-битовых списках может встречаться полностью нулевой альфа-канал; в этом случае маска остаётся резервным вариантом.
Предоставленный shared/PluginSDK.pas и shared/modFrxImageList.pas реализует геттеры, парсер и читатель ImageList, используемые обновлённым просмотрщиком. В приведённом ниже фрагменте предполагается, что FileStream открыт для анализируемого файла:
InfoText := GetString(GetFrxImageListInfo, ImageIndex);
if ParseFrxImageListInfo(InfoText, Info) then begin
  ColorOffset := GetInteger(GetFrxIconOffset, ImageIndex) + 8;
  ColorSize := GetInteger(GetFrxIconSize, ImageIndex) - 8;
  Images := TFrxImageList.Create(FileStream, ColorOffset, ColorSize, Info);
  try
    Icon := Images.Icon(0);
    try
      Icon.SaveToFile('Image_0.ico');
    finally
      Icon.Free;
    end;
  finally
    Images.Free;
  end;
end;
Читатель проверяет диапазоны и геометрию и использует общие элементы управления Windows для декодирования нативного списка. Перебрать каждый распознанный список один раз. Подавить его отдельную запись маски, сравнив фактическое смещение маски с каждым скорректированным смещением изображения плюс 8. Экспортируемые ячейки ICO-файлов являются производными изображениями со списка масок/альфа-канала; автономные изображения сохраняют свои исходные полезную нагрузку.
64 — GetProductName
Передайте нули для обоих индексов и нулевой указатель ввода. Результатом будет VB Decompiler или DE Decompiler, полученный из идентификатора загруженного хоста независимо от компилятора анализируемого файла.
Скопируйте каждую возвращаемую UTF-16-строку немедленно: указатель принадлежит хосту и остаётся действительным только до следующего обратного вызова. Предоставленный DecompilerProductName помощник проверяет ответ и переходит к VB Decompiler на более старых хостах. Сохраните исторические экспорты SDK, пути реестра и ключи локализации без изменений.
Совместимость и загрузки
  • Существующие плагины продолжают использовать команды 60–62 без изменений.
  • Обновлённый просмотрщик сохраняет поведение целого изображения на более старых хостах.
  • Распознанные нативные DFM-списки используют команду 63 для индивидуальных предварительных просмотров ячеек и экспорта ICO; независимо закодированные изображения коллекций остаются обычными записями.
  • VB5/6 и графика .NET сохраняют свои существующие пути извлечения.
  • Эти новые геттеры не изменяют исходный файл, восстановленный код, формы или текущий выбор.
Скачать общий SDK, включая ссылку на необязательную команду и вспомогательные средства Delphi. Ознакомьтесь с предоставленными дополнениями SDK 26.6. См. FRX Image Viewer для описания сценария работы пользователя.

SDK 26.6: открытые элементы, отметки и полные адреса

DE Decompiler 26.6 поддерживает следующие дополнительные команды через существующий callback PluginEngine. Вызывайте API в главном потоке приложения. Копируйте возвращённую строку UTF-16 до следующего callback; входные строки сохраняют существующий формат ANSI с завершающим нулём.

IDКонстантаАргументы и результат
65GetDisplayedTreeItemБез аргументов. Возвращает TREE1;kind;module;function;form для открытого содержимого независимо от выделения в дереве; при отсутствии актуального элемента — пустую строку.
66GetModuleFunctionMarkИндексы модуля и функции. Возвращает 0 или 1 либо пустую строку, если функции нет в текущем дереве.
67SetModuleFunctionMarkИндексы модуля и функции; на входе 0 или 1. Возвращает 1 при успехе либо пустую строку, если функции нет в текущем дереве.
68FindModuleFunctionByVAНа входе шестнадцатеричный адрес; в аргументе модуля — номер совпадения с нуля. Возвращает module,function для точного совпадения либо пустую строку, когда совпадений больше нет.
69GetModuleFunctionVAИндексы модуля и функции. Возвращает полный беззнаковый виртуальный адрес десятичной строкой с учётом PE ImageBase для x64.

В TREE1 возможны виды function, module, unit, form, usercontrol, otherform, submain, root и other. Неиспользуемые индексы равны -1; юнит Delphi не представляется индексом модуля. Команда 55 по-прежнему возвращает координаты последней активной процедуры и может сохранять их при показе формы.

Отметки функций соответствуют действию клавиши Space. Чтение или установка отметки не открывает и не декомпилирует функцию, не меняет выделение и позицию курсора. Перестроение дерева может удалить отметки; эти команды не добавляют их сохранение в VDD.

Адрес на входе всегда шестнадцатеричный, даже если содержит только цифры; допустимы префиксы 0x и $. Поиск выполняется по точному адресу и позволяет перебрать функции с общим адресом. Для x64 принимаются полный VA и адрес модели совместимости. Команда 42 сохраняет прежний знаковый 32-битный результат. Это адреса нативного кода, а не токены метаданных.

Старые хосты возвращают пустую строку для неизвестных команд. Неверные индексы или входные данные, отклонённый вызов вне главного потока и запрещённая запись возвращают Error. Если полный адрес x64 недоступен, также возвращается Error. Явно обрабатывайте пустую строку и Error, сохраняя прежний резервный способ работы.

Current := GetString(GetDisplayedTreeItem);
Coords := FindFunctionByVA('0x89CB90');
State := GetString(GetModuleFunctionMark, 4, 51);
Reply := SetStringResult(SetModuleFunctionMark, '1', 4, 51);
FullVA := GetString(GetModuleFunctionVA, 4, 51);