A single msfconsole-style terminal for static reverse-engineering and malware triage — sandboxed by default, with a one-command report at the end.
A single, msfconsole-style terminal for static reverse-engineering /
malware-triage work, so you're not juggling strings, pefile
scripts, yara, objdump, and a hash calculator across five
terminal tabs.
mal> load /path/to/sample.exe
✓ loaded /path/to/sample.exe
╭─────────────────────────── ACTIVE SAMPLE ────────────────────────────╮
│ file /path/to/sample.exe type PE (Windows executable) │
│ size 142,312 bytes entropy 6.94 │
│ md5 3d483dcf565eca2fc27... sha1 e6da1ac2ebc3946c8d... │
│ sha256 53a9c0557a948069d5... loaded 2026-08-05 07:03:39 UTC │
╰──────────────────────────────────────────────────────────────────────╯
mal> use static/pe_info
✓ using static/pe_info
mal(static/pe_info)> run
...
The sample card is reprinted right above the prompt after every command, so you can scroll back through pages of module output and still glance up to see exactly what you're working on — no full-screen TUI, no lost scrollback.
Recommended: run it sandboxed (Docker). This is the path to use whenever you're pointing malconsole at an actual untrusted sample — see Sandboxing below for exactly what isolation this gives you and why it matters.
./scripts/run-sandboxed.sh # builds the image on first run, drops you into mal>
./scripts/run-sandboxed.sh /path/to/sample.exe # same, with the sample bind-mounted read-onlyLocal install, for module development or trusted samples only:
pip install -r requirements.txt
# or, editable install with a `malconsole` command on your PATH:
pip install -e .[full]
python -m malconsole.main
# or, if installed: malconsoleEvery analysis module degrades gracefully: if pefile, pyelftools,
capstone, yara-python, or fpdf2 isn't installed, that module (or
the PDF half of report save) simply won't be available (or will
tell you what to pip install if you try to use it). The core
console only needs rich and prompt_toolkit.
| command | what it does |
|---|---|
load <path> |
load a sample into the active session (hashes it, sniffs filetype, computes entropy) |
use <module/path> |
select a module — tab-complete works |
show modules |
list every available module |
show options / options |
show the current module's options |
show info / info |
details about the current module |
set <OPT> <value> |
set an option on the current module |
unset <OPT> |
clear an option |
run (alias exploit, if you're feeling nostalgic) |
execute the current module |
back |
leave the current module |
search <term> |
search modules by name/description |
sandbox |
check whether this session looks isolated (VM/container) |
report status |
show what's been collected for the report so far |
report save <path> |
write the report — .md or .pdf, inferred from the extension |
card / status |
reprint the sample card on demand |
clear |
clear the scrollback |
exit / quit |
leave |
Tab completion covers commands, module paths (use ), option names
(set /unset ), and filesystem paths (load ).
static/pe_info— PE headers, sections (with per-section entropy, handy for spotting packed sections), imports, exports.static/elf_info— ELF headers, sections, program headers,DT_NEEDEDlibraries.hashing/hashes— md5/sha1/sha256/sha512, PE imphash, and ssdeep fuzzy hashing if installed.strings/extract— ASCII + UTF-16LE string extraction with an IOC pass (IPv4s, URLs, domains, emails, registry paths, Windows file paths).yara_scan/scan— compiles and runs YARA rules against the loaded sample. Ships with no bundled signatures — pointRULESat your own rule file/directory.disasm/capstone_view— read-only Capstone disassembly of a named PE/ELF section, or a manual offset/length/arch. Same category of tool asobjdump -d; it never executes the bytes it decodes.
malconsole itself never executes a loaded sample — every module only
reads it as bytes (hashing, header parsing, string extraction,
disassembly for display). That keeps the tool's own behavior
predictable, but the parsing libraries it calls (pefile,
pyelftools, capstone, yara-python) are still processing
attacker-controlled, potentially malformed files, and malformed-file
parser bugs are a real, recurring class of issue across the industry
(this tool and IDA/Ghidra/radare2 alike). So: isolate the environment,
not just the code.
1. Run the console itself inside the provided container.
./scripts/run-sandboxed.sh /path/to/sample.exeThis builds Dockerfile (a non-root user, minimal base) and runs it
with --network none --read-only --cap-drop ALL --security-opt no-new-privileges --pids-limit 256, your sample bind-mounted
read-only at /samples, and only ./reports on the host writable
(bind-mounted at /reports in the container). If you'd rather run
docker yourself, copy the flags out of
scripts/run-sandboxed.sh directly.
2. Or run it inside a dedicated analysis VM (REMnux, FLARE-VM, or your own snapshot-and-revert Linux/Windows VM) if you want to pair it with GUI RE tools — container isolation and VM isolation both work, containers are just faster to spin up.
3. Either way, check your isolation from inside the console:
mal> sandbox
✓ environment looks isolated
container: yes (/.dockerenv present)
virtual machine: unknown
running as root: no
platform: Linux-6.x-x86_64-with-glibc2.39
This runs automatically at startup too. It's a best-effort, read-only,
no-network check (container markers, VM/DMI signals, root/uid 0) — a
heads-up if something looks like bare metal, not a gate. It never
blocks load or run.
Every time you run a module, its structured findings (not just the
printed tables — the underlying data) are captured into the session.
When you're done poking around:
mal> report status # see what's been collected + running risk signal
mal> report save findings.md # Markdown - always works, zero extra deps
mal> report save findings.pdf # PDF - needs fpdf2 (pip install fpdf2)
Either format includes: sample metadata and hashes, a Key Evidence section (the concrete proof behind each finding — matched YARA rule names, watchlisted API imports, packed-section entropy values, IOC matches — the "PoC" a triage report needs), every module's full output table by table, a consolidated IOC list, an auto-generated risk signal + recommendations based on what was actually found, and an appendix with the full command log for reproducibility.
It's explicitly labeled as an automated static-analysis aid throughout — it flags signals and cites the evidence for each one, it doesn't hand you a verdict.
Drop a file under malconsole/modules/<category>/your_module.py:
from ...core.module_base import BaseModule
from ...core import ui
class MyModule(BaseModule):
name = "My Module"
description = "One line describing what it does."
category = "misc"
def __init__(self):
super().__init__()
self.register_option("FILE", required=True, description="...")
def run(self, session, out=ui):
out.info("hello from my module")
MODULE = MyModule # required - this is what the registry looks forIt'll show up automatically under show modules as
misc/your_module next time you start the console — no registration
step needed. If a module's real dependency is missing, it's simply
skipped at discovery time rather than crashing the console.
A few things worth knowing before you point this at live samples:
- No exploit/malware-generation code anywhere in this project.
Every module only reads a sample as bytes (hashing, header
parsing, string extraction, disassembly for display) — nothing
here shells out,
evals, unpickles, or executes sample content. I grepped the whole tree foreval/exec/os.system/subprocess/shell=True/picklebefore calling this done — none are present. - The real residual risk is upstream, not in this tool's own code.
pefile,pyelftools, andcapstoneall parse attacker-controlled, potentially malformed files — that class of parser has historically been where crashes and memory-safety bugs show up industry-wide. See Sandboxing above for how to isolate the environment this runs in, and keep dependencies updated. Never double-click or otherwise execute a loaded sample outside the console. - YARA rules are treated as trusted input. Only point
RULESat rule sources you trust, the same way you'd trust any code you compile and run locally. - Large files are hashed in 1 MiB chunks (bounded memory) and string
output is capped and paginated by default, to avoid a huge sample
turning
runinto an unresponsive wall of text. - No sample is ever uploaded anywhere — there's no network activity in this tool at all. If you later want a VirusTotal-lookup module, that's an easy add, but it should be opt-in given samples are often confidential.
MIT — do whatever you want with it, no warranty. If you use this in production triage, run the sandboxing steps above; if you extend it with dynamic/execution capability, isolate that at least as strictly as the static side is here.