ShieldCore is a cross-platform plugin protection framework that encrypts, signs, and loads plugins with runtime integrity and anti-tampering checks. The system is split into three main logical layers:
- Host Application — loads and validates plugins
- Plugin Layer — arbitrary code packaged as
.plgfiles - Packer Tool — converts DLLs/SOs into encrypted
.plgpackages
include/shieldcore/
├── common.hpp # Shared types, file I/O, binary structures
├── crypto_utils.hpp # AES-256-GCM, SHA256, RSA signing
├── plugin_loader.hpp # In-memory DLL/SO loading
├── integrity_checker.hpp # Host executable hash verification
├── anti_debug.hpp # Debugger detection (startup + periodic)
├── http_client.hpp # Backend validation, license activation
└── memory_protection.hpp # Memory region verification
src/host/
├── main.cpp # Entry point, orchestration
├── crypto_utils.cpp # OpenSSL bindings
├── plugin_loader.cpp # Platform-specific DLL/SO loading
├── integrity_checker.cpp # SHA256 file hashing
├── anti_debug.cpp # ptrace/IsDebuggerPresent detection
├── http_client.cpp # libcurl JSON requests
└── memory_protection.cpp # Memory page protection checks
src/plugin/
└── plugin.cpp # Sample plugin exporting Execute()
src/tools/
└── packer.cpp # Encrypts + signs plugins
Host Startup
↓
[1] Anti-Debug Check (IsDebuggerPresent)
↓
[2] Host Self-Integrity Check (SHA256 of executable)
↓
[3] Load .plg File into Memory
↓
[4] Parse Plugin Header (magic, version, nonce, signature)
↓
[5] AES-256-GCM Decryption (using kDemoAesKey + nonce)
↓
[6] Compute SHA256 of Decrypted Payload
↓
[7] Verify Hash Matches Header Hash
↓
[8] RSA Signature Verification (using embedded public key)
↓
[9] Backend Validation (POST /validate with plugin_id + hwid)
↓
[10] In-Memory Plugin Load (dlopen/memfd or equivalent)
↓
[11] Resolve Execute() Symbol
↓
[12] Launch Periodic Checks:
├─ Debugger check every 5 seconds
├─ Memory protection check every 10 seconds
└─ Host integrity check every 10 seconds
↓
[13] Call Execute()
↓
[14] Cleanup & Exit
| Checkpoint | What | Why | When |
|---|---|---|---|
| Anti-debug | ptrace(PTRACE_TRACEME) or IsDebuggerPresent() |
Prevent live inspection | Startup + every 5s |
| Host integrity | SHA256 of executable | Detect tampering | Startup + every 10s |
| Plugin magic | Verify "SCPLG" header |
Reject corrupted/fake files | On load |
| Decryption | AES-256-GCM with nonce | Ensure only authorized payloads load | On load |
| Hash verification | SHA256 match | Detect payload tampering | On load |
| Signature verification | RSA-2048 signature | Authenticate plugin origin | On load |
| Backend validation | Server response | License/revocation check | On load |
| Memory protection | Page permissions | Detect code injection/patching | Every 10s during execution |
- PluginHeader struct (packed binary layout, 321 bytes)
- Helper utilities:
toHex(),readFileBytes(),writeFileBytes() - Type aliases:
ByteBuffer, size constants
- SHA256 hashing via OpenSSL
- AES-256-GCM encrypt/decrypt (authenticated encryption)
- RSA-2048 sign/verify using embedded PEM keys
- Key management:
embeddedPublicKeyPem(),embeddedPrivateKeyPem()
- Windows:
LoadLibrary()with reflective DLL loading (stub) - Linux/macOS:
memfd_create()+dlopen(/proc/self/fd/...) - Symbol resolution:
dlsym()orGetProcAddress() - Handles cleanup on unload
- Compute SHA256 of files on disk
- Compare against hardcoded or environment-provided hash
- Exit if mismatch detected
- Startup: Single check via
ptrace(PTRACE_TRACEME)orIsDebuggerPresent() - Runtime: Background thread checking every 5 seconds
- Exit immediately if debugger detected
- validateWithBackend() — POST
/validatewith plugin_id + hwid - activateLicense() — POST
/activatewith license_key + nonce + timestamp - Nonce generation for replay protection
- Parse JSON responses for
valid/revokedstatus
- Verify page protections (detect RWX regions)
- Periodic thread checking every 10 seconds during plugin execution
- Can expand to check for code caves, patched jumps, etc.
Three background threads run during plugin execution:
main thread:
- Load plugin
- Call Execute()
- Wait for completion
integrityThread (spawned before Execute):
- Every 10 seconds: verify host executable hash
- Exit(1) if mismatch
debugCheckThread (spawned before Execute):
- Every 5 seconds: check for attached debugger
- Exit(1) if debugger present
memoryCheckThread (spawned before Execute):
- Every 10 seconds: verify memory page protections
- Can be extended for tampering detection
All three are stopped cleanly after Execute() returns.
Binary layout (little-endian, 321 byte header + payload):
[HEADER - 321 bytes]
Magic (5 bytes): "SCPLG"
Version (4 bytes): uint32
Flags (4 bytes): uint32
PayloadLength (8 bytes): uint64
Nonce (12 bytes): AES-GCM nonce
PayloadHash (32 bytes): SHA256 of decrypted payload
Signature (256 bytes): RSA-2048 signature of hash
[PAYLOAD - variable length]
Encrypted DLL/SO bytes (AES-256-GCM encrypted)
[TAG - 16 bytes]
AES-GCM authentication tag
- AES Key: 32-byte hardcoded demo key (use
SHIELDCORE_PRIVATE_KEY_PEMenv var during development) - RSA Keys: Embedded PEM strings; override with
SHIELDCORE_PRIVATE_KEY_PEMandSHIELDCORE_PUBLIC_KEY_PEM - Nonce: Random 12 bytes generated per encryption, stored in header
ptrace(PTRACE_TRACEME)for debugger detectionmemfd_create()for in-memory plugin loading/proc/self/exefor executable path resolution- GCC/Clang compilation
sysctlsyscalls for debugger detection (not yet implemented; currently uses ptrace)dlopen()with in-memory file descriptor approach/proc/self/exefallback toreadlink(/proc/self/exe)or_dyld_get_image_name()- Clang compilation with
-fPICand-dynamiclib
IsDebuggerPresent()for debugger detectionLoadLibrary()from memory (reflective DLL loading not yet fully implemented)GetProcAddress()for symbol resolution- MSVC or MinGW-w64 compilation
make release-O2optimization-DNDEBUGpreprocessor flag- Link-time optimization (
-flto) on Linux/macOS
make debug-O0no optimization-gdebug symbols- Full stack traces available
make release STRIP_SYMBOLS=1- Strips all debug symbols (
-slinker flag) - Reduces binary size and reverse-engineering surface
# Ubuntu/WSL
sudo apt install build-essential make libssl-dev libcurl4-openssl-dev
# macOS
brew install openssl curl
# Windows (MSYS2)
pacman -S base-devel openssl curlcd /path/to/project
make releaseBinaries appear in build/:
hostapp(Linux/macOS) orhostapp.exe(Windows)plugin.so(Linux),plugin.dylib(macOS), orplugin.dll(Windows)packerorpacker.exe
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out build/test_private.pem
openssl pkey -in build/test_private.pem -pubout -out build/test_public.pemexport SHIELDCORE_PRIVATE_KEY_PEM="$(cat build/test_private.pem)"
export SHIELDCORE_PUBLIC_KEY_PEM="$(cat build/test_public.pem)"./build/packer ./build/plugin.so ./build/plugin.plgOutput: build/plugin.plg (encrypted, signed package)
./build/hostapp ./build/plugin.plgExpected output:
ShieldCore plugin executed
Start a mock backend server (e.g., HTTP server listening on port 8080 with a /validate endpoint):
./build/hostapp ./build/plugin.plg http://127.0.0.1:8080The host will POST to /validate with:
{
"plugin_id": "plugin.plg",
"hwid": "linux-dev-hwid"
}Respond with {"status": "valid"} to allow execution.
| Variable | Purpose | Example |
|---|---|---|
SHIELDCORE_PRIVATE_KEY_PEM |
Override private key (packer signing) | $(cat my_key.pem) |
SHIELDCORE_PUBLIC_KEY_PEM |
Override public key (host verification) | $(cat my_key.pub.pem) |
SHIELDCORE_EXPECTED_HOST_HASH |
Expected SHA256 of host executable | abc123def456... |
- Write a C++ file with
extern "C" void Execute()export - Compile to
.so/.dylib/.dll - Pack with the packer tool
- Run with the host
- Integrity checks: Edit integrity_checker.cpp
- Debugger detection: Edit anti_debug.cpp
- Memory checks: Expand memory_protection.cpp
- Modify http_client.cpp to call real license API
- Implement proper HWID generation for each platform
- Add timestamp + nonce validation server-side
# Per-build randomization (future enhancement)
make release BUILD_VARIANT=v1
# Obfuscation flags (future enhancement)
make release OBFUSCATE=1- Attacker with full system access can bypass all client-side protections
- Private key material must be protected server-side
- Backend API must use TLS and proper authentication
- HWID generation is weak; improve with machine certificates or hardware attestation
- This is an anti-piracy delay, not a security boundary
- Replace demo keys with production RSA-2048 key material
- Implement real backend for license validation and revocation
- Harden HWID generation (machine certificates, TPM, etc.)
- Add code obfuscation and CFI (control flow integrity) checks
- Implement per-build randomization to defeat pattern matching
- Add telemetry and abuse detection server-side