
Ein minimaler PE-Mapper, der DLLs direkt aus dem Speicher lädt und über eine saubere Plugin-Schnittstelle aufruft, ohne dass LoadLibrary benötigt wird.
Ein minimaler reflektiver PE-Mapper mit einer hot-swap-fähigen Plugin-Schnittstelle für Windows x64. Mappt eine DLL direkt aus einem Byte-Puffer im Speicher, löst deren Exporte auf und ruft über eine saubere IPlugin-ABI auf, ohne LoadLibrary zu berühren. Begleitcode zum Blogbeitrag über reflektive Loader und modulare Plugin-Architekturen.
Siehe die vollständige Ausarbeitung: 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
Der Harness liest die DLL in einen Byte-Puffer ein, mappt sie mit dem reflektiven Loader, löst die Plugin-Exporte auf und leitet den Befehl über die IPlugin-Schnittstelle weiter.
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 ein und implementiere die IPlugin-Schnittstelle:#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 */ }
};
Implementiere die fünf exportierten Funktionen (create_plugin, destroy_plugin, plugin_init, plugin_exec, plugin_cleanup) unter Verwendung von HeapAlloc/Placement-new für CRT-sichere modulübergreifende Allokation.
Füge eine CMakeLists.txt hinzu und registriere sie in der Root-CMakeLists.txt mit add_subdirectory().
Der Host muss nicht wissen, was dein Modul intern tut. Er mappt, löst auf, ruft init -> execute -> cleanup auf und macht weiter.
Der Mapper deckt die Grundlagen ab und hört dort bewusst auf:
Wenn ein Modul eines davon benötigt, erweitere entweder den Mapper oder lehne das Modul frühzeitig mit einem klaren Fehler ab. Stille Halbunterstützung ist der schlimmste Fehlermodus.