1. Overview
The AntiRansomEngine is a user-space ransomware scanning engine that combines YARA-based signature detection with a minimal behavioral heuristic (extension-based indicators). It is implemented in modern C++ and designed to run continuously in a background worker thread, emitting events to the UI layer through sigc++ signals.
At runtime, the engine:
- Initializes the YARA runtime (
yr_initialize()) - Loads and compiles YARA rules from application resources
- Recursively scans files under
/homeusing YARA - Performs a heuristic pass to detect suspicious extensions (e.g.,
.locked,.crypted) - Reports detections and lifecycle events via
sig_event_
2. Dependencies and Runtime Integration
This component depends on:
- YARA (
<yara.h>) – rule compilation and file scanning - std::filesystem – directory traversal and file existence checks
- glib/gi18n – localized log messages via
_() - sigc++ – event propagation to the GUI layer
- Resource.hpp – portable lookup of installed data files
The engine operates in user space and does not require privileged operations. However, scanning scope and performance characteristics depend on filesystem permissions and dataset size.
3. Initialization and Shutdown
3.1 Construction
On instantiation, the engine initializes YARA and immediately attempts to load rules:
yr_initialize()is called; failure is logged tostderrload_yara_rules()compiles the ruleset and stores it inyara_rules_
If YARA initialization or rule compilation fails, the engine can still start, but scanning will be effectively disabled (because yara_rules_ remains nullptr).
3.2 Destruction
The destructor enforces a clean shutdown sequence:
- Stops the background worker thread via
stop() - Destroys compiled rules via
yr_rules_destroy()(if present) - Finalizes YARA runtime via
yr_finalize()
This prevents leaks and avoids YARA finalization while scanning is still in flight.
4. YARA Rules Loading and Compilation
4.1 Rule Source
Rules are loaded from an application resource rather than a fixed system path:
rules/ransomware.yar
The effective file path is resolved via:
std::string rule_path = resource("rules/ransomware.yar");
This design supports both development runs and installed deployments without hardcoding distribution-specific paths.
4.2 Compiler Lifecycle and Error Handling
Rule compilation uses the YARA compiler API:
yr_compiler_create()creates a compiler instanceyr_compiler_set_callback()registers an error callback that:- Sets a shared
has_errorsflag - Logs file/line diagnostics to
stderr
- Sets a shared
yr_compiler_add_file()adds the rule file to the compilation unityr_compiler_get_rules()emits a compiledYR_RULES*intoyara_rules_
If the rule file is missing or unreadable, the engine logs a warning and continues without rules. If compilation reports errors, rules are not installed into the engine.
5. File Scanning Pipeline
5.1 Single-file Scan
The engine scans an individual file through:
void scan_file(const std::string& path)
Preconditions:
yara_rules_must be non-null (compiled rules loaded)- The target file must exist and be accessible
The scan operation is performed using:
yr_rules_scan_file(yara_rules_, path.c_str(), 0, yara_callback, &sig_event_, 0)
On success, the engine produces no direct log output; detections are reported exclusively via the callback. On error, the engine logs the return code to stderr for diagnosis.
5.2 YARA Match Callback and Event Emission
Detection reporting is centralized in yara_callback. When a rule match occurs:
- The callback receives
CALLBACK_MSG_RULE_MATCHING - The matched rule identifier (
rule->identifier) is appended to a localized message - The message is emitted via
sig_event_
User data passed into YARA is a pointer to sig_event_, allowing the callback to propagate UI-ready messages without coupling to the UI layer.
6. Background Worker Loop
6.1 Main Loop Behavior
The main execution loop is implemented in run() and is controlled by the running_ flag. Lifecycle messages are emitted when the engine starts and stops.
Each scan cycle consists of two passes over /home:
- Signature pass (YARA): recursively iterates all regular files under
/homeand invokesscan_file(). - Heuristic pass: recursively iterates
/homeagain and emits a warning if a file extension indicates suspicious encryption output (currently.lockedor.crypted).
The loop is protected by a try/catch block; exceptions during traversal or scanning are surfaced through sig_event_.
6.2 Cooperative Stop and Sleep Strategy
To support responsive stop behavior, the engine:
- Checks
running_during directory traversal to break early - Uses a 30-second sleep implemented as a 1-second loop:
- Allows faster termination (worst-case ~1 second latency)
- Avoids long blocking sleeps that delay shutdown
7. Start/Stop API
Thread control is exposed via:
start()– setsrunning_, spawns the worker thread, and logs tostdoutstop()– clearsrunning_, joins the worker thread, and logs tostdout
Repeated calls are idempotent:
start()returns immediately if already runningstop()returns immediately if not running
8. Event Signaling and UI Integration
The engine exposes:
sigc::signal<void(const std::string&)>& signal_event()
This signal provides a unified channel for:
- Engine lifecycle events (start/stop)
- Rule match detections (YARA identifiers)
- Heuristic detections (suspicious extension indicators)
- Runtime errors raised during scanning
All messages are localized via glib/gi18n, enabling consistent i18n across GTK-based UI surfaces.
9. Security, Performance, and Operational Considerations
- Scanning scope: the current implementation scans recursively under
/home, which may be expensive on large filesystems. - Double traversal: each cycle traverses
/hometwice (YARA + heuristic). This improves separation of concerns but increases I/O pressure. - Heuristic simplicity: extension-based detection is intentionally minimal and should be treated as an indicator, not proof of ransomware.
- Permissions: inaccessible files are skipped indirectly via filesystem iteration failures and
exists()checks; exceptions are caught and reported. - Rule integrity: compilation errors prevent rules from loading, reducing false assurance. Diagnostics are emitted via the compiler callback.
- Threading model: event emission occurs from the worker thread. UI consumers should ensure thread-safe delivery (e.g., marshal to GTK main loop if required by the UI layer).
Overall, AntiRansomEngine provides a pragmatic first layer of ransomware detection with a clear path for future enhancements (incremental scanning, file change monitoring, configurable scan roots, and stronger heuristics).