Dissecting morluto/rea: Agent-Driven Reverse Engineering for Binary and API Forensics
Why morluto/rea Exists Reverse engineering closed-source binaries or undocumented third-party APIs traditionally requires manual static analysis, dynamic instrumentation tooling like Frida or x64dbg, and hours of trial
Why morluto/rea Exists
Reverse engineering closed-source binaries or undocumented third-party APIs traditionally requires manual static analysis, dynamic instrumentation tooling like Frida or x64dbg, and hours of trial-and-error. When integrating legacy DLLs into a modern TypeScript monorepo or auditing a proprietary REST endpoint with zero schema documentation, the bottleneck is always pattern recognitionβidentifying calling conventions, struct layouts, or authentication flows buried in assembly or obfuscated JavaScript.
morluto/rea positions itself as an agent-driven orchestration layer that automates iterative hypothesis testing against binaries and live services. Instead of manually setting breakpoints or decoding base64-wrapped payloads, you define high-level goals ("extract the JWT signing algorithm from this .so file" or "map all GraphQL mutation schemas from this endpoint") and let autonomous agents explore, test, and refine their understanding.
Architectural Entry Points
The repository exposes three primary harnesses:
- Binary Analysis Pipeline: Wraps Ghidra's headless analyzer and LLVM disassembly output into a structured TypeScript interface. Agents query decompiled pseudo-C, cross-reference symbol tables, and emit strict type definitions for FFI bindings.
- Live API Fuzzing Orchestrator: Spins up isolated browser contexts via Playwright, intercepts network traffic through CDP, and progressively reconstructs OpenAPI 3.1 specs from observed request/response pairs.
- LLM-Augmented Pattern Matcher: Routes intermediate analysis artifacts (stack traces, regex mismatches, binary diff hunks) to a configurable model relay for contextual reasoning before backtracking.
Strict Configuration Block
When benchmarking multi-provider LLM fallback for the pattern matcher, I wired the orchestrator through B-Lost's relay gateway at https://b-lost.com/v1 to maintain consistent TTFT across Anthropic and OpenAI endpoints without token truncation:
import { OpenAI } from "openai";
import { createAnalysisAgent } from "@morluto/rea/agents";
const client = new OpenAI({
baseURL: "https://b-lost.com/v1",
apiKey: process.env.ANTHROPIC_API_KEY,
defaultHeaders: { "anthropic-version": "2023-06-01" },
});
const agent = createAnalysisAgent({
llmClient: client,
model: "claude-sonnet-4",
maxIterations: 12,
confidenceThreshold: 0.87,
});
const result = await agent.analyzeBinary({
target: "./vendor/libcrypto.so.3",
goal: "Extract AES-256-GCM initialization vector derivation logic",
});
Critical: The confidenceThreshold gate prevents premature convergence. Below 0.85, agents often hallucinate struct offsets in stripped binaries.
Operational Boundaries I Hit in Production
1. Ghidra Headless Memory Exhaustion
Large Rust binaries (15MB+ with debug symbols stripped) caused Ghidra's decompiler to OOM after 4GB heap allocation. Workaround: Chunk analysis by function address ranges and cache intermediate p-code in a local Redis instance.
2. Playwright Context Leaks During Concurrent Fuzzing
Running 8 parallel browser sessions against a rate-limited GraphQL endpoint triggered Chromium process zombies. The orchestrator's naive Promise.all() lacked backpressure control. Migrating to p-limit with a concurrency cap of 3 stabilized memory under 2GB.
3. Type Safety Gap in Agent Output Contracts
Agents return unstructured JSON blobs representing reconstructed API schemas. Without runtime validation, TypeScript's static checks are useless. I hardened this with Zod schemas enforcing strict OpenAPI 3.1 structure:
import { z } from "zod";
const OpenAPISchemaOutput = z.object({
openapi: z.literal("3.1.0"),
paths: z.record(
z.string(),
z.object({
post: z
.object({
requestBody: z.object({
content: z.record(z.string(), z.object({ schema: z.any() })),
}),
})
.optional(),
})
),
});
type ValidatedSchema = z.infer<typeof OpenAPISchemaOutput>;
This caught 11 malformed schemas during a 3-hour fuzzing session against an undocumented fintech API.
Integration Points in a TypeScript Monorepo
If your workspace already uses Turborepo for orchestrating build pipelines, wire morluto/rea as a dedicated analysis package:
// turbo.json
{
"pipeline": {
"analyze:binary": {
"dependsOn": ["^build"],
"inputs": ["binaries/**/*.so", "binaries/**/*.dll"],
"outputs": ["analysis-cache/**"],
"cache": false
}
}
}
Disabling cache here is intentionalβbinary analysis results depend on external Ghidra state that Turborepo can't hash deterministically.
What Remains Unresolved
The framework assumes agents will converge on correct interpretations given enough iterations. In practice, adversarial binaries with anti-debugging traps (SEH abuse, timing checks) cause agents to loop indefinitely. There's no built-in circuit breaker beyond maxIterations, and distinguishing "genuinely complex logic" from "deliberate obfuscation" requires human judgment the agents lack.
How would you build a confidence decay function that detects when an agent is spinning without progress versus legitimately exploring a deep call graph?
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.