Base framework for building malware detectors
Reason this release was yanked:
Replaced by maldet 1.x — see https://github.com/bolin8017/maldet
Project description
islab-malware-detector
A base framework for building malware detectors with modern Python.
- Source code: https://github.com/bolin8017/islab-malware-detector.git
- Wiki: https://github.com/bolin8017/islab-malware-detector/wiki
- PyPI: https://pypi.org/project/islab-malware-detector/
Features
- Pydantic v2 Configuration - Type-safe config with env vars and file support
- Typer CLI - Extensible command-line interface via factory function
- Structured Logging - Console and JSON output formats with structlog
- Abstract Base Class - Define train, evaluate, and predict methods
- Type Hints - Full typing support throughout the codebase
Requirements
| Tool | Version |
|---|---|
| Python | >= 3.12 |
Installation
pip install islab-malware-detector
Or with uv:
uv add islab-malware-detector
Quick Start
Basic Usage
from pathlib import Path
from typing import Any
from maldet import BaseDetector, BaseDetectorConfig
class MyDetector(BaseDetector):
"""My custom malware detector."""
def train(self) -> Path:
"""Train the malware detection model."""
self.logger.info("training_started", dataset=str(self.config.data.train))
# Ensure output directory exists
self.ensure_directory_exists(self.config.output.model)
# Your training logic here
# - Load training data from self.config.data.train
# - Extract features and train model
# - Save model to self.config.output.model
self.logger.info("training_completed", model=str(self.config.output.model))
return self.config.output.model
def evaluate(self) -> dict[str, Any]:
"""Evaluate the trained model."""
self.logger.info("evaluation_started", dataset=str(self.config.data.test))
# Your evaluation logic here
# - Load test data from self.config.data.test
# - Load model from self.config.output.model
# - Calculate metrics
metrics = {
"accuracy": 0.95,
"precision": 0.93,
"recall": 0.97,
"f1_score": 0.95,
}
self.logger.info("evaluation_completed", **metrics)
return metrics
def predict(self) -> Path:
"""Run predictions on new data."""
self.logger.info("prediction_started", input=str(self.config.data.predict))
# Ensure output directory exists
self.ensure_directory_exists(self.config.output.prediction)
# Your prediction logic here
# - Load input data from self.config.data.predict
# - Load model from self.config.output.model
# - Generate predictions
# - Save results to self.config.output.prediction
self.logger.info("prediction_completed", output=str(self.config.output.prediction))
return self.config.output.prediction
# Create and use the detector
if __name__ == "__main__":
detector = MyDetector()
# Train the model
model_path = detector.train()
print(f"Model saved to: {model_path}")
# Evaluate the model
metrics = detector.evaluate()
print(f"Evaluation metrics: {metrics}")
# Run predictions
predictions_path = detector.predict()
print(f"Predictions saved to: {predictions_path}")
Configuration
Custom Configuration
You can extend the base configuration with your own fields:
from pydantic import Field
from pydantic_settings import SettingsConfigDict
from maldet import BaseDetectorConfig
class MyDetectorConfig(BaseDetectorConfig):
"""Custom configuration with additional fields."""
model_config = SettingsConfigDict(
env_prefix="MY_DETECTOR_",
env_nested_delimiter="__",
)
# Custom fields for your detector
batch_size: int = Field(default=32, description="Training batch size")
model_name: str = Field(default="random_forest", description="Model type to use")
use_gpu: bool = Field(default=False, description="Whether to use GPU acceleration")
n_estimators: int = Field(default=100, description="Number of trees for random forest")
class MyDetector(BaseDetector):
config_class = MyDetectorConfig
def train(self) -> Path:
self.logger.info(
"training_config",
batch_size=self.config.batch_size,
model_name=self.config.model_name,
use_gpu=self.config.use_gpu,
)
# Use self.config.batch_size, self.config.model_name, etc.
...
Environment Variables
Configure your detector using environment variables:
# Data paths
export MALWARE_DETECTOR_DATA__TRAIN="./data/train"
export MALWARE_DETECTOR_DATA__TEST="./data/test"
export MALWARE_DETECTOR_DATA__PREDICT="./data/predict"
# Output paths
export MALWARE_DETECTOR_OUTPUT__MODEL="./output/model.pkl"
export MALWARE_DETECTOR_OUTPUT__PREDICTION="./output/predictions.json"
# Logging
export MALWARE_DETECTOR_LOG__LEVEL="INFO"
export MALWARE_DETECTOR_LOG__FORMAT="console"
# Custom fields (for MyDetectorConfig)
export MY_DETECTOR_BATCH_SIZE=64
export MY_DETECTOR_MODEL_NAME="xgboost"
export MY_DETECTOR_USE_GPU=true
Configuration File
Save configuration as TOML file:
# config.toml
version = "0.3.0"
[data]
train = "./data/train"
test = "./data/test"
predict = "./data/predict"
[output]
model = "./output/model.pkl"
feature = "./output/features.pkl"
prediction = "./output/predictions.json"
log = "./logs/detector.log"
[log]
level = "INFO"
format = "console"
# Custom fields (for MyDetectorConfig)
batch_size = 64
model_name = "xgboost"
use_gpu = true
n_estimators = 200
Load configuration from file:
config = MyDetectorConfig.from_toml("config.toml")
detector = MyDetector(config=config)
CLI Integration
Create CLI for Your Detector
The framework provides automatic CLI generation:
# my_detector_cli.py
from maldet import BaseDetector, BaseDetectorConfig
class MyDetector(BaseDetector):
# ... implementation ...
pass
# Create CLI app
app = MyDetector.create_cli()
# Add custom commands
@app.command()
def info():
"""Display detector information."""
print("My Malware Detector v1.0")
print("Custom implementation using islab-malware-detector framework")
if __name__ == "__main__":
app()
CLI Usage
# Display help
python my_detector_cli.py --help
# Train the model
python my_detector_cli.py train --config config.toml
# Evaluate the model
python my_detector_cli.py evaluate --config config.toml
# Run predictions
python my_detector_cli.py predict --config config.toml
# Generate default config file
python my_detector_cli.py init --output config.toml
# Custom logging
python my_detector_cli.py train --log-format json --log-level DEBUG
MLflow Tracking
Detectors auto-log to MLflow when MLFLOW_TRACKING_URI is set in the environment.
When unset, behavior is unchanged — no MLflow dependency is required for normal use.
Install with the optional mlflow extra:
pip install "islab-malware-detector[mlflow]"
Environment variables:
| Variable | Effect |
|---|---|
MLFLOW_TRACKING_URI |
When set, enables MLflow tracking |
MLFLOW_RUN_ID |
Reuse an existing run (platform creates it) |
Logged artifacts per action:
train: flattened config params,config.json, model directory undermodel/evaluate: numeric metrics,metrics.json(always written tooutput.logdir)predict: prediction file underprediction/
Example:
export MLFLOW_TRACKING_URI="http://mlflow.example.com"
export MLFLOW_RUN_ID="<run-id-created-by-platform>"
python my_detector_cli.py train --config config.json
Logging
The framework uses structlog for structured logging:
from maldet import configure_logging, get_logger
# Configure logging at application startup
configure_logging(level="INFO", format="console")
# Get a logger in your code
logger = get_logger(__name__)
# Log structured events
logger.info("model_training_started", dataset="train.csv", samples=1000)
logger.debug("feature_extracted", feature_count=128, elapsed_ms=45.2)
logger.warning("missing_data", file="sample.exe", reason="corrupted_header")
logger.error("training_failed", error_type="ValueError", message="Invalid input shape")
Output Formats
Console format (development):
2024-01-20T10:30:00 [info ] model_training_started dataset=train.csv samples=1000
2024-01-20T10:30:45 [debug ] feature_extracted feature_count=128 elapsed_ms=45.2
JSON format (production):
{"event": "model_training_started", "dataset": "train.csv", "samples": 1000, "timestamp": "2024-01-20T10:30:00", "level": "info"}
{"event": "feature_extracted", "feature_count": 128, "elapsed_ms": 45.2, "timestamp": "2024-01-20T10:30:45", "level": "debug"}
Architecture
Core Components
- BaseDetector: Abstract base class defining the interface (train, evaluate, predict)
- BaseDetectorConfig: Pydantic configuration with data paths, output paths, and logging
- CLI Factory: Automatic CLI generation with train/evaluate/predict commands
- Logging: Structured logging with console and JSON formats
Directory Structure
your-detector/
├── config.toml # Configuration file
├── my_detector.py # Your detector implementation
├── my_detector_cli.py # CLI wrapper (optional)
├── data/
│ ├── train/ # Training data
│ ├── test/ # Test data
│ └── predict/ # Prediction input
├── output/
│ ├── model.pkl # Trained model
│ ├── features.pkl # Extracted features (optional)
│ └── predictions.json # Prediction results
└── logs/
└── detector.log # Application logs
Migration from v0.2.x
Version 0.3.0 introduced breaking changes with a cleaner ABC-based design:
| v0.2.x | v0.3.x |
|---|---|
def stage_extract(self) |
Removed - implement in train() |
def stage_vectorize(self) |
Removed - implement in train() |
def stage_train(self) |
def train(self) -> Path |
def stage_predict(self) |
def predict(self) -> Path |
detector.run() |
Call methods directly: train(), evaluate(), predict() |
detector.run(stages=["extract"]) |
Not supported - call methods directly |
default_stages class attribute |
Not used - implement your own workflow |
Migration example:
# v0.2.x (old)
class OldDetector(BaseDetector):
def stage_extract(self):
# Extract features
return self.config.folder.feature
def stage_train(self):
# Train model
return self.config.folder.model
def stage_predict(self):
# Predict
return self.config.path.output
detector = OldDetector()
detector.run(stages=["extract", "train"])
# v0.3.x (new)
class NewDetector(BaseDetector):
def train(self) -> Path:
# Extract features + train model
features = self._extract_features()
model = self._train_model(features)
return self.config.output.model
def evaluate(self) -> dict[str, Any]:
# Evaluate model
return {"accuracy": 0.95}
def predict(self) -> Path:
# Predict
predictions = self._run_inference()
return self.config.output.prediction
detector = NewDetector()
detector.train()
detector.evaluate()
detector.predict()
Examples
See the examples directory for complete working examples:
- Basic Detector: Simple random forest classifier
- Deep Learning Detector: CNN-based detector with GPU support
- Ensemble Detector: Multiple models with voting
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE.txt for details.
Citation
If you use this framework in your research, please cite:
@software{islab_malware_detector,
title = {islab-malware-detector: A Framework for Building Malware Detectors},
author = {PO-LIN LAI},
year = {2024},
url = {https://github.com/bolin8017/islab-malware-detector}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file islab_malware_detector-0.5.0.tar.gz.
File metadata
- Download URL: islab_malware_detector-0.5.0.tar.gz
- Upload date:
- Size: 72.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97aa80069032a3532f15e26b2de78696f2c23568d2f9f5a170b8b7b801ce86a8
|
|
| MD5 |
ce50058d5fc858d8e5971693351465ce
|
|
| BLAKE2b-256 |
335896f58e4402b388d7541c38828eab665a9425df44ce4938120761e24ad0a6
|
File details
Details for the file islab_malware_detector-0.5.0-py3-none-any.whl.
File metadata
- Download URL: islab_malware_detector-0.5.0-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94e52df62f3d2c1519e0089deb6ff0665fa0554495664909856dd52dc29c32a8
|
|
| MD5 |
0a1097dd7f8e58e89bab389132354695
|
|
| BLAKE2b-256 |
0bd9e26ae53211b2591392616295914e5173340fef3a4e1d2fea4289362905fb
|