A web-based scanner that checks if a downloaded file (.exe, .dll, .msi, .bin, .elf) is safe to run before you run it. The backend analyses uploads through multiple stages (PE structure, entropy, strings, YARA, VirusTotal) and combines the signals into a single CLEAN / SUSPICIOUS / MALICIOUS verdict with human-readable reasons.
⚠️ For educational and authorised security testing use only. See Disclaimer.
- Multi-stage static analysis — PE structure, suspicious imports, section entropy, string extraction, YARA rules
- VirusTotal lookup — cross-checks the file's SHA256 against 70+ AV engines (free-tier API key)
- Weighted verdict engine — combines signals into a single score, explains every contributing reason
- Local SQLite cache — same file, scanned twice, returns instantly
- Drag-and-drop React UI — verdict badge, expandable analysis panels
- Graceful fallbacks — missing API key, network errors, and malformed files never crash the pipeline
- Rotating file logs — every scan, error, and VT lookup is recorded in
logs/scanner.log
┌─────────────────┐ multipart/form-data ┌─────────────────────┐
│ React (Vite) │ ───────────────────────────▶ │ FastAPI backend │
│ localhost:5173 │ │ 127.0.0.1:8000 │
└─────────────────┘ ◀────── JSON verdict ───── └──────────┬──────────┘
│
┌───────────┬─────────────────┼──────────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐
│ pefile + │ │ YARA │ │ SQLite │ │ VirusTotal │
│ entropy │ │ rules │ │ cache │ │ API v3 │
│ + strings│ │ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘ └────────────┘
- Python 3.12+ (3.14 tested)
- Node.js 20+
- Windows, macOS, or Linux (PE analysis works on any host; some test paths assume Windows)
- A free VirusTotal API key — optional, the scanner runs without it but the verdict will lack the strongest signal
git clone https://github.com/POSTTTT/malware-scanner.git
cd malware-scanner
python -m venv venv
# Windows PowerShell:
.\venv\Scripts\Activate.ps1
# macOS/Linux:
source venv/bin/activate
pip install -r requirements.txtcp .env.example .env
# then open .env and paste your key after VIRUSTOTAL_API_KEY=The scanner also runs without a key — VT lookups will be skipped with a clear reason.
cd frontend
npm install
cd ..You need two terminals open simultaneously.
Terminal 1 — backend:
cd backend
..\venv\Scripts\python.exe -m uvicorn main:app --reloadTerminal 2 — frontend:
cd frontend
npm run devOpen http://localhost:5173 in your browser.
Drag a file onto the drop zone (or click to browse). The UI streams it to the backend, which:
- Validates the file (extension, size limit 50 MB)
- Computes SHA256 and checks the local cache
- If new: runs PE analysis, entropy, strings, YARA, then queries VirusTotal
- Combines all signals into a verdict with a 0–100 score
- Returns the result; the UI renders verdict + reasons + expandable details
You can also call the API directly:
curl -X POST http://127.0.0.1:8000/scan -F "file=@C:\Windows\System32\notepad.exe"Interactive API docs are at http://127.0.0.1:8000/docs.
The verdict engine combines weighted signals from each scanner. Score thresholds:
| Score | Verdict |
|---|---|
< 20 |
CLEAN |
20–49 |
SUSPICIOUS |
≥ 50 |
MALICIOUS |
Selected signals (full list in backend/scanners/verdict.py):
| Signal | Points |
|---|---|
| VT: ≥ 10 engines flag the file | +60 |
| VT: ≥ 5 engines flag | +40 |
| VT: ≥ 1 engine flags | +20 |
| VT: 0 / many engines clean (well-known) | −20 |
| PE has Authenticode signature | −20 |
| PE imports the process-injection trio | +25 |
| Other suspicious imports | +3 each, max +15 |
| Section entropy ≥ 7.5 (likely packed/encrypted) | +25 |
| Section entropy ≥ 7.0 (possibly packed) | +15 |
| Suspicious keywords (bitcoin, decrypt, vssadmin, etc.) | +5 each, max +15 |
| YARA: high-severity match | +40 |
| YARA: medium-severity match | +20 |
| YARA: low-severity match | +10 |
The response always includes a reasons[] array showing which signals contributed and their scores.
malware-scanner/
├── backend/
│ ├── main.py # FastAPI app entry
│ ├── config.py # config.yaml loader
│ ├── database.py # SQLite cache
│ ├── logger.py # rotating file logger
│ ├── api/
│ │ ├── health.py # GET /health
│ │ └── scan.py # POST /scan
│ ├── scanners/
│ │ ├── hasher.py # SHA256
│ │ ├── pe_analyzer.py # pefile-based PE parsing
│ │ ├── entropy.py # Shannon entropy per section
│ │ ├── strings.py # ASCII / UTF-16 string extraction
│ │ ├── yara_scan.py # YARA rule matcher
│ │ ├── virustotal.py # VT API v3 client
│ │ ├── static.py # orchestrates all static stages
│ │ └── verdict.py # weighted scoring engine
│ └── schemas/scan.py # Pydantic response models
├── frontend/ # Vite + React UI
├── rules/starter.yar # bundled YARA rules
├── tests/test_pipeline.py # end-to-end smoke test
├── config.yaml # central config (size limits, extensions, VT)
├── requirements.txt
├── PLAN.md # implementation plan + future work
└── IDEA.md # original concept
With the backend running:
python tests/test_pipeline.pyThis uploads a clean Windows binary (notepad.exe) and a hand-crafted "fake ransomware" pattern, then asserts the verdicts are CLEAN and MALICIOUS respectively. Set SCANNER_URL to point at a different host/port if needed.
Most knobs live in config.yaml:
uploads:
max_size_mb: 50
allowed_extensions: [.exe, .dll, .msi, .bin, .elf]
virustotal:
rate_limit_per_minute: 4 # matches free-tier quotaSecrets (VIRUSTOTAL_API_KEY) live in .env, which is gitignored.
Tracked in PLAN.md:
capaintegration — map binary behaviour to MITRE ATT&CK techniques- MalwareBazaar — second threat-intel source
- Authenticode publisher trust list — auto-CLEAN files signed by known vendors
- Async pipeline — only needed when adding slow analyzers (capa, sandbox)
- Sandbox (Phase 10) — run in a Docker container, observe behaviour
This tool is for educational and authorised security testing purposes only. Do not use it on files you don't have permission to analyse. The authors are not responsible for misuse.