
Минимальный PE-маппер, который загружает DLL напрямую из памяти и вызывает их через чистый интерфейс плагинов, без необходимости в LoadLibrary.
Минимальный рефлективный PE-маппер с интерфейсом горячей замены плагинов для Windows x64. Отображает DLL прямо из байтового буфера в памяти, разрешает её экспорты и вызывает их через чистый ABI IPlugin, не затрагивая LoadLibrary. Сопутствующий код к посту в блоге о рефлективных загрузчиках и модульных архитектурах плагинов.
Полный разбор: Using Reflective Loaders to Replace LoadLibrary for Hot-Swappable Modules in C++
# Configure
cmake -B build
# Build
cmake --build build --config Release
# The build produces:
# build/Release/cmdplugin.dll (example plugin)
# build/Release/harness.exe (test harness)
# Map cmdplugin.dll from disk, run "dir C:\"
harness.exe cmdplugin.dll "dir C:\"
# Default: loads cmdplugin.dll, runs "whoami"
harness.exe
Harness считывает DLL в байтовый буфер, отображает её с помощью рефлективного загрузчика, разрешает экспорты плагина и передаёт команду через интерфейс IPlugin.
ReflectivePluginLoader/
├── CMakeLists.txt # Root build
├── Include/
│ ├── IPlugin.h # Plugin ABI (TaskApi, IPlugin, helpers)
│ └── ReflectiveLoaderEngine.h # PE mapper + export resolver
├── Modules/
│ └── CmdPlugin/
│ ├── cmdplugin.cpp # Example: command execution plugin
│ └── CMakeLists.txt
├── Testing/
│ ├── main.cpp # Test harness (loads DLL from file)
│ └── CMakeLists.txt
└── Tools/
└── file2hex.py # Convert a DLL to a C byte array
Modules/.IPlugin.h и реализуйте интерфейс IPlugin:#include "IPlugin.h"
class MyPlugin : public IPlugin {
public:
void init() const override { /* setup */ }
void execute(TaskApi* task) const override { /* do work */ }
void cleanup() const override { /* teardown */ }
};
Реализуйте пять экспортируемых функций (create_plugin, destroy_plugin, plugin_init, plugin_exec, plugin_cleanup), используя HeapAlloc/placement new для безопасного межмодульного выделения памяти с учётом CRT.
Добавьте CMakeLists.txt и зарегистрируйте его в корневом CMakeLists.txt с помощью add_subdirectory().
Хосту не нужно знать, что ваш модуль делает внутри. Он отображает, разрешает, вызывает init -> execute -> cleanup и продолжает работу.
Маппер обрабатывает основы и намеренно на этом останавливается:
Если модулю нужно что-то из этого, либо расширьте маппер, либо отклоните модуль на раннем этапе с понятной ошибкой. Молчаливая частичная поддержка — худший режим отказа.