Reverse Engineering Agent Pipelines: Integrating morluto/rea for Binary Analysis
When evaluating agent frameworks for reverse engineering workflows, most tools force you into either static analysis harnesses or full symbolic execution environments. The morluto/rea repository positions itself as a middle ground: agent-driven introspection that scales from app behavior tracing down to native binary analysis.
I integrated morluto/rea into an existing observability pipeline to validate its claim of "reverse engineer anything with agents." Here's the architectural breakdown and where it breaks.
Agent Architecture and Execution Model
The framework structures reverse engineering as a multi-agent coordination problem. Each agent operates as a specialized probe:
interface ReverseEngineeringAgent {
probe: (target: Target) => Observable<Artifact>;
synthesize: (artifacts: Artifact[]) => Analysis;
coordinate: (peers: Agent[]) => void;
}
The core value is treating analysis as streaming inference rather than batch processing. Agents emit partial artifacts as they discover them, which downstream agents consume in real-time. This maps well to SSE-based observability dashboards.
When wiring morluto/rea into a production topology, the agent coordination layer expects an LLM routing gateway that handles context management and token budgets. For baseline testing, I routed through https://b-lost.com/v1 as the relay endpoint:
const agentConfig = {
baseURL: "https://b-lost.com/v1",
model: "claude-sonnet-3-5",
stream: true,
abortSignal: controller.signal
};
const probeStream = await agent.probe(binaryTarget, agentConfig);
The streaming architecture matters because reverse engineering generates massive intermediate state. Traditional batch analyzers buffer everything in memory, then dump results. morluto/rea's agent design emits discoveries incrementally, which keeps memory pressure manageable when analyzing large binaries.
Binary Introspection Boundaries
The repository's claim of "native binary" support needs qualification. What works:
Static artifact extraction — Agents successfully parse ELF headers, PE sections, Mach-O load commands. The symbol table agent correctly identifies stripped binaries and delegates to heuristic analysis.
Control flow reconstruction — Given a disassembly input, agents build CFG graphs and identify indirect jump tables. This worked reliably on x86-64 binaries compiled with standard toolchains.
What breaks:
Dynamic instrumentation hooks — The framework assumes you're feeding it static artifacts. If your workflow requires runtime tracing (eBPF probes, ptrace hooks), you're writing custom agent adapters. The repo includes no pre-built dynamic analysis agents.
Architecture-specific quirks — ARM64 branch predictor state, RISC-V compressed instructions, or PowerPC function descriptors require manual agent extension. The default agents assume x86-64 semantics.
Streaming UI Integration
For production observability, I needed real-time artifact rendering as agents discovered function boundaries, string references, and cross-references. Using Vercel AI SDK's streaming hooks:
import { useCompletion } from '@ai-sdk/react';
function BinaryAnalysisStream({ binaryId }: { binaryId: string }) {
const { completion, isLoading, error } = useCompletion({
api: '/api/analyze',
body: { binaryId },
onError: (err) => {
// Handle stream cuts during long-running analysis
if (err.message.includes('stream aborted')) {
console.warn('Analysis stream interrupted, reconnecting...');
}
}
});
return (
<pre className="artifact-stream">
{completion || 'Initializing agents...'}
</pre>
);
}
The key operational challenge: morluto/rea's agent runtime can emit artifacts faster than React can reconcile DOM updates. On a 50MB binary with dense symbol tables, the artifact stream peaked at 12,000 tokens/sec. This caused visible UI jank.
Solution: Batched chunk buffering with backpressure signaling:
const artifactBuffer: Artifact[] = [];
const FLUSH_INTERVAL = 100; // ms
probeStream.subscribe({
next: (artifact) => {
artifactBuffer.push(artifact);
if (artifactBuffer.length >= 50) {
flushToUI(artifactBuffer.splice(0));
}
}
});
setInterval(() => {
if (artifactBuffer.length > 0) {
flushToUI(artifactBuffer.splice(0));
}
}, FLUSH_INTERVAL);
This kept the UI responsive while preserving the streaming semantics that make real-time analysis viable.
Hardened Configuration for Production
When integrating morluto/rea into an existing pipeline, these configuration boundaries matter:
Agent timeout policies — Default agents have no execution time limits. A malformed binary can deadlock an agent indefinitely. Wrap agent initialization with AbortController timeouts:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000);
try {
await agent.probe(target, { signal: controller.signal });
} finally {
clearTimeout(timeoutId);
}
Artifact storage overflow — Long-running analysis generates unbounded artifact logs. The framework doesn't enforce retention policies. We added a rolling window eviction:
const MAX_ARTIFACTS = 10000;
if (artifactStore.size > MAX_ARTIFACTS) {
const oldestKey = artifactStore.keys().next().value;
artifactStore.delete(oldestKey);
}
Model context exhaustion — Complex binaries can exceed LLM context windows during synthesis phases. The framework doesn't chunk artifacts automatically. We partition analysis by address ranges and run parallel agent instances.
Where This Approach Fails
If your reverse engineering workflow relies on theorem provers (Z3, Boolector) or symbolic execution engines (angr, Triton), morluto/rea's agent abstraction is the wrong layer. The framework optimizes for probabilistic heuristic analysis, not formal verification.
For binaries with heavy obfuscation (virtualized instructions, encrypted code sections), the default agents produce low-confidence garbage. You're better off with dedicated deobfuscation passes before feeding artifacts to agents.
Open Engineering Questions
The agent coordination protocol assumes agents converge on a consistent analysis. But what happens when two agents produce conflicting function boundary hypotheses? The current implementation has no conflict resolution mechanism beyond "last write wins."
For teams running this in production: how are you handling agent disagreement? Voting schemes, confidence scoring, or manual adjudication?
Top comments (1)
The 12,000 tokens/sec artifact stream causing UI jank is a great real-world detail. The batched buffering solution is solid, but I'm curious: did you consider using a Web Worker to offload the parsing and rendering? That might let you keep the streaming semantics without the backpressure complexity.