A comprehensive, explainability-first malware detection framework trained on the EMBER 2018 benchmark dataset (799,876 labeled Windows PE file samples). This project systematically compares four model families and applies SHAP and LIME to produce actionable security explanations.
| Model | Accuracy | ROC-AUC | TPR@1%FPR |
|---|---|---|---|
| XGBoost | 97.21% | 0.9952 | 94.82% |
| LightGBM | 96.84% | 0.9948 | 94.20% |
| MLP | 96.06% | 0.9883 | 89.64% |
| RandomForest | 94.20% | 0.9870 | 81.80% |
Key XAI finding: Import table features account for ~38% of total SHAP importance, followed by byte histogram patterns (~21%).
malware-detection/
├── data/
│ ├── raw/ # EMBER .npy files
│ ├── processed/ # cleaned & processed
│ └── splits/ # train/val/test splits
├── notebooks/
│ ├── 01_EDA.ipynb # Exploratory Data Analysis
│ ├── 02_preprocessing.ipynb # Feature Engineering
│ ├── 03_baseline.ipynb # Baseline model results
│ ├── 04_deep_learning.ipynb # MLP analysis
│ ├── 05_explainability.ipynb # SHAP & LIME
│ └── 06_results.ipynb # Final results & paper figures
├── src/
│ ├── data_loader.py # Memory-safe EMBER data loading
│ ├── features.py # PE feature metadata (2381 dims)
│ ├── models/
│ │ ├── baseline.py # LightGBM, XGBoost, RandomForest
│ │ ├── mlp.py # Deep MLP (PyTorch)
│ │ └── cnn.py # 1D CNN (PyTorch)
│ ├── explainability/
│ │ ├── shap_analysis.py # SHAP TreeExplainer + group attribution
│ │ └── lime_analysis.py # LIME local explanations
│ ├── train.py # Full training pipeline
│ ├── evaluate.py # Unified evaluation metrics
│ └── visualize.py # Publication-ready figures
├── results/
│ ├── figures/ # All generated figures
│ ├── metrics/ # JSON results files
│ └── models/ # Saved model files (.pkl, .pt)
├── paper/
│ ├── draft.md # Research paper draft
│ └── figures/ # Paper-quality figures
├── config.yaml # All hyperparameters
├── run_explainability.py # XAI pipeline entry point
└── requirements.txt
pip install -r requirements.txtPlace EMBER 2018 .npy files in data/raw/:
data/raw/X_train_final.npy
data/raw/y_train_final.npy
data/raw/X_test_final.npy
data/raw/y_test_final.npy
# Train all baseline models (LightGBM, XGBoost, RandomForest)
py -m src.train --model baselines
# Train MLP
py -m src.train --model mlp
# Debug mode (fast, 50k samples)
py -m src.train --debug --model baselines# SHAP + LIME for all models
py run_explainability.py --model all
# Single model
py run_explainability.py --model lightgbmjupyter notebook notebooks/EMBER 2018 — Endgame Malware BEnchmark for Research
| Split | Benign | Malicious | Total |
|---|---|---|---|
| Train | 254,992 | 254,940 | 509,932 |
| Val | 44,999 | 44,989 | 89,988 |
| Test | 99,985 | 99,971 | 199,956 |
Feature space: 2,381 static PE features across 10 groups:
- ByteHistogram (256), ByteEntropy (256), StringFeatures (100)
- GeneralInfo (10), SectionInfo (92), ImportsInfo (384)
- ExportsInfo (128), DataDirectories (30), HeaderInfo (62), Extra (1063)
- Import table features dominate (~38% of SHAP importance) — consistent with malware using suspicious API calls
- Byte patterns contribute ~31% (histogram + entropy) — packing/obfuscation detection
- False positives are mainly legitimately packed software with high byte entropy
- False negatives typically use dynamic API loading to hide imports
If you use this code, please cite:
@article{mariam2025explainable,
title = {Explainable Static Malware Detection on Windows PE Files Using Ensemble Learning},
author = {Mariam Zakaria},
journal = {arXiv preprint},
year = {2025}
}MIT License — see LICENSE file.