# How to Create and Integrate Custom Auxiliary Modules in CAPEv2: A Complete Guide

> Learn to create and integrate custom auxiliary modules in CAPEv2. Follow our complete guide to subclass the Auxiliary class, implement methods, and configure your new modules.

- Repository: [Kevin O'Reilly/capev2](https://github.com/kevoreilly/capev2)
- Tags: how-to-guide
- Published: 2026-03-05

---

**To create a custom auxiliary module in CAPEv2, subclass the `Auxiliary` abstract base class from `lib.cuckoo.common.abstracts`, implement the `start()` and `stop()` methods, place your Python file in `modules/auxiliary/`, and add a configuration section to [`conf/auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/conf/auxiliary.conf) with `enabled = yes`.**

CAPEv2 extends malware analysis capabilities through a flexible auxiliary module system that runs parallel to the core sandbox execution. These modules—ranging from network sniffers to screenshot capture utilities—inherit from a common abstract base and integrate automatically via the framework's plugin discovery mechanism. Understanding how to create and integrate custom auxiliary modules within the CAPEv2 framework enables you to add specialized monitoring, data collection, or environment manipulation capabilities without modifying core engine code.

## Understanding the CAPEv2 Auxiliary Plugin Architecture

The auxiliary subsystem follows a standardized plugin pattern defined in [`lib/cuckoo/common/abstracts.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/common/abstracts.py). When an analysis begins, [`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py) handles the lifecycle through the following sequence:

1. **Discovery** – The `load_plugins()` function (lines 106-119) scans every package under `modules/auxiliary` (and OS-specific analyzer paths) for Python files containing classes that inherit from `Auxiliary`.
2. **Registration** – Valid classes are automatically registered via `register_plugin("auxiliary", cls)` without requiring manual intervention.
3. **Configuration** – The framework reads module-specific options from [`conf/auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/conf/auxiliary.conf) using `Config("auxiliary")`.
4. **Execution** – The `RunAuxiliary` class instantiates enabled modules, injects the current task and machine objects via `set_task()` and `set_machine()`, passes parsed options through `set_options()`, and invokes `start()`.
5. **Lifecycle Management** – Upon analysis completion, the framework calls `stop()` to ensure clean shutdown and resource release.

## Step-by-Step Implementation Guide

Follow these concrete steps to implement a production-ready auxiliary module.

### 1. Create the Module File

Place your Python file in `modules/auxiliary/` for cross-platform modules, or in `analyzer/windows/modules/auxiliary/` (or `linux/`) for OS-specific implementations. The filename should reflect the module purpose, such as [`process_monitor.py`](https://github.com/kevoreilly/capev2/blob/main/process_monitor.py).

### 2. Subclass the Auxiliary Base

Import the abstract base class and define your implementation:

```python
from lib.cuckoo.common.abstracts import Auxiliary
import logging

log = logging.getLogger(__name__)

class ProcessMonitor(Auxiliary):
    """Monitor specific process behaviors during analysis."""
    
    def start(self):
        """Called when analysis begins."""
        pass
    
    def stop(self):
        """Called when analysis ends."""
        pass

```

The `Auxiliary` base class (lines 84-102 in [`lib/cuckoo/common/abstracts.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/common/abstracts.py)) provides the interface contract including `set_task()`, `set_machine()`, and `set_options()` methods that the framework uses for dependency injection.

### 3. Implement Lifecycle Methods

At minimum, implement `start(self)` and `stop(self)`. Access configuration through the `self.options` attribute populated by `RunAuxiliary.start()` in [`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py) (lines 73-89):

```python
def start(self):
    """Initialize monitoring based on configuration."""
    self.interval = getattr(self.options, "interval", 5)
    self.target_process = getattr(self.options, "process_name", "malware.exe")
    log.info("Starting ProcessMonitor for %s (interval: %ds)", 
             self.target_process, self.interval)
    # Implementation logic here

def stop(self):
    """Cleanup and finalize data collection."""
    log.info("Stopping ProcessMonitor")
    # Cleanup logic here

```

### 4. Configure the Module

Add a dedicated section to [`conf/auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/conf/auxiliary.conf) (or `conf/auxiliary.conf.default`):

```ini
[ProcessMonitor]
enabled = yes
interval = 10
process_name = target.exe

```

The `enabled` flag controls whether `RunAuxiliary` instantiates your class during analysis startup.

### 5. Handle Optional Callbacks

For modules needing to react to analysis events (process creation, file drops), implement the `callback(self, name, *args, **kwargs)` method. The framework invokes this via `RunAuxiliary.callback()` for events such as `on_process` or `on_file`.

## Complete Working Example

Here is a functional auxiliary module that logs periodic status messages:

```python
from lib.cuckoo.common.abstracts import Auxiliary
import threading
import time
import logging

log = logging.getLogger(__name__)

class StatusLogger(Auxiliary):
    """
    Logs periodic status messages during analysis.
    Demonstrates threading safety and configuration handling.
    """
    
    def __init__(self):
        self._running = False
        self._thread = None
        self.interval = 5
    
    def start(self):
        """Begin logging in a background thread."""
        # self.options injected by RunAuxiliary.set_options()

        self.interval = int(getattr(self.options, "interval", 5))
        self._running = True
        
        self._thread = threading.Thread(target=self._log_loop)
        self._thread.daemon = True
        self._thread.start()
        
        log.info("StatusLogger started with %ds interval", self.interval)
    
    def _log_loop(self):
        """Internal logging loop."""
        while self._running:
            log.debug("Analysis status: active")
            time.sleep(self.interval)
    
    def stop(self):
        """Signal the thread to stop and wait for completion."""
        self._running = False
        if self._thread:
            self._thread.join(timeout=5)
        log.info("StatusLogger stopped")

```

Configuration entry:

```ini
[StatusLogger]
enabled = yes
interval = 30

```

## Key Source Files and Architecture References

Understanding these core files ensures proper integration:

- **[`lib/cuckoo/common/abstracts.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/common/abstracts.py)** (lines 84-102): Defines the `Auxiliary` abstract base class with `set_task()`, `set_machine()`, `set_options()`, `start()`, and `stop()` methods.
- **[`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py)** (lines 106-119): Contains `load_plugins()` which scans `modules/auxiliary/` and registers subclasses automatically.
- **[`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py)** (lines 63-99): Implements `RunAuxiliary.start()` which instantiates modules, injects dependencies, and manages the execution lifecycle.
- **[`conf/auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/conf/auxiliary.conf)**: Runtime configuration file where each module declares its `enabled` status and custom parameters.
- **[`modules/auxiliary/sniffer.py`](https://github.com/kevoreilly/capev2/blob/main/modules/auxiliary/sniffer.py)**: Reference implementation showing network capture integration.

## Best Practices for Production Modules

Consider these implementation details when deploying custom auxiliary modules:

- **Thread Safety**: Run blocking operations in separate threads to avoid stalling the analysis manager, using proper synchronization primitives for shared data access.
- **Error Isolation**: Exceptions raised in `start()` are caught and logged in `RunAuxiliary`, allowing analysis to continue without your module. Design defensively to ensure failures don't cascade.
- **Configuration Validation**: Use `getattr(self.options, "param", default)` with sensible defaults to prevent `AttributeError` when configuration keys are missing.
- **Resource Cleanup**: Always implement `stop()` to release file handles, network sockets, or threads, preventing resource leaks during long-running analysis operations.
- **Performance Impact**: Disabled modules are skipped early in the loading process via the `config_mapper` logic, so ensure the `enabled` flag is set to `no` for development modules not in use.

## Summary

- **Inherit from `Auxiliary`**: Subclass the base class defined in [`lib/cuckoo/common/abstracts.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/common/abstracts.py) to ensure API compatibility.
- **Implement `start()` and `stop()`**: These required methods define your module's operational lifecycle and cleanup procedures.
- **Place in `modules/auxiliary/`**: The plugin loader automatically discovers Python files in this directory (or OS-specific analyzer paths).
- **Configure via [`auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/auxiliary.conf)**: Add an `[YourModule]` section with `enabled = yes` and custom parameters; the framework injects these via `self.options`.
- **Leverage automatic registration**: No manual registration code is required—the `load_plugins()` function in [`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py) handles discovery via class inspection.

## Frequently Asked Questions

### What is the difference between auxiliary modules and processing modules in CAPEv2?

Auxiliary modules run during the live analysis phase alongside the malware execution, enabling real-time monitoring and environment interaction. Processing modules operate after analysis completion in [`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py) under the processing category, handling static analysis of collected data. Auxiliary modules inherit from `Auxiliary` and implement `start()`/`stop()`, while processing modules typically inherit from `Processing` and implement `run()`.

### Can auxiliary modules access the analysis task and machine objects?

Yes. The `RunAuxiliary` class automatically injects these dependencies before calling `start()`. The framework invokes `set_task(task)` and `set_machine(machine)` on your instance, allowing access to task configuration, target file paths, and machine-specific settings such as IP addresses or platform details.

### How do I debug a custom auxiliary module that isn't loading?

First verify the file is in `modules/auxiliary/` (or the correct OS-specific analyzer path) and contains a class inheriting from `Auxiliary`. Check [`conf/auxiliary.conf`](https://github.com/kevoreilly/capev2/blob/main/conf/auxiliary.conf) to ensure your module section includes `enabled = yes`. Review the CAPEv2 logs for import errors during the `load_plugins()` scan in [`lib/cuckoo/core/plugins.py`](https://github.com/kevoreilly/capev2/blob/main/lib/cuckoo/core/plugins.py). The framework logs registration failures but continues loading other modules.

### Are auxiliary modules executed in separate processes or threads?

Auxiliary modules run within the main CAPEv2 analysis process but should spawn their own threads for blocking operations. The `RunAuxiliary.start()` method instantiates modules sequentially in the main thread, so heavy initialization or blocking I/O should be offloaded to background threads to prevent delaying the analysis start time.