Demo only — The unsigned
plugins.jsoncan be tampered with freely (replace hash + BPL together). For production, sign the manifest or embed hashes in a signed executable.
Hash-based plugin validation via manifest. Plugins are only loaded if their SHA256 hash matches the manifest.
HashValidationApp.exe
|
+-- DCC_UsePackage = rtl;fmx;FMXPluginFramework
|
+-- TManifestValidator.Create(plugins.json)
| reads sha256 fields from manifest
|
+-- FLoader.OnValidateModule := FManifest.ValidateModule
| callback checks SHA256 hash before LoadPackage
|
+-- SignedPlugin.bpl
+-- UnsignedOptional.bpl
+-- UnsignedRequired.bpl
- TManifestValidator from Plugin.Manifest as OnValidateModule callback
- plugins.json extended with sha256 fields
- Empty hash = no check (optional field)
- Wrong hash on a required plugin = exception
| File | Description |
|---|---|
| HashValidationApp.dpr | Host application with TManifestValidator |
| Source/uMain.pas + .fmx | MainForm -- displays loaded plugins |
| plugins.json | Manifest with sha256 fields |
| HashValidationApp.dproj | Delphi project (statically linked) |
| HashValidation.groupproj | Build group (Framework + DemoPlugins + App) |
| update-hashes.ps1 | Post-build script that auto-updates SHA256 hashes in plugins.json |
- Framework statically linked via
DCC_UsePackage=rtl;fmx;FMXPluginFramework TManifestValidator.Createreads plugins.json including sha256 fieldsOnValidateModule := FManifest.ValidateModule-- hook is set- For each BPL: compute SHA256, compare against manifest
- No hash in manifest = accept (backwards-compatible)
- Wrong hash +
required=true= exception, app does not start
{
"plugins": [
{
"name": "MyPlugin",
"file": "MyPlugin",
"required": true,
"sha256": "a1b2c3d4e5f6..."
}
]
}The sha256 field is optional. An empty string or missing field means: no hash check for this plugin.
Via Delphi code:
uses Plugin.Manifest;
Writeln(TManifestValidator.ComputeHash('C:\Path\To\MyPlugin.bpl'));Via command line (Windows):
certutil -hashfile MyPlugin.bpl SHA256
- Build the project via
HashValidation.groupproj(Framework + Plugins + App) - The post-build event automatically:
- Copies
plugins.jsonto the output directory - Runs
update-hashes.ps1to compute and insert SHA256 hashes for all BPLs
- Copies
- Start the app -- all 3 plugins load successfully
- To test rejection, tamper with a hash in
Bin\Win64_Release\plugins.json(e.g. change the first character):- With
required: false-> plugin is skipped, app continues - With
required: true-> exception, app does not start
- With
The plugins.json in the source directory has empty sha256 fields. The post-build script fills them automatically in the output copy after each build.
Hash check and Authenticode signature can be combined in the OnValidateModule callback:
function ValidateModule(const AFilePath: string): Boolean;
begin
Result := FManifest.ValidateModule(AFilePath)
and TSecurityValidator.VerifyAuthenticode(AFilePath);
end;- Manifest is unsigned (for production: sign the manifest itself or embed it in a signed EXE)
- Framework BPL is loaded by the OS before checks run (for full protection: use SecureBootstrap)
- No downgrade protection without versioning in the manifest