一个极简的PE映射器,直接从内存加载DLL并调用干净的插件接口,无需LoadLibrary。
一个极简的反射式 PE 映射器,带有适用于 Windows x64 的热插拔插件接口。它直接从内存中的字节缓冲区映射 DLL,解析其导出,并通过干净的 IPlugin ABI 进行调用,而无需接触 LoadLibrary。这是关于反射式加载器和模块化插件架构的博客文章的配套代码。
# 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
测试框架将 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,然后继续。
映射器处理基础功能,并有意止步于此:
如果模块需要其中任何一项,要么扩展映射器,要么尽早以明确的错误拒绝该模块。静默的半支持是最糟糕的失败模式。