# borer 0.2.1-dev (v0.2.1-97-g4d2ebe1e) > borer is a reverse-engineering engine built for AI agents. It gives an agent what a human reverse engineer brings to a binary: it finds the code that matters, reads it as C, follows data through it and writes down what it learned. It is one Rust binary: an MCP server when run with no arguments, a command-line tool with them. There is no GUI, and no Ghidra, IDA or Binary Ninja underneath. ## Why borer exists Most software that matters ships as binaries nobody can read: malware, closed firmware, game clients, drivers, the third-party libraries inside every product. Reading them takes reverse engineers, and there are far too few of them for the volume of code that needs reading. A malware analyst triages a handful of samples a day while millions arrive. A vulnerability researcher audits one component while the attack surface around it keeps growing. Agents can read code all day without tiring. What they lack is a tool made for them. The existing disassemblers were built for a person at a screen: interactive GUIs, state hidden in a project database, output sized for eyes rather than a context window, and answers an agent has no way to check. borer is that tool, designed from the start for a reader that is a program: - **Answers an agent can trust.** Every block of decompiled C is run in an emulator from seeded states and compared with the machine code it came from, and the output says how much was checked. Instructions it cannot model stay as `/* asm: ... */` instead of a guess. An agent that knows which lines are proven can build on them. - **Built for a context window.** Every list is filtered and paged on the server and says `# showing N of M`. A repeated request with `since=` returns only what changed. The same question gives the same bytes every time. - **Fast enough to read everything.** A whole binary loads and decompiles in seconds, so an agent can sweep every function instead of guessing where to look. - **Safe on hostile input.** No clock, no random seed, bounds-checked reads, capped scans and fuel-limited walks: a malformed or malicious file gets an error, never a crash. The binary is never modified, and annotations are dry-run by default. - **Its own engine.** The analysis, lifters, emulator, structurer and decompiler are written from scratch in Rust for this purpose, so every layer can be shaped around what an agent needs. Only instruction decoding and file parsing come from standard crates. ## What it is for - **Malware analysis.** Triage a sample in one call (what it is, how it is packed or protected, where to start), then unpack it, decode its strings, pull out its indicators, and write a YARA rule that finds its family again. - **Vulnerability research.** Follow attacker-controlled data from an input to where it is used with taint analysis, find the checks between them, solve for inputs that reach a path, and diff a patched binary against the old one to see what was fixed. - **Auditing what you ship.** Read the closed-source libraries, drivers and firmware inside a product the same way you would read your own code. - **Understanding software.** Recover class layouts, protocols and message formats, and read a running process's objects by their recovered layout. Formats: PE, ELF, Mach-O, raw code and memory dumps. Architectures: x86, x86-64 and arm64 for disassembly, decompilation and emulation. 32-bit ARM (A32 and Thumb-2) for disassembly and decompilation. ## Where it is going The aim is an agent that takes a binary and returns what a skilled reverse engineer would: what it does, what is dangerous in it, and the evidence for each claim. borer is built to push every measure as far as it will go: faster analysis, less memory, more of the binary understood, more of the output proven, and decompiled code closer to the source. When it reaches a limit, the next step is to move that limit. Each step below moves borer toward that aim: 1. **Decompiled C indistinguishable from source.** Natural loops and conditions instead of gotos, recovered types and structures, and text that compiles back to the same machine code, with the emulator check kept on every line. 2. **Whole-program reasoning.** Data flow, taint and value ranges across every function and every call, so an agent asks "can this input reach that copy unchecked?" and gets an answer with the path that proves it. 3. **Findings.** Built-in detectors for memory-safety bugs, unsafe API use, hard-coded secrets and known malware behaviors, each one reported with its path and a proof or a reproducing input. 4. **Scale.** Fleets of agents on huge codebases and sample feeds: shared analysis caches, incremental re-analysis when a binary changes, and results that diff cleanly between versions. 5. **Every platform.** Wider architecture coverage (32-bit ARM emulation, MIPS, RISC-V), managed code (.NET, Java) and firmware images. 6. **Runtime alongside static.** Debugging, tracing and live memory on every operating system, so a static claim can be confirmed against the running program. ## Install One command downloads the latest release for your machine, checks it against the release's SHA256SUMS, and registers borer with every MCP client it finds. macOS and Linux: ```bash curl -fsSL https://borer.lol/install | sh ``` Windows (PowerShell): ```powershell irm https://borer.lol/install.ps1 | iex ``` `setup` finds Claude Code, Claude Desktop, Cursor, Windsurf, Devin Desktop, VS Code, VS Code Insiders, Gemini CLI, Antigravity, Codex CLI, Zed, OpenCode, pi, Copilot CLI, Grok Build, Cline, Roo Code, Kilo Code, Continue, Amp, Qwen Code, Kiro, Factory Droid, Kimi Code, Junie, Augment, Warp and LM Studio. It backs up each file it edits to `.bak`, replaces an entry whose program no longer exists (`--replace` replaces any other), and ends by naming the clients to restart, since none reads its configuration again while it runs. Quit Claude Desktop from the tray, turn borer on in Cursor under Settings > MCP, and run `/reload` in pi. For Codex it also sets `tool_timeout_sec = 600`, and for pi `"timeout": 600`, since the first analysis of a large binary can take longer than their default minute. pi also gets `"exposure": "direct"`, so borer's tools are offered like built-in ones rather than only to codemode. As a Claude Code plugin, which fetches the binary of the plugin's version when a session starts and replaces it when the plugin updates: ```text /plugin marketplace add imjustprism/borer /plugin install borer@borer ``` Or by hand: download an archive from the [latest release](https://github.com/imjustprism/borer/releases/latest) (Windows x64, Linux x64, macOS), move `borer` where it will stay (`setup` registers the path it runs from), then: ```bash ./borer setup # show what would change ./borer setup --apply # register borer with every client found ``` From source, with the toolchain that `rust-toolchain.toml` pins: ```bash git clone https://github.com/imjustprism/borer cd borer cargo build --release target/release/borer setup --apply ``` To register it by hand, use an absolute path. Claude Desktop, Cursor, Windsurf, Gemini CLI, Antigravity, Qwen Code, Kimi Code, Junie, Augment, Warp, LM Studio and Factory Droid read `mcpServers`. Continue reads it too, from a file of its own (`~/.continue/mcpServers/borer.json`), and Amp reads it under `amp.mcpServers`: ```json { "mcpServers": { "borer": { "command": "/path/to/borer", "args": [] } } } ``` VS Code (`mcp.json` in the user folder) reads `servers`: ```json { "servers": { "borer": { "type": "stdio", "command": "/path/to/borer", "args": [] } } } ``` Zed (`settings.json`) reads `context_servers`: ```json { "context_servers": { "borer": { "command": "/path/to/borer", "args": [] } } } ``` OpenCode (`~/.config/opencode/opencode.json`) and Kilo Code (`~/.config/kilo/kilo.json`) read `mcp`, with the command as an array: ```json { "mcp": { "borer": { "type": "local", "command": ["/path/to/borer"], "enabled": true } } } ``` pi (`~/.pi/agent/mcp.json`, or `pi mcp add borer -- /path/to/borer`) reads `mcpServers`: ```json { "mcpServers": { "borer": { "command": "/path/to/borer", "args": [], "timeout": 600, "exposure": "direct" } } } ``` Copilot CLI (`~/.copilot/mcp-config.json`) wants a `local` server and its tools named: ```json { "mcpServers": { "borer": { "type": "local", "command": "/path/to/borer", "args": [], "tools": ["*"] } } } ``` Cline (`~/.cline/data/settings/cline_mcp_settings.json`), Roo Code and Kiro read `mcpServers` with a `timeout` (in seconds, or milliseconds for Kiro), which `setup` raises for a first analysis. Codex CLI (`~/.codex/config.toml`) and Grok Build (`~/.grok/config.toml`, which takes the same table without the timeouts): ```toml [mcp_servers.borer] command = "/path/to/borer" args = [] startup_timeout_sec = 30 tool_timeout_sec = 600 ``` To uninstall, `borer setup --apply --remove` takes borer out of every client (`borer setup --remove` shows what it would change). Then delete the binary and its cache (`%LOCALAPPDATA%\borer`, or `~/.cache/borer`). The installers do all three: ```bash curl -fsSL https://borer.lol/install | sh -s -- --uninstall ``` ```powershell & ([scriptblock]::Create((irm https://borer.lol/install.ps1))) -Uninstall ``` ## Use it from an agent A typical session: 1. `load_binary` 2. `borer://triage` (what the file is, how it is protected, where to start) 3. `find_function_by_string`, `strings` or `symbols` 4. `function_summary`, then `decompile` 5. `xrefs`, `cfg` or `callgraph` to go wider Any address argument takes `0x` hex, decimal, or a name. | Area | Tools | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Load | `load_binary`, `binary_info`, `fetch_pdb`, `reload` | | Find | `functions`, `function`, `symbols`, `strings`, `search`, `find_function_by_string`, `find_crypto_constants`, `entropy` | | Read code | `function_summary`, `function_strings`, `decompile`, `decompile_batch`, `disassemble`, `disassemble_function`, `cfg`, `callgraph`, `reaches`, `xrefs`, `class_layout` | | Read data | `read`, `hexdump` | | Annotate | `set_name`, `set_comment`, `set_type`, `types`, `annotations`, `save_project`, `load_project` | | Live process (Windows only) | `live_attach`, `live_detach`, `live_modules`, `live_read`, `live_object`, `live_instances`, `live_watch` | | Anything else | `query`, `script` | Deeper analyses are `borer://` resources: taint, struct layout, emulation, input solving, unpacking, flattening, VM dispatch, devirtualization, binary diff, stack strings, decoded and encoded strings, IOCs, byte signatures and YARA rules. `borer://help` lists all of them. A client without resource support passes the same URI to `query`. ## Use it from the command line ```bash borer triage sample.exe borer functions sample.exe borer decompile sample.exe borer xrefs sample.exe borer verify sample.exe # lifter vs emulator, fails on any disagreement borer help # every command ``` Useful flags: `--pack ` loads target knowledge, `--no-pdb` skips the companion PDB, and `--arch x86|x64|arm64` (with `--base`, `--entry` and `--regions`) maps raw code or a dump. ## More - **Live processes (Windows only):** `live_attach` opens a running process read-only (`PROCESS_VM_READ`) and maps the loaded binary onto it. The live tools then read objects by their recovered class layout and watch fields change. Some anti-cheat software flags any foreign handle, read-only or not. - **Packs:** target knowledge (one engine's class names, message ports) lives in local `.borer` files, never in engine code. None ship with borer. `borer sigmake` builds a signature pack from static libraries you already have (COFF `.lib`, ELF `.a`, Rust `.rlib`). - **Other tools:** `borer sig` writes the shortest byte signature that finds a function again (moving bytes wildcarded), `borer yara` a YARA rule from functions' signatures and strings, and `borer names ida|ghidra|binja|x64dbg` borer's names and comments as a script or database those tools apply. `borer info` gives the MD5, SHA-256, imphash and TLSH, and what any data appended past the last section is. `borer addr` converts between virtual address, relative address and file offset. - **Scripting:** sandboxed [Rhai](https://rhai.rs/) scripts (no files, no network, an operation budget) through the `script` tool or `borer script`. - **Sizes:** every answer is capped at 72,000 bytes, cut at a line with a note on how to page the rest (`BORER_BUDGET` sets the cap in bytes, `0` lifts it). A file is read into memory whole, so one past 1 GiB is refused with a message (`BORER_MAX_FILE`, in bytes or with `K`, `M` or `G`, and `0` lifts it). A client that sends a progress token gets a progress notification every few seconds while a first analysis runs. ## Network access borer sends nothing about what you analyze, and has no telemetry or crash reporting. Three things reach the network: - **The update check.** A command line run at a terminal checks once a day whether a newer release is out: a request to `https://github.com/imjustprism/borer/releases/latest` with the user agent `borer/`, so GitHub sees your IP address, the version and the time. It never runs for the MCP server, under `CI`, or with stderr redirected, and `BORER_NO_UPDATE_CHECK=1` turns it off. - **`fetch_pdb`**, only when asked and dry-run by default, sends the PDB's name, GUID and age to the symbol server (Microsoft's unless configured). `borer doctor` checks that server is reachable unless run as `borer doctor offline`. - **`borer update`** and the installers download the release from GitHub. ## Limits - No instruction sets beyond x86, x86-64, arm64 and 32-bit ARM. - 32-bit ARM code is not emulated, so the emulator-backed analyses refuse it. - On arm64, `taint`, `layout`, `solve`, `unpack` and `devirt` refuse to run. - Shapes the structurer cannot prove stay as labels and gotos. SIMD code prints as intrinsics (`paddd`, `__add_4s`), not as C. - No debugger: no breakpoints and no writes. Live access is Windows only. - .NET IL and Swift are not decompiled (.NET metadata is read). - DWARF supplies names and types, not line tables. - Embedded containers are listed (`borer://children`), not extracted. - Library signatures ship for three runtimes only (LLVM compiler-rt, the Microsoft C++ standard library, the Rust standard library). Any other library needs a pack built with `borer sigmake`. ## Workspace | Crate | Role | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | [`borer-engine`](https://github.com/imjustprism/borer/blob/main/crates/borer-engine) | The analysis core: loading, lifting, emulation, decompilation. Pure and synchronous: no I/O, no async. | | [`borer`](https://github.com/imjustprism/borer/blob/main/crates/borer) | The MCP server and CLI, thin adapters over the engine. | | [`borer-live`](https://github.com/imjustprism/borer/blob/main/crates/borer-live) | Read-only access to a running process. | | [`borer-fixtures`](https://github.com/imjustprism/borer/blob/main/crates/borer-fixtures) | Programs the tests decompile and check against their source. | ## Contributing `python scripts/gate.py` runs what CI runs: fmt, clippy with `-D warnings`, tests, rustdoc, `cargo deny`, typos, ruff and a smoke test of the real server. The rules for people and coding agents alike are in [`borer.rules`](https://github.com/imjustprism/borer/blob/main/borer.rules). Commit titles look like `type: summary`. By opening a pull request you agree that your contribution is licensed under the project's license and that the maintainer may relicense it, including under commercial terms. The details are in [CONTRIBUTING.md](https://github.com/imjustprism/borer/blob/main/CONTRIBUTING.md). ## License borer is free software under the [GNU Affero General Public License v3.0](https://github.com/imjustprism/borer/blob/main/LICENSE) (AGPL-3.0-only). Use it for anything, change it and share it. If you distribute borer or a modified version, or run one as a network service, you must publish its complete source under the same license. Versions 0.1.0 and 0.1.1 were released under MIT. A commercial license, for uses the AGPL does not fit, is available: open an issue or reach out on GitHub. Third-party notices (pefile ordinal tables, the TLSH reference implementation, the library signature sets and the SDK type data, with their provenance) are in [NOTICE](https://github.com/imjustprism/borer/blob/main/NOTICE). Each release archive also carries THIRD-PARTY-LICENSES, the licenses of every crate and runtime the binary links. Ghidra is a project of the NSA. IDA and Hex-Rays are trademarks of Hex-Rays SA, Binary Ninja is a trademark of Vector 35, and Claude is a trademark of Anthropic. Other names are their owners' trademarks. borer is not affiliated with or endorsed by any of them. ## Example session Real answers on `notepad.exe`, as an agent receives them. ### load_binary ```json {"name":"load_binary","arguments":{"path":"C:\\Windows\\System32\\notepad.exe"}} ``` ```text path: C:\Windows\System32\notepad.exe size: 360448 bytes format: PE arch: x86-64 (64-bit) base: 0x140000000 entry: 0x1400019c0 sections (8): name va vsize file_off size rwx entropy .text 0x140001000 0x267e2 0x1000 0x27000 r-x 6.24 fothk 0x140028000 0x1000 0x28000 0x1000 r-x 0.02 .rdata 0x140029000 0xa6c8 0x29000 0xb000 r-- 5.58 .data 0x140034000 0x2740 0x34000 0x1000 rw- 1.62 .pdata 0x140037000 0x1218 0x35000 0x2000 r-- 3.32 .didat 0x140039000 0xf8 0x37000 0x1000 rw- 0.25 .rsrc 0x14003a000 0x1e1d0 0x38000 0x1f000 r-- 6.97 .reloc 0x140059000 0x35c 0x57000 0x1000 r-- 1.62 imports: 340 (25 delay-loaded) [GDI32.dll!SetMapMode, GDI32.dll!SetViewportExtEx, GDI32.dll!SetWindowExtEx, GDI32.dll!LPtoDP, GDI32.dll!SetBkMode, GDI32.dll!GetTextMetricsW, GDI32.dll!TextOutW, GDI32.dll!AbortDoc, GDI32.dll!EndDoc, GDI32.dll!SetAbortProc], ... exports: 0 locals: 514 named functions pdb: 1182 symbols applied image: kind exe linked stamp 0x112f10a4 linker 14.38 subsystem gui mitigations: aslr high-entropy-va dep cfg seh missing: - debug: notepad.pdb (pdb 7C615E8830F1E7745577F37A0DDC2E7E1) notes: unsigned checksum 0x5c23e verified unwind 386 functions dirs: import resource exception reloc debug load-config iat delay-import rich: 11 tools (product.build x objects): 0x1.0 x1380, 0x93.30729 x94, 0x105.33145 x31, 0x108.33145 x28, 0x104.33145 x11, 0x101.33145 x7, ... 5 more rsrc: named icon group_icon version manifest version: CompanyName "Microsoft Corporation" ProductName "Microsoft® Windows® Operating System" FileDescription "Notepad" FileVersion "10.0.26100.9278 (WinBuild.160101.0800)" ProductVersion "10.0.26100.9278" InternalName "Notepad" OriginalFilename "NOTEPAD.EXE" LegalCopyright "© Microsoft Corporation. All rights reserved." manifest: requestedExecutionLevel=asInvoker uiAccess=false dpiAwareness=PerMonitorV2 longPathAware=true libraries (50): COMCTL32.dll, GDI32.dll, USER32.dll, api-ms-win-base-util-l1-1-0.dll, api-ms-win-core-com-l1-1-0.dll, api-ms-win-core-datetime-l1-1-0.dll, api-ms-win-core-debug-l1-1-0.dll, api-ms-win-core-delayload-l1-1-0.dll, api-ms-win-core-delayload-l1-1-1.dll, api-ms-win-core-errorhandling-l1-1-0.dll, api-ms-win-core-file-l1-1-0.dll, api-ms-win-core-handle-l1-1-0.dll, ... hashes: md5 8a1d8175ccca97054cdb25acbb4cc07e sha256 468ffe129c395abf6b21a09efdf261910a95fb98aa982ead73caa7b2b684577e imphash aa9e7e1bd35e47c6de05df960241a986 tlsh T1B8749D5DA2A918D4FD7B41788802C656D6B2F8315325E2EF02D0C13D8F67AD8793EF62 # next: query borer://triage (a whole triage in one call) # since=772ccfd5 # evidence: 1-89e53042 ``` ### find_function_by_string ```json {"name":"find_function_by_string","arguments":{"filter":"Software\\Microsoft\\Notepad","limit":5}} ``` ```text # showing 5 of 7 rows: 8 function/string pairs match 'Software\Microsoft\Notepad' across 3 strings in 7 functions # strings: 1=L"Software\Microsoft\Notepad" 2=L"Software\Microsoft\Notepad\DefaultFonts" # entry name: string numbers 0x14000aac4 DismissBanner: 1 0x14000b3e4 TryCreateStoreBanner: 1 0x140012a2c GetGlobals: 1 2 0x14001ea18 RegGetIntSaveDefault: 1 0x14001eee0 SaveGlobals: 1 # 2 more rows; offset=5 for the next page # evidence: 2-383d1b5f ``` ### function_summary ```json {"name":"function_summary","arguments":{"address":"0x140012a2c"}} ``` ```text name: GetGlobals entry: 0x140012a2c range: 0x140012a2c..0x140012f32 (1286 bytes) returns: nothing a caller uses effects: writes g32_140035654, g32_140035658, g32_14003565c, g32_140035660, g8_140035664, g8_140035665, g8_140035666, g8_140035667 (+12 more); reads g16_14002b664, g32_14002b660, g64_14003566c, g64_140035730 shape: 51 blocks, 257 instrs callers: 1 [NPInit] callees: 7 [RegGetInt, RegGetIntSaveDefault, RegGetString, __security_check_cookie, api-ms-win-core-registry-l1-1-0.dll!RegCloseKey, api-ms-win-core-registry-l1-1-0.dll!RegOpenKeyExW, memset] strings: 0x14002aee8 L"Software\Microsoft\Notepad"; 0x14002b648 L"Lucida Console"; 0x14002b648 L"Lucida Console" +0x10; 0x14002b320 L"lfEscapement"; 0x14002b340 L"lfOrientation"; 0x14002b360 L"lfWeight"; 0x14002b378 L"lfItalic"; 0x14002b390 L"lfUnderline"; 0x14002b3a8 L"lfStrikeOut"; 0x14002b3c0 L"lfCharSet"; 0x14002b3d8 L"lfOutPrecision"; 0x14002b3f8 L"lfClipPrecision" (+27 more) data: 0x140034400 (.data); 0x14002b660 (.rdata); 0x14002b664 (.rdata); 0x140035654 (.data); 0x140035658 (.data); 0x14003565c (.data); 0x140035660 (.data); 0x140035664 (.data); 0x140035665 (.data); 0x140035666 (.data); 0x140035667 (.data); 0x140035668 (.data) (+26 more) # since=cd9a1292 # evidence: 3-fda009b1 ``` ### decompile ```json {"name":"decompile","arguments":{"address":"0x140012a2c","detail":"skeleton","limit":22}} ``` ```text // showing 22 of 91 lines from 0; offset=22 continues 1 // void GetGlobals() @ 0x140012a2c: 257 instructions, 51 blocks 2 // checked vs binary: statements as emitted, 51/51 blocks: 49 proved, 2 tested x3 states; unchecked: C spelling, later text passes 3 // warn: callee RegGetIntSaveDefault: no prototype in the text, so arguments and result are guesses; undeclared g64_14003566c, szSearch, szReplace, chPageText (+1 more): read but declared nowhere 4 // folded: /GS cookie in local_18, 1 check; calls to __security_check_cookie are left out (still replayed) 5 // effects: writes g32_140035654, g32_140035658, g32_14003565c, g32_140035660, g8_140035664, g8_140035665, g8_140035666, g8_140035667 (+12 more); reads g16_14002b664, g32_14002b660, g64_14003566c, g64_140035730 6 ... 7 extern uint64_t RegGetInt(uint64_t, uint64_t, uint64_t); 8 extern void RegGetString(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); 9 extern void *memset(void *s, int c, size_t n); 10 ... 11 memset(&local_c8, 0, 92); 12 ... 13 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Notepad", REG_OPTION_NON_VOLATILE, KEY_READ, &local_d8) == 0) { ... } else { 14 ... 15 } 16 ... 17 var2 = RegGetInt(var1, L"lfEscapement", local_c0); 18 ... 19 var3 = RegGetInt(local_d8, L"lfOrientation", local_bc); 20 ... 21 var4 = RegGetInt(local_d8, L"lfWeight", local_b8); 22 ... # since=369911e5 # evidence: 4-1517fd36 ``` ## Tool reference ### annotations Area: Annotate. Safety: read-only. List the annotation overlay: names, findings and open questions (comments opening with ?); filter pages like every list. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `filter` | string | no | Case-insensitive substring of a row (address, kind or text). | | `limit` | integer | no | Max rows (default 200, max 1000). | | `offset` | integer | no | Rows to skip first (paging). | #### Call ```json { "name": "annotations", "arguments": {} } ``` ### binary_info Area: Load. Safety: read-only. Summary of the current program: format, arch, entry, sections with entropy, imports/exports. #### Parameters None. #### Call ```json { "name": "binary_info", "arguments": {} } ``` ### callgraph Area: Read code. Safety: read-only. Callgraph from a function as mermaid: callees (callers=true: what reaches it), six per function before the rest is shared out, imports as leaves; a trailing %% line counts what was hidden. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Root function entry address. | | `callers` | boolean | no | What reaches it instead of what it calls. | | `max_nodes` | integer | no | Maximum graph nodes (default 30, max 100). | #### Call ```json { "name": "callgraph", "arguments": { "address": "
" } } ``` ### cfg Area: Read code. Safety: read-only. Control-flow graph of a function as mermaid: basic blocks (start, terminator) and successor edges, 300 blocks a page by offset; a trailing %% line says when blocks were cut. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Function entry or any address inside it. | | `offset` | integer | no | Blocks to skip, 300 a page. | #### Call ```json { "name": "cfg", "arguments": { "address": "
" } } ``` ### class_layout Area: Read code. Safety: writes; dry-run unless dry_run=false. Class layout from its methods: field offset, width, reads/writes, methods, vftable; takes a class name or a method address; apply=Name defines it as a struct typing each method's object (dry-run unless dry_run=false). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `apply` | string | no | Struct name to define the layout as. | | `class` | string | yes | Class name or a method address. | | `dry_run` | boolean | no | Preview only; false applies. | #### Call ```json { "name": "class_layout", "arguments": { "class": "" } } ``` ### decompile Area: Read code. Safety: read-only. Pseudo-C with locals local_N/arg_N (N hex bytes below the entry sp: higher N, lower address), named calls, structured flow; /* asm */ marks unmodeled code, goto unproven flow. Line 2 says what the binary checked; a `// warn:` line names what is known wrong in the text (none: no check fired, not proof), `// next:` lines what to read next. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Function entry or any address inside it. | | `detail` | string | no | `skeleton` for flow and calls only; `full` or absent for all of it. Values: `full`: The whole function; `skeleton`: The flow and the calls only | | `filter` | string | no | Keep only lines containing this text, case-insensitively. | | `limit` | integer | no | Return at most this many lines (default 300; more than the text has for all). | | `offset` | integer | no | Skip this many lines of the answer. | #### Call ```json { "name": "decompile", "arguments": { "address": "
" } } ``` ### decompile_batch Area: Read code. Safety: changes state. Pseudo-C for many functions: filter on name or entry hex, max_functions (10, max 50); 6000 chars per function, 40000 total; out= writes all of them uncapped, leaves first, under the output root (BORER_OUTPUT_DIR or the binary's project dir); overwrite=true replaces a file. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `filter` | string | no | Case-insensitive filter on function name or entry hex. | | `library` | boolean | no | With out: also write library functions (default false). | | `max_functions` | integer | no | Maximum functions to decompile (default 10, max 50). | | `out` | string | no | Write every function to this `.c` file instead, uncapped, leaves first; not with `filter` or `max_functions`. Relative to the output root, or absolute under it. | | `overwrite` | boolean | no | With out: replace an existing file (default false). | #### Call ```json { "name": "decompile_batch", "arguments": {} } ``` ### disassemble Area: Read code. Safety: read-only. Disassemble `count` instructions (default 32, max 256) at an address or name as `va text` rows (bytes=true adds bytes); whole functions: disassemble_function. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Address or a function/symbol name. | | `bytes` | boolean | no | Add the raw-bytes column (default false). | | `count` | integer | no | Max instructions (default 32, max 256). | #### Call ```json { "name": "disassemble", "arguments": { "address": "
" } } ``` ### disassemble_function Area: Read code. Safety: read-only. Disassemble a whole function block by block with `L_:` labels and named call/jmp targets (max_instrs default 400, max 2000). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Entry, any address inside it, or a name. | | `bytes` | boolean | no | Add the raw-bytes column (default false). | | `max_instrs` | integer | no | Maximum instructions to return (default 400, max 2000). | #### Call ```json { "name": "disassemble_function", "arguments": { "address": "
" } } ``` ### entropy Area: Find. Safety: read-only. High-entropy regions (packed/encrypted data) as `off va len entropy` rows at or above threshold bits/byte under a `# showing N of M` header; the scan stops at 200 regions. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Most regions listed (default 200, max 200). | | `offset` | integer | no | Regions to skip first (paging). | | `threshold` | number | no | Minimum bits per byte to report (default 7.2, max 8.0). | | `window` | integer | no | Window size in bytes (default 1024, minimum 64). | #### Call ```json { "name": "entropy", "arguments": {} } ``` ### fetch_pdb Area: Load. Safety: writes; dry-run unless dry_run=false. Fetch the loaded PE's missing companion PDB over https from the symbol server (Microsoft's or BORER_SYMBOL_SERVER) into the cache; guid+age must match; dry-run unless dry_run=false; the next load_binary applies it. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `dry_run` | boolean | no | Preview only (default true); false fetches. The symbol server is the Microsoft one, or the one `BORER_SYMBOL_SERVER` names. | #### Call ```json { "name": "fetch_pdb", "arguments": {} } ``` ### find_crypto_constants Area: Find. Safety: read-only. Crypto tables and constants (AES, SHA-1/2, MD5, CRC-32, ChaCha, Blowfish, RC5/6, xxHash/FNV/SipHash, Base64) in the file as `va section algorithm` rows (`off=` if unmapped); then API hashes, 32-bit constants hashing an export name (ROR13 as block_api, djb2, FNV-1a, CRC-32) with the candidates, `corroborated` when a neighbour resolves alike. offset/limit (200, max 500). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | no | Max rows (default 200, max 500). | | `offset` | integer | no | Rows to skip (paging). | #### Call ```json { "name": "find_crypto_constants", "arguments": {} } ``` ### find_function_by_string Area: Find. Safety: read-only. Functions referencing strings containing `filter`: a `# showing N of M` header, a numbered `# strings:` legend, then `entry name: 1 2 5` rows; offset/limit page rows and legend (50, max 300). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `filter` | string | yes | Case-insensitive substring of the referenced string. | | `limit` | integer | no | Max rows and legend strings (default 50, max 300). | | `offset` | integer | no | Function rows to skip first (paging). | #### Call ```json { "name": "find_function_by_string", "arguments": { "filter": "" } } ``` ### function Area: Find. Safety: read-only. One function's detail: name, range, counts, callers/callees and its basic-block table (`start size term successors`, 300 a page by offset). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Entry, any address inside it, or a name. | | `offset` | integer | no | Blocks to skip first (300 a page). | #### Call ```json { "name": "function", "arguments": { "address": "
" } } ``` ### function_strings Area: Read code. Safety: read-only. String literals a function references as `site string_va text` rows (max 100). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Entry, any address inside it, or a name. | #### Call ```json { "name": "function_strings", "arguments": { "address": "
" } } ``` ### function_summary Area: Read code. Safety: read-only. One-call triage of a function: shape, loops, jump tables, callers/callees by name, strings and data it references; `# next:` lines name what to read next. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Entry, any address inside it, or a name. | #### Call ```json { "name": "function_summary", "arguments": { "address": "
" } } ``` ### functions Area: Find. Safety: read-only. Discovered functions as `entry size blocks instrs callers callees src name` rows; filter on name or entry hex, sort=size for the largest first. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `filter` | string | no | Case-insensitive filter on name or entry hex; `thunk` or `funclet` lists what is otherwise left out. | | `limit` | integer | no | Max rows (default 50, max 300). | | `offset` | integer | no | Matches to skip (paging). | | `sort` | string | no | `address` (default) or `size` for the largest first. Values: `address`: By entry address; `size`: By size, the largest first | #### Call ```json { "name": "functions", "arguments": {} } ``` ### hexdump Area: Read data. Safety: read-only. Hexdump `length` bytes (default 64, max 4096) at `address`. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Address (0x-hex or decimal), a name, or `off:` for a file offset. | | `length` | integer | no | Number of bytes (default 64, max 4096). | #### Call ```json { "name": "hexdump", "arguments": { "address": "
" } } ``` ### live_attach Area: Live process (Windows only). Safety: writes; dry-run unless dry_run=false. Attach read-only to a running process (name or pid) running the loaded binary (any process with BORER_LIVE_ANY=1); maps the binary onto it so live tools take static addresses and names. Replaces an earlier attach. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `process` | string | yes | Executable name or pid. | #### Call ```json { "name": "live_attach", "arguments": { "process": "" } } ``` ### live_detach Area: Live process (Windows only). Safety: changes state. Detach from the attached process and drop its watches. #### Parameters None. #### Call ```json { "name": "live_detach", "arguments": {} } ``` ### live_instances Area: Live process (Windows only). Safety: read-only. Find a class's live objects by vtable in the attached process's data; live_object reads one. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `class` | string | yes | Class name. | | `count_only` | boolean | no | Header line only. | | `limit` | integer | no | Max instances (default 64, max 512). | | `offset` | integer | no | Instances to skip. | #### Call ```json { "name": "live_instances", "arguments": { "class": "" } } ``` ### live_modules Area: Live process (Windows only). Safety: read-only. List the attached process's modules. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header line only. | | `filter` | string | no | Substring of name or path. | | `limit` | integer | no | Max rows (default 50, max 500). | | `offset` | integer | no | Rows to skip. | #### Call ```json { "name": "live_modules", "arguments": {} } ``` ### live_object Area: Live process (Windows only). Safety: read-only. Read an object in the attached process as its class: each field's name, type, live value, and what pointers point at. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Object address: live, static, or a name. | | `class` | string | no | Class; default: the one its vtable names. | #### Call ```json { "name": "live_object", "arguments": { "address": "
" } } ``` ### live_read Area: Live process (Windows only). Safety: read-only. Read typed values from the attached process; pointers say what they point at. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Live or static address, or a name; `live:0x..` is never rebased. | | `count` | integer | no | Values (default 1, max 256). | | `kind` | string | no | What to decode the bytes as (default u64). Values: `u8`; `u16`; `u32`; `u64`; `i8`; `i16`; `i32`; `i64`; `f32`; `f64`; `ptr`; `cstr`; `wstr` | #### Call ```json { "name": "live_read", "arguments": { "address": "
" } } ``` ### live_watch Area: Live process (Windows only). Safety: read-only. Watch attached-process memory: with an address, keep its bytes under the name; without, list what changed, naming fields when the class is known. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | no | Address to start watching; omit to diff. | | `class` | string | no | Class naming the fields (default: from the vtable). | | `length` | integer | no | Bytes (default: the class's size, else 256; max 65536). | | `name` | string | yes | Watch name. | #### Call ```json { "name": "live_watch", "arguments": { "name": "" } } ``` ### load_binary Area: Load. Safety: changes state. Load a PE, ELF or Mach-O file (a fat Mach-O: its x86-64 slice), or any other file as raw bytes, as the current program; returns its summary. pdb=false skips the companion PDB; entry_file_offset overrides the entry; arch maps raw code or a dump. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `arch` | string | no | Raw code or a dump: map its bytes as this arch. Values: `x86`; `x64`; `arm64` | | `base` | string | no | With arch: the file's address (default 0). | | `entry` | string | no | With arch: entry address (default first executable byte). | | `entry_file_offset` | integer | no | File offset to use as the entry instead of the header's. | | `path` | string | yes | Absolute path to the file. | | `pdb` | boolean | no | Apply the companion PDB the debug record names (default true). | | `regions` | string | no | With arch, not base: VA@OFF:LEN[:rwx],... (max 256). | #### Call ```json { "name": "load_binary", "arguments": { "path": "" } } ``` ### load_project Area: Annotate. Safety: changes state. Load a JSON project file into the annotation overlay, replacing it. A project saved for another binary (by SHA-256) is refused unless force=true; names, comments and types at addresses no section holds, or blank, are skipped and listed. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `force` | boolean | no | Load a project saved for another binary anyway (default false). | | `path` | string | yes | Project JSON path. | #### Call ```json { "name": "load_project", "arguments": { "path": "" } } ``` ### query Area: Anything else. Safety: read-only. Read a borer:// resource as resources/read does, for hosts that cannot read resources (borer://triage, borer://scenarios/0x401000/a1=0..8); a template read bare says its grammar, !offset=N!limit=N page a listing, borer://help lists all. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `uri` | string | yes | A borer:// resource URI. | #### Call ```json { "name": "query", "arguments": { "uri": "" } } ``` ### reaches Area: Read code. Safety: read-only. Shortest call chain from one function to another (or to an import, called through its slot or a thunk), or that there is none and how far it looked. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `depth` | integer | no | Longest chain to follow (default 24, max 64). | | `from` | string | yes | Function the call chain starts at. | | `to` | string | yes | Target function, or an import by name or slot. | #### Call ```json { "name": "reaches", "arguments": { "from": "", "to": "" } } ``` ### read Area: Read data. Safety: read-only. Read `count` values of `kind` (default one u64) as `va value` rows; pointers are named. `type` reads a user type instead: one row per field. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Address (0x-hex or decimal), a name, or `off:` for a file offset. | | `count` | integer | no | Values to read (default 1, max 256). | | `kind` | string | no | What to decode the bytes as (default u64). Values: `u8`; `u16`; `u32`; `u64`; `i8`; `i16`; `i32`; `i64`; `f32`; `f64`; `ptr`; `cstr`; `wstr` | | `type` | string | no | A user type instead of kind: `Rec`, `Rec[4]`, `char[16]`. | #### Call ```json { "name": "read", "arguments": { "address": "
" } } ``` ### reload Area: Load. Safety: writes; dry-run unless dry_run=false. Restart the server on the binary at its path, keeping the session, the loaded file and its names and comments: use after rebuilding borer, instead of restarting the client. #### Parameters None. #### Call ```json { "name": "reload", "arguments": {} } ``` ### save_project Area: Annotate. Safety: changes state. Save the annotation overlay (names, comments, types) to a .json project file keyed by the binary's SHA-256, under the output root (BORER_OUTPUT_DIR or the binary's project dir); overwrite=true replaces a file. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `overwrite` | boolean | no | Replace an existing file (default false). | | `path` | string | yes | Output `.json` path, relative to the output root or absolute under it. | #### Call ```json { "name": "save_project", "arguments": { "path": "" } } ``` ### script Area: Anything else. Safety: writes; dry-run unless dry_run=false. Run a sandboxed Rhai script over the loaded program: what it printed, then the names and comments it proposed (dry-run unless dry_run=false). print(help()) lists every call; query(uri) reads any borer:// resource, rows(uri) its table. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `code` | string | yes | Rhai source. | | `dry_run` | boolean | no | Preview only (default true); false applies. | #### Call ```json { "name": "script", "arguments": { "code": "" } } ``` ### search Area: Find. Safety: read-only. Search the whole file for bytes (AOB hex, ?? wildcards) or kind=text substring; hits as `function: va va ...` rows, `off=` where unmapped; offset/limit (200, max 500). #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `kind` | string | no | What the query is (default bytes). Values: `bytes`; `text` | | `limit` | integer | no | Max hits (default 200, max 500). | | `offset` | integer | no | Hits to skip (default 0). | | `query` | string | yes | Hex bytes with ?? wildcards (kind=bytes) or a literal substring (kind=text). | #### Call ```json { "name": "search", "arguments": { "query": "" } } ``` ### set_comment Area: Annotate. Safety: writes; dry-run unless dry_run=false. Comment an address in the overlay; dry-run unless dry_run=false. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Address the comment attaches to. | | `comment` | string | yes | Comment text. | | `dry_run` | boolean | no | Preview only (default true); false applies. | #### Call ```json { "name": "set_comment", "arguments": { "address": "
", "comment": "" } } ``` ### set_name Area: Annotate. Safety: writes; dry-run unless dry_run=false. Name a function (any address inside it) or a data global in the overlay, not the binary; names=["addr=name",...] renames many. A name taken elsewhere needs force=true. Dry-run unless dry_run=false. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | no | Function entry, any address inside it, or a data address. | | `dry_run` | boolean | no | Preview only (default true); false applies. | | `force` | boolean | no | Take a name another address holds (default false). | | `name` | string | no | New name, an identifier (C++ `::<>~`, `@$?.` kept). | | `names` | array | no | Many at once instead: `address=name` each (max 500). | #### Call ```json { "name": "set_name", "arguments": {} } ``` ### set_type Area: Annotate. Safety: writes; dry-run unless dry_run=false. Define or apply a user type: at a data global `type` types it (a `Player *` names the fields read through it); at a function it is the C prototype, or with `var` (a1, local_58) that variable's; `type` alone declares C types. Dry-run unless dry_run=false. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | no | Data global to type, or a function for a prototype or `var`. | | `dry_run` | boolean | no | Preview only; false applies. | | `fields` | array | no | Struct fields, each `offset:name:type` (`0x1c:mp:u32`). | | `name` | string | no | Struct, enum or typedef to define, or `var`'s new name. | | `size` | integer | no | Size past the last field, or an enum's width (4 or 8). | | `type` | string | no | Type to apply or typedef (`Player *`), a prototype, or alone C declarations. | | `values` | array | no | Enum values, each `name:value` (`Run:1`). | | `var` | string | no | Function variable to name/type (`a1`, `local_58`). | #### Call ```json { "name": "set_type", "arguments": {} } ``` ### strings Area: Find. Safety: read-only. Printable ASCII/UTF-16LE strings as `va len enc "text"` rows; runs that are bytes of decoded instructions (prologues, nop padding) are left out. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `encoding` | string | no | Which strings to scan for (default both). Values: `ascii`; `utf16`; `both` | | `filter` | string | no | Case-insensitive substring filter. | | `limit` | integer | no | Max rows (default 200, max 500). | | `min_length` | integer | no | Minimum length (default 5, min 4). | | `offset` | integer | no | Matches to skip (paging). | #### Call ```json { "name": "strings", "arguments": {} } ``` ### symbols Area: Find. Safety: read-only. Imports/exports/forwards/locals/data as `kind addr name` rows under `# module:` lines, demangled (a forward ends `-> MODULE.name`); xrefs(import) lists its call sites. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `filter` | string | no | Case-insensitive substring of the raw (module included) or demangled name. | | `kind` | string | no | One kind of symbol only (default every kind); drops the kind column. Values: `import`; `export`; `local`; `forward`; `data` | | `limit` | integer | no | Max rows (default 50, max 1000). | | `offset` | integer | no | Matches to skip (paging). | #### Call ```json { "name": "symbols", "arguments": {} } ``` ### types Area: Annotate. Safety: read-only. List user-defined types and where they are applied; filter pages like every list. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `count_only` | boolean | no | Header only (default false). | | `filter` | string | no | Substring filter on name or applied address. | | `limit` | integer | no | Max rows (default 50, max 500). | | `offset` | integer | no | Rows to skip first (paging). | #### Call ```json { "name": "types", "arguments": {} } ``` ### xrefs Area: Read code. Safety: read-only. References to an address or name, one `function: site kind, ...` row per referencing function, same-code functions folded; an import lists calls through its slot; `Class+0x24` lists who touches that field. #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | yes | Address or name (function, import, overlay name), or Class+offset. | | `count_only` | boolean | no | Header only (default false). | | `limit` | integer | no | Max groups (default 60, max 500). | | `offset` | integer | no | Groups to skip first (paging). | #### Call ```json { "name": "xrefs", "arguments": { "address": "
" } } ``` ## Resources 62 URI templates for the heavier questions. Read one with `resources/read`, or pass the URI to the `query` tool from a client without resource support. `borer://help/{name}` explains any of them with an example. ### `borer://help/{name}` How to read one resource: its URI, what it answers and, for a template, an example built from the loaded binary ### `borer://session/evidence/{id}` The answer its `# evidence:` line names, kept as it was sent; every answer carries one as its last line (a mermaid graph: `%% evidence:`), the id -<8 hex digits>, and this returns the text behind it or says it was let go past the 256 the session keeps ### `borer://playbook/{name}` A prompt's text, for an agent whose host offers prompts only to its user: triage, protocol, find_check/ or explain_function/ ### `borer://stackstrings/{filter}` Stack strings whose text contains the filter ### `borer://flat/{address}` Cases of one flattening dispatcher, in table order, each with where it ends. The table order is not the order they run ### `borer://solve/{spec}` Find an argument value that makes a check answer differently: spec is
[,aN] (the decompiler's aN, a1 by default). Every constant the function compares against is tried and the answers grouped, so a value standing apart is the one it wants, with the comparison it came from ### `borer://partial/{address}` A counted loop comparing a few bits of a product to a byte table: the iterations, the bit window, the table and the loop-invariant multiplicand. That shape is a hidden-number problem, solved by lattice reduction and not by more samples ### `borer://sig/{address}` The shortest byte signature that matches the code at a function or address exactly once, the bytes that move between builds (RIP-relative displacements, absolute addresses, branch offsets) wildcarded: the pattern, a C string with its mask, and whether it is unique ### `borer://yara/{functions}` A YARA rule that finds the functions again: each one's unique byte signature and the strings it references, under the file's magic; functions are names or entries, comma-separated. The rule ends at its closing brace: save it up to there, since borer's own note lines follow, or use the CLI's borer yara, which writes it alone ### `borer://names/{tool}` borer's names and comments for another tool to apply: tool is ida (an IDAPython script), ghidra (a Ghidra Python script), binja (a Binary Ninja script) or x64dbg (a database to load); a PE's scripts rebase to the tool's image base. An x64dbg database ends at its closing brace: save it up to there, since borer's own note lines follow, or use the CLI's borer names, which writes the file alone ### `borer://addr/{place}` One place as virtual address, relative address, file offset, section and function: place is a virtual address, rva: or off: ### `borer://encoded/{filter}` Encoded strings whose decoded value contains {filter} ### `borer://why/{address}` What is at an address and how borer knows: where its name came from (the compiler's debug information, a symbol, inferred from code, or nothing), why the function was discovered, what refers to it, and any value recovered by running the code that builds it ### `borer://layout/{spec}` Propose a structure from what a function does through one pointer: spec is
[,] (a register, or aN for the argument the decompiler names aN; default the first argument). Each row is a field with the width of the access and what it is passed to. Add ,apply= at a function's entry to define the fields as struct Name and type that parameter with it, so decompile names them (a dry run; add ,dry_run=false to apply) ### `borer://taint/{spec}` Follow a value forward through its function: spec is
[,] (a register, or aN for the argument the decompiler names aN; default rax, where a call leaves its result). Reports the instructions that carry it, the calls it is passed to and as which argument, the memory it is stored into, and where it still is at the end ### `borer://emulate/{address}` Run code and read the result. The address carries an experiment: comma-separated reg=val, aN=val (the argument the decompiler names aN; a1 is the first), w= (set data or patch code), stop=, steps= (at most 20000000), trace= (what each of the last n instructions changed; a small steps= watches the start instead), origin= (the instruction that first put the value v in a register or in memory), profile= (the n most-run addresses and most-read pages, where the steps went; at most 64), dump=: (at most 4096 bytes, ?? where nothing is mapped). Reports final registers, the imported APIs and syscalls it serviced as api(args) -> ret with each argument decoded (a string as text, a flag or handle named, an unknown pointer as ptr 0x...), decoded text and each dump. ### `borer://devirt/{address}` Run a virtualized function and recover the program it executes: handlers summarized once, the trace cleaned of dead stores (writes nothing that runs after them reads) and cut into straight-line runs at every virtual branch, one line per step. The address carries comma-separated settings: budget= raises the step cap (2000000 by default, at most 100000000) for a protector whose dispatch starts after a long bootstrap; strict faults on the first read of an import or of memory the loader would fill, where by default it reads zero and goes on; reg= presets a register, such as the VM's context pointer the entry does not build ### `borer://unpack/{address}` Run a packer's bootstrap and report the code it decrypts into memory, with the original entry point. Append ,budget=N to raise the step cap toward a fuller unpack ### `borer://calls/{callee}` Every call site of a function or import (direct, through its slot or a thunk) with the arguments the decompiler resolves at each: a constant in hex, a string quoted, a global by name, else the expression, ? where the lifter saw none (an import is padded to its declared parameters). [,aN=]...: aN=0x40 keeps the calls whose argument aN is that number, aN=text the ones whose argument or string contains it, aN=? the unseen ones; aN!=, aN> and aN< too; offset= for the next page (200 rows a page, 500 callers decompiled at most) ### `borer://iocs/{filter}` Indicators of one type (url, domain, ip, ipv4, ipv6, email, registry, path, pipe, mutex, object, useragent) or whose value contains the text, comma-separated; offset= for the next page ### `borer://hidden/{filter}` Run-time generated strings whose text or generator matches {filter} ### `borer://decoded/{filter}` Decoder-recovered strings whose text contains {filter}; offset= for the next page ### `borer://oracle/{address}` Run the function at {address} over a probe string in every argument shape and report what it does with it ### `borer://run/{spec}` Call a function on inputs typed by its recovered signature and check its decompiled text on them: [,steps=N]/[;...], each input its arguments in order: 5, -1, "text", hex:0102 or out:16 (a zeroed buffer). A row per input: the return value, the stop, the steps, the bytes each buffer holds after, and whether the text run as C agrees, differs (at a line) or is unchecked (at most 64 inputs, 1000000 steps each by default, 100000000 in all); then the imported APIs and syscalls the runs serviced as api(args) -> ret with each argument decoded ### `borer://diverge/{spec}` Call a function on two inputs and report where the runs part ways: the first step that differs (the comparison that split them), the calls each side then makes, and the writes and serviced calls that differ: [,steps=N]/; ### `borer://vectors/{spec}` Test vectors for reimplementing a function: [,count=N][,steps=N]. Inputs from the constants it compares and generated from its recovered signature (16 by default, at most 64), each run in the emulator: a row per input with what it returned and left in its buffers, then a C harness asserting the vectors that returned ### `borer://diff/{path}` Compare the loaded binary against another version at {path} and report which functions changed, were added or removed ### `borer://difffn/{function}/{path}` Show how one function changed between the loaded binary and another version at {path}, as a diff of the decompilations ### `borer://carry/{path}` Carry this project's names to another build of the same program: each name with its new address and how the function was paired, by identical body or by shape. An update moves every address, and the fingerprints do not move ### `borer://migrate/{function}/{path}` Migrate the field offsets a function reads from the loaded build to the version at {path}: which offsets are unchanged, removed, added, or moved ### `borer://vm/{address}` The handlers of one dispatch loop, each with what it does ### `borer://asserts/{filter}` Asserted fields whose name or class contains the filter ### `borer://sources/{filter}` Source files whose path contains the filter, with their function counts ### `borer://classes/{filter}` Registered classes whose name or code contains the filter ### `borer://messages/{filter}` Classes with a registered wire id whose name contains the filter, each with its named fields and the handlers testing for the id (200 a page) ### `borer://map/{namespace}` One namespace's classes, each with its role, parent, methods and instance (5000 rows at most) ### `borer://ports/{filter}` The messages ports accept and their handlers, for the components or messages whose name contains the filter (5000 rows at most) ### `borer://attrs/{filter}` Registered attributes whose name or code contains the filter (200 a page); one exact match lists every function reading or writing it with the definition global ### `borer://exportpack/{spec}` The session's names as a pack that names the same functions in another build by their first bytes: , or ,all to add the names borer recovered ### `borer://scenario/{spec}` A function decompiled under assumptions, /: branches and switches on them fold, only the code that can run is written, and the first line counts the blocks cut ### `borer://scenarios/{spec}` A dispatcher exploded, / or /: a scenario per value, the values that behave alike grouped, each row with its blocks kept, calls and returns ### `borer://script/{path}` Runs a Rhai script file against the loaded program in borer's sandbox: what it printed, and the names and comments it proposes (set_name applies one) ### `borer://clr/{filter}` A .NET assembly's metadata rows of one kind (type, method, pinvoke, memberref, asmref, moduleref, string) or whose name or detail contains the text, comma-separated; offset= for the next page ### `borer://singletons/{filter}` Singletons whose class name contains the filter ### `borer://function/{address}` function_summary at an address or name ### `borer://decompile/{address}` Pseudo-C of the function at an address or name ### `borer://disasm/{address}` Disassembly of the function at an address or name ### `borer://fields/{address}` Field offsets the function at an address or name dereferences, by (base, offset) ### `borer://fieldrefs/{offset}` Every instruction program-wide that reads, writes or takes the address of [reg+offset], with its function; `offset[,name-filter]`, 500 rows at most ### `borer://vslot/{slot}` Every recovered class whose virtual at a zero-based vtable slot returns a constant (a wire id, a type tag), by value; `slot[,class-filter]` ### `borer://schema/{function}` The record a deserializer reads off its stream (fields, widths, nesting, repeats), for a function by address or name, or the reading virtual of a class ### `borer://schemas/{slot}` Every class with a constant at a zero-based vtable slot and the record its reading virtual decodes, one line each: a protocol as a table; `slot[,class-filter]` ### `borer://encode/{function}` What a serializer writes onto its stream (fields in wire order, widths, the object field each came from, helpers followed into the members they write), for a function by address or name, or the writing virtual of a class ### `borer://hooks/{slot}` Every class with a constant at a zero-based vtable slot with the addresses a binding hooks: its encoder, its decoder, its handler and each call site the client sends it from; `slot[,class-filter]` ### `borer://protocol/{slot}` Every class with a constant at a zero-based vtable slot on one row with who constructs it, the handler receiving it, what it writes onto the wire and what it reads back: the whole protocol as one table; `slot[,class-filter]` ### `borer://senders/{slot}` Every class with a constant at a zero-based vtable slot and the functions calling its factory or constructors: who sends each command, as a table; `slot[,class-filter]` ### `borer://encodes/{slot}` Every class with a constant at a zero-based vtable slot and what its writing virtual puts on the wire, one line each: the outbound protocol as a table; `slot[,class-filter]` ### `borer://shape/{function}` Every function running the same code as the one at an address or name over other operands, with the strings and data addresses that differ: a registration family as a table ### `borer://anchors/{path}` Every pinned fact in a manifest file (`field `, `vconst `, `function `, `encode `, `decode ` lines) derived again from the loaded binary and reported held, moved, changed or gone ### `borer://changes/{path}` What changed since a snapshot file of an earlier build (written by the CLI's `borer snapshot `): commands, packet layouts, attributes, message routes and ids added, removed or changed, by stable name ### `borer://about/{name}` Everything known about one name, from every table at once: the attribute (with each user reading or writing it), the class (role, parent, instance, virtuals, the messages it accepts or the components handling it, the wire for a command), and the function summary; start here with any name ### `borer://grep/{text}` Pseudo-C lines program-wide containing the text (percent-encoded), or matching it when written re:, with their function, its signature and the if/else/loop/switch/case lines enclosing them (numbered ^N); decompiles everything once into the index on first use; 200 matching lines at most