
Un mapeador PE mínimo que carga DLLs directamente desde memoria y llama a una interfaz de plugin limpia, sin necesidad de LoadLibrary.
Un mapeador PE reflexivo mínimo con una interfaz de plugin intercambiable en caliente para Windows x64. Mapea una DLL directamente desde un búfer de bytes en memoria, resuelve sus exportaciones y llama a una ABI IPlugin limpia sin tocar LoadLibrary. Código complementario para la entrada del blog sobre cargadores reflexivos y arquitecturas de plugins modulares.
Consulta el análisis completo: 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
El harness lee la DLL en un búfer de bytes, la mapea con el cargador reflexivo, resuelve las exportaciones del plugin y despacha el comando a través de la interfaz 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 e implementa la interfaz 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 */ }
};
Implementa las cinco funciones exportadas (create_plugin, destroy_plugin, plugin_init, plugin_exec, plugin_cleanup) usando HeapAlloc/placement new para una asignación segura entre módulos compatible con el CRT.
Añade un CMakeLists.txt y regístralo en el CMakeLists.txt raíz con add_subdirectory().
El host no necesita saber qué hace tu módulo internamente. Mapea, resuelve, llama a init -> execute -> cleanup y continúa.
El mapeador cubre lo básico y deliberadamente se detiene ahí:
Si un módulo necesita alguno de estos, extiende el mapeador o rechaza el módulo desde el principio con un error claro. El soporte parcial silencioso es el peor modo de fallo.