Interactive binary vulnerability analysis using ByteRay MCP tools...
When tracing data flow, always use SSA form tools. SSA uniquely versions every variable assignment (buf#1, buf#2), making it precise for tracking where data flows. Use these tools for tracing:
trace_ssa_step -- Incremental SSA trace, 5 steps at a time. Preferred for interactive analysis.trace_variable -- Full-function SSA variable scan. Use when you need all uses at once.read_ssa_form -- View all SSA instructions. Use when you need the complete SSA listing.Do NOT use read_pseudocode for data flow analysis -- pseudocode merges variable versions and loses precision.
Every finding MUST include a CVSS 4.0 severity assessment:
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:Htrace_data_flow or trace_ssa_step confirms a complete source-to-sink path with no sanitization detected by check_sanitizationcheck_sanitization found partial mitigationstrcpy in imports) without data flow evidenceYou MUST run taint analysis tools (trace_data_flow, trace_ssa_step) before assigning High confidence. Do NOT rely on read_pseudocode or list_imports alone -- these show structure, not data flow.
If check_sanitization detects mitigation:
All address parameters MUST be integers, not strings. The server rejects null.
address=4196352 or address=0x401000address="0x401000" or address=nullWhen you get an address from a tool output (e.g. "address": "0x401000"), parse the hex string to an integer before passing it to the next tool.
The ByteRay MCP server runs remotely. It CANNOT access paths like /mnt/user-data/uploads/... -- those only exist in Claude's sandbox. Do NOT call open_binary with a sandbox path. It will always fail with "File not found."
Choose the upload method based on the situation:
If the user can provide a URL to the binary (GitHub release, S3, Google Drive direct link, any public HTTP URL):
fetch_binary(url="https://example.com/firmware.bin", filename="firmware.bin") -- server downloads directly, returns {path, size, sha256}open_binary(path=returned_path) -- begins analysisThis is instant regardless of file size because the server fetches the binary directly over HTTP -- no base64 encoding, no token limits.
import base64
with open("/mnt/user-data/uploads/filename", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
print(len(b64)) # verify it encoded
open_binary(path="filename", content_base64=b64) with the encoded string.For larger files without a URL, the base64 string is too large for a single tool call. Use chunked upload:
import base64, math, os
with open("/mnt/user-data/uploads/filename", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
CHUNK_SIZE = 8192 # 8KB per chunk
total_chunks = math.ceil(len(b64) / CHUNK_SIZE)
for i in range(total_chunks):
chunk = b64[i * CHUNK_SIZE : (i + 1) * CHUNK_SIZE]
with open(f"/tmp/chunk_{i}.txt", "w") as cf:
cf.write(chunk)
print(f"Split into {total_chunks} chunks")
start_upload(filename="name", total_chunks=N) -- returns upload_idupload_chunk(upload_id=id, chunk_index=i, data=chunk_data)finalize_upload(upload_id=id) -- returns {path, size, sha256}open_binary(path=returned_path) -- begins analysisPerformance note: Base64 transfer adds ~33% overhead. For binaries already on the server, always use the local path instead. Always prefer fetch_binary with a URL when possible.
open_binary(path="filename", content_base64=b64)open_binary(path="/absolute/path/to/binary")find_attack_surface(session_id) -- returns sources, sinks, suggestionsWhen you have a name and need an address:
resolve_name(session_id, name="system") -- returns all matching addressesgoto_address, read_pseudocode, who_calls, etc.When you have an address and need context + code:
goto_address(session_id, address=0x401234) -- shows section, function, symbol, AND codeinspect_address(session_id, address) -- metadata only (no code, faster)find_attack_surface -- identify a sink (e.g. "system")who_calls(function_name="system") -- get caller addresstrace_ssa_step(address, variable_name="buf", direction="backward", max_steps=5) -- see 5 operations leading to the sink argumenthas_more: trace_ssa_step(..., from_index=N, max_steps=5) -- next 5 operationsreached_source: vulnerability confirmed (tainted data reaches sink)check_sanitization(address) -- is this a safe pattern?find_attack_surface -- identify sources (recv, fgets) and sinks (system, strcpy)who_calls(function_name="system") -- find functions calling the dangerous sinkread_pseudocode(address) -- does user input flow to the sink?trace_data_flow(function_address) -- run taint analysis to confirm the pathtrace_ssa_step finds a suspicious path: recv -> buf -> systemtrace_ssa_step shows an if-block or function callcheck_sanitization(if_block_address) -- reports what sanitization was detectedis_sanitized=true: path is likely safe, not vulnerableis_sanitized=false: no protection found, vulnerability confirmednavigate_cfg(address, direction="forward") -- see where execution goes after this blocknavigate_cfg(successor_address, direction="forward") -- step further along the pathnavigate_cfg(address, direction="backward") -- see where execution came fromview="ssa" for data flow precision or view="pseudocode" for readabilityresolve_name("target_function") -- get addressget_call_tree(address, direction="callers", depth=3) -- who can reach it?read_pseudocode at each level to check for sanitizationlist_functions(filter="handler") -- narrow down interesting functionsget_function_detail(address) -- see signature, stack frame, calling conventionread_block(address) -- show code for just one block (not the entire function)navigate_cfg(address, direction="forward") -- step through blocks one at a timelist_imports -- see what external APIs the binary linkswho_calls(function_name="strcpy")read_pseudocode or read_block| Question | Tool |
|---|---|
| What is at address X? | goto_address (code + context) or inspect_address (metadata) |
| Where is function Y? | resolve_name |
| Show the code | read_pseudocode (whole function) or read_block (single block) |
| Who calls this? | who_calls (1 level) or get_call_tree(direction="callers") (N levels) |
| What does this call? | what_calls (1 level) or get_call_tree(direction="callees") (N levels) |
| Is there a vulnerability? | trace_ssa_step (incremental, interactive) or trace_data_flow (automated, single function) |
| Is data sanitized? | check_sanitization(address) |
| Walk the CFG step by step | navigate_cfg(address, direction) |
| What APIs does it use? | list_imports |
| Show strings | get_strings(filter="password") or search_strings |
| What sections/segments? | list_sections, list_segments |
| Find byte pattern | search_bytes(pattern="48 8b 05") |
| Trace a variable (full) | trace_variable(address, variable_name) |
| Trace a variable (step) | trace_ssa_step(address, variable_name, direction, max_steps) |
| See SSA form | read_ssa_form(address) |
| See assembly | read_assembly(address) |
| Read raw bytes | read_memory(address, length) |
| Control flow graph | get_control_flow(address, format="mermaid") |
| File hashes | get_file_hash(session_id) |
read_block over read_pseudocode for large functions. read_pseudocode returns the entire function which can be thousands of lines. read_block returns a single basic block -- much faster and smaller.list_functions and get_strings. Set limit=50 instead of loading all 200 results if you only need a few.check_sanitization requires a function address. Do NOT call it on PLT stubs, thunks, or data addresses. If you get "No function at 0x...", use inspect_address or goto_address first to find the containing function's start address, then retry.find_attack_surface, plan which functions to examine before making individual tool calls. This reduces round trips.goto_address to find the nearest function, then use that function's start address instead.open_binary again to create a new session.list_functions) can be passed directly to other toolstrace_ssa_step instead of trace_data_flow for interactive analysis -- it returns 5 steps at a time and you decide whether to continuecheck_sanitization whenever trace_ssa_step shows a conditional branch or function call between source and sinknavigate_cfg with view="ssa" for the most precise data flow during CFG walkingread_block instead of read_pseudocode when a function has many blocks and you only need to see a specific areaget_call_tree is limited to depth 5 and 200 nodes for performancetrace_data_flow works on a single function; chain with who_calls / get_call_tree for interprocedural analysisfind_attack_surface detects firmware-specific sources/sinks automaticallyFor full parameter details, see tool-reference.md.