| name | speakeasy |
| description | Cheatsheet for Mandiant Speakeasy, a Windows user-mode and kernel-mode binary emulation framework. Use it to emulate Windows PE executables, DLLs, drivers, or x86/x64 shellcode for reverse engineering, behavioral analysis, malware analysis, authorized penetration testing, product-security assessment, software testing, or research; produce and interpret JSON reports; collect dropped files, memory snapshots, coverage, and API/file/registry/network events; shape the emulated host through config or CLI overrides; mount host files; debug with GDB; or program against speakeasy.Speakeasy for API/code/memory hooks, manual export calls, memory/register access, and custom unpacking. Trigger on Speakeasy, Windows binary/driver/shellcode emulation, Speakeasy reports/configs, or Speakeasy Python API questions. Assumes the Speakeasy 2.x CLI is installed on PATH; create a separate uv-managed Python environment when imports are required. |
Speakeasy on Windows — Cheatsheet
Use this as a command and API reference, not a fixed workflow. Prefer the installed CLI for ordinary
whole-sample emulation; move to Python only when the task requires callbacks or direct emulator state.
Apply it to benign, proprietary, suspicious, or malicious Windows code according to the user's goal,
including reverse engineering, testing, pentesting, and product-security work.
Install the dependency
Install the pinned prerelease in an isolated uv tool environment, then verify it:
uv tool install --python 3.13 "speakeasy-emulator==2.0.0b3"
speakeasy -h
Prerequisite and runtime boundary
Assume an external installer has provisioned speakeasy with uv tool and placed it on PATH.
Do not install, upgrade, uninstall, or mutate that global tool environment from this skill.
Get-Command speakeasy
speakeasy -h
uv tool list | Select-String speakeasy
The uv tool environment makes the CLI available but does not make import speakeasy work in
the host or project Python. Never reach into uv tool dir to run or modify its private interpreter.
Create a separate environment as described below when Python is needed.
Commands here target speakeasy-emulator==2.0.0b3 on Python 3.13. If the installed help differs,
treat speakeasy -h as authoritative and check the provisioned version with uv tool list.
Choose CLI or Python
| Prefer the CLI | Use Python |
|---|
| Standard EXE/DLL/driver/shellcode runs | API, code, memory, interrupt, or instruction hooks |
| JSON report and dropped-file archive | Manual DLL export calls or custom entry sequencing |
| Config files and scalar environment overrides | Read/write emulated memory and registers |
| Independent samples and batch triage | Subclassing, unpacking, or in-process report handling |
| Bounded runs using worker-process timeout | Custom orchestration that the CLI cannot express |
CLI fast paths
# PE executable, DLL, or driver; the CLI selects user/kernel mode and runs all entry points
speakeasy -t .\sample.exe -o .\report.json
speakeasy -t .\sample.dll --timeout 30 -o .\report.json
speakeasy -t .\driver.sys --max-api-count 5000 -o .\report.json
# Raw shellcode: architecture is mandatory; offset is hexadecimal
speakeasy -t .\shellcode.bin --raw --arch x86 --raw-offset 0x20 -o .\report.json
speakeasy -t .\shellcode64.bin --raw --arch amd64 -o .\report.json
# Override a PE entry-point RVA; emulate child processes; pass emulated argv
speakeasy -t .\sample.exe --entry-point 0x1234 -o .\report.json
speakeasy -t .\sample.exe --emulate-children --argv="-log -silent" -o .\report.json
# Acquire artifacts and richer telemetry
speakeasy -t .\sample.exe --dropped-files-path .\dropped.zip -o .\report.json
speakeasy -t .\sample.exe --analysis-coverage --snapshot-memory-regions -o .\report.json
speakeasy -t .\sample.exe --analysis-memory-tracing -o .\report.json
# Debug logging or interactive GDB stub (GDB extra must have been provisioned)
speakeasy -t .\sample.exe --verbose -o .\report.json 2> .\run.log
speakeasy -t .\sample.exe --gdb --gdb-port 1234 --verbose
The CLI normally runs emulation in a worker process. Keep that default for timeout supervision and
use --no-mp only for in-process debugging; --gdb enables it automatically. Bound unstable samples
with all three controls when useful:
speakeasy -t .\sample.exe --timeout 20 --max-api-count 4000 `
--max-instructions 800000 -o .\report.json
Configuration and emulated environment
# Write UTF-8 explicitly, especially under Windows PowerShell 5.1
speakeasy --dump-default-config | Set-Content -Encoding utf8 .\default-config.json
speakeasy -t .\sample.exe -c .\profile.json --timeout 30 -o .\report.json
# Identity, process context, environment, and deterministic DNS
speakeasy -t .\sample.exe --hostname WS-3471 --domain CORP --user-name analyst `
--no-user-is-admin --env TEMP=C:\Windows\Temp `
--network-dns-names c2.example=203.0.113.10 -o .\report.json
# Expose a host file or directory inside the modeled filesystem; repeat -V as needed
speakeasy -t .\sample.exe `
-V 'C:\samples\config.dat:C:\ProgramData\config.dat' -o .\report.json
Precedence is built-in defaults, then -c JSON overlay, then explicit CLI flags. Nested object lists
(filesystem, registry, HTTP responses, processes, module inventories) belong in the JSON config;
consult the configuration reference instead of forcing them onto the command line.
Inspect the report
$r = Get-Content -Raw .\report.json | ConvertFrom-Json
$r | Select-Object sha256, arch, filetype, size, emulation_total_runtime
$r.entry_points | Select-Object ep_type, start_addr, instr_count, error
$r.entry_points.events | Where-Object event -in @('api','file_write','net_dns','net_http','process_create')
$r.entry_points.dropped_files | Select-Object path, size, sha256
Events are chronological within each entry-point run. Expensive options have direct report effects:
coverage populates entry_points[].coverage, memory tracing adds access counters and symbol accesses,
and snapshots place compressed payloads in the top-level content-addressed data store.
Create a Python environment only when required
Create a task-local environment in a writable analysis directory. Do not put it in source control and
do not reuse the uv tool environment. Keep the package version aligned with the provisioned CLI.
uv venv --python 3.13 .\.venv-speakeasy
uv pip install --python .\.venv-speakeasy\Scripts\python.exe `
"speakeasy-emulator==2.0.0b3"
$sePython = Resolve-Path .\.venv-speakeasy\Scripts\python.exe
& $sePython -c "import importlib.metadata, speakeasy; print(importlib.metadata.version('speakeasy-emulator'))"
& $sePython .\analyze.py .\sample.exe
For a disposable one-file script, let uv create an on-demand isolated environment instead:
uv run --no-project --python 3.13 --with "speakeasy-emulator==2.0.0b3" -- `
python .\analyze.py .\sample.exe
Only add Speakeasy to a project's dependency/lock file when that project's own code imports it.
Python API fast paths
Use the public speakeasy.Speakeasy facade. Prefer a context manager so native hooks are released.
from pathlib import Path
import speakeasy
target = Path("sample.dll")
with speakeasy.Speakeasy(argv=["-silent"]) as se:
module = se.load_module(str(target))
se.run_module(module, all_entrypoints=True, emulate_children=False)
report = se.get_report()
report_dict = report.model_dump(mode="json")
Path("report.json").write_text(se.get_json_report(), encoding="utf-8")
Unlike the CLI, run_module() defaults to all_entrypoints=False; request all exports explicitly
when that is the intended analysis. Load from bytes with load_module(data=blob, filename="sample.dll").
import speakeasy
with speakeasy.Speakeasy() as se:
address = se.load_shellcode("shellcode.bin", speakeasy.arch.ARCH_X86)
se.run_shellcode(address, offset=0x20)
report = se.get_report()
Register hooks before loading/running. API-hook callbacks receive the facade, full API name, original
handler, and raw parameters; call func(params) when normal modeled behavior should still occur.
import speakeasy
def hook_write_file(emu, api_name, func, params):
result = func(params)
handle, buffer, size, written, overlapped = params
data = emu.mem_read(buffer, min(size, 256))
print(api_name, handle, data)
return result
with speakeasy.Speakeasy() as se:
se.add_api_hook(hook_write_file, "kernel32", "WriteFile")
module = se.load_module("sample.exe")
se.run_module(module)
Other high-value methods:
add_code_hook, add_dyn_code_hook, add_mem_read_hook, add_mem_write_hook
mem_read, mem_write, mem_alloc, reg_read, reg_write, get_mem_maps
module.get_exports() plus call(export.address, params) for selected DLL exports
get_dropped_files() and create_file_archive() for in-process artifact collection
stop() from a hook and resume(address, count=...) for custom execution control
Code and memory hooks can fire per instruction/access; restrict address ranges and avoid expensive work
inside callbacks. Lower-level emulator objects are internal and may change.
Failure interpretation
Unsupported API: module.name: the current path cannot safely continue without a handler; inspect
other entry-point runs, adjust the environment, or add a handler only when its semantics are known.
- Early/odd behavior: model expected files, registry, identity, modules, and network responses in config.
- Slow/huge output: disable memory tracing, coverage, or snapshots and add hard stopping limits.
- CLI flags missing from this sheet: verify
uv tool list and speakeasy -h; do not silently replace
the externally provisioned tool.
Bundled reference map
The upstream documentation snapshot is under references/speakeasy-docs/.
Open only the pages needed for the task:
- Start/help: index,
install,
help, and
README
- CLI: full reference,
help snapshot,
analysis recipes,
environment overrides, and
execution controls
- Config/report/memory: configuration,
reporting,
memory, and
limitations
- Python/extending: library,
API handlers,
volumes, and
examples
- Debug/version detail: GDB,
GDB examples,
Speakeasy 2 walkthrough, and
Safety
A Python environment isolates dependencies, not the operating system. Analyze untrusted samples in a
disposable VM/container, keep host mounts narrow, and never expose secrets or production data. Speakeasy
models Windows behavior rather than intentionally executing the sample natively, but parsers, native
dependencies, and emulator code still process attacker-controlled bytes.