
에이전틱 리버스 엔지니어링 IDE로, 순수 Rust 기반 다중 아키텍처 디스어셈블러, 네이티브 디컴파일러, 디버거, 그리고 바이너리 분석 및 CTF 작업을 위한 LLM 에이전트를 갖추고 있습니다.
에이전트 기반 리버스 엔지니어링 환경 — "리버스 엔지니어링을 위한 Cursor" 정신으로 만든 Ghidra급 데스크톱 앱. Tauri 2(React + TypeScript 프런트엔드)를 기반으로 하며, 그 위에 플러그 가능한 분석 백엔드가 올라간다. 기본값은 순수 Rust 네이티브 엔진 — 외부 프로세스 없음, copyleft 의존성 없음, Capstone을 통한 다중 아키텍처 지원. r2(radare2)를 통해 분석을 실행할 수도 있다: 설치하고 엔진으로 선택하면 앱 전체 — 에이전트 도구와 UI — 가 이를 구동한다. 에이전트 도구와 UI는 백엔드에 구애받지 않는다 — docs/backends.md 참조.

루트에 Cargo 워크스페이스가 있고, 데스크톱 앱은 그 안의 한 패키지다.
tauri/ desktop app (Tauri + React)
src/ React frontend
src-tauri/ Tauri Rust backend (engine sessions, agent wiring)
package.json app scripts (Vite, Vitest, Tauri CLI)
crates/
recurse-agent/ agent framework: LLM loop, tool runtime, SQLite memory
recurse-static/ static analysis: ELF/PE/Mach-O parsing, multi-arch disassembly,
CFG and cross-reference recovery, the engine seam
recurse-vtil/ VTIL-inspired de-obfuscation/de-virtualization IL, lifter, optimizer
recurse-mcp/ standalone headless MCP server (stdio) over the engine — no Tauri, no IDA
recurse-debug/ cross-platform debugger (ptrace/Mach/Win32, breakpoints, stepping)
recurse-eval/ headless eval harness (YAML-configured tiers)
justfile single entry point for both halves
recurse-agent는 에이전트일 뿐이다; 정적 분석은 recurse-static에, 디버거는 recurse-debug에 있으므로 에이전트는 사용하지도 않는 시스템 코드를 끌어들이지 않는다. 어떤 크레이트도 Tauri에 의존하지 않으며, 각각 독립적으로 빌드/테스트된다; recurse-eval은 에이전트를 헤드리스로 구동한다. 모두 워크스페이스 멤버이므로 하나의 Cargo.lock과 하나의 target/이 저장소 전체를 커버한다.
Ctrl+L로 토글)checksec 불필요), 그리고 분석 카운트/clear와 재열기 후에도 유지되며 다음 세션을 시드한다recurse-agent); 동일한 에이전트 루프가 UI와 평가 하네스에서 실행된다lift 연산: 함수를 VTIL 스타일 디오브푸스케이션 IL로 승격하고 루틴 전체에 걸친 전파/폴딩/데드 코드 제거/분기 해석 패스를 실행한다 — 디스어셈블리가 VM 디스패처나 불투명 술어 체인처럼 보일 때 유용하다(docs/vtil-lift.md 참조)decompile은 동일한 recurse-vtil 파이프라인에서 C 유사 의사코드(if/while 구조화, 전체 명령어 커버리지)를 렌더링한다 — 외부 도구 불필요, r2 불필요recurse-mcp 서버: MCP stdio를 통해 동일한 Engine을 모든 MCP 지원 에이전트(Claude Code, Cursor, Claude Desktop, …)에 제공 — Tauri 불필요, IDA 라이선스 불필요, Python 브리지 불필요(docs/recurse-mcp.md 참조)분석은 단일 Engine 트레이트(crates/recurse-static/src/engine.rs)를 통과하므로, 엔진은 선택 사항이지 하드 의존성이 아니다:
native (기본값) — 순수 Rust ELF/PE/Mach-O 파싱 및 다중 아키텍처 디스어셈블리(object + capstone): x86/x86-64, ARM, AArch64, MIPS, PowerPC, RISC-V, SPARC, SystemZ, M68K, BPF. 자식 프로세스 없음, 외부 도구 없음, 빌드에 LGPL 없음. 디컴파일러(recurse-vtil의 lift → optimize → structure 파이프라인 — docs/vtil-lift.md 참조)와 VTIL 스타일 디오브푸스케이션을 위한 lift 연산을 포함한다.설정 메뉴, RECURSE_BACKEND 환경 변수, 또는 저장된 구성으로 선택한다. 에이전트는 하나의 백엔드 중립적 analyze 도구(functions, disasm, graph, lift, decompile, xrefs, strings, imports, info, 그리고 엔진 콘솔용 raw)를 받는다 — 활성 엔진이 실제로 지원하는 연산으로 필터링되므로, raw(네이티브에는 콘솔이 없음)는 사용 가능할 때만 노출된다. UI는 어떤 엔진의 JSON이 아닌 정규 결과 타입을 소비한다. 트레이트, 크레이트 선택, 라이선싱 근거는 docs/backends.md를 참조. 대용량 바이너리 열기가 빠른 이유는 분석이 지연되기 때문이다 — 발견 단계는 함수를 저렴하게 인덱싱하고 기본 블록은 함수를 볼 때만 디코딩된다; docs/lazy-analysis.md 참조.
IDA/Ghidra에 MCP 서버를 붙이거나 CLI 에이전트에 디스어셈블리를 붙여넣는 것은 5개 함수짜리 CTF에서는 통하지만 실제 바이너리에서는 무너진다. Recurse는 챗봇 래퍼가 아니라 목적에 맞게 구축된 환경이다:
pdF 덤프를 컨텍스트로 재파싱할 필요도, 지어낸 0x401023도 없다.npm test가 없다 — 검증은 시각적이다. 에이전트의 이름 변경은 함수 목록, 그래프, 디컴파일에 즉시 전파되므로 사람이 한 번의 클릭으로 확인하거나 거부한다.| Tool | Version (tested) | Install |
|---|---|---|
| Node.js | ≥ 20 (23.11 used) | https://nodejs.org or nvm |
| npm | ≥ 10 | ships with Node.js |
| Rust | ≥ 1.77 (1.97 used) | https://rustup.rs |
| cargo | — | ships with Rust (rustup) |
확인:
node --version && npm --version && rustc --version && cargo --version
기본 네이티브 엔진은 순수 Rust다 — 설치할 것이 없다. 대신 r2(radare2)를 분석 엔진으로 사용하려면 설치하고 선택한다(설정 메뉴 또는 RECURSE_BACKEND=r2); Recurse는 PATH에 있는 r2 바이너리를 구동한다. r2는 선택 사항이며, 빌드에 절대 요구되지 않고, Recurse와 함께 배포되지 않는다 — 직접 설치하라.
Debian/Ubuntu/Pop!_OS:
sudo apt update
sudo apt install -y libwebkit2gtk-4.1-dev build-essential \
curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
다른 배포판: 공식 Tauri prerequisites를 따르라.
두 엔진 모두 하나를 제공한다: native는 recurse-vtil(lift → optimize → structure — docs/vtil-lift.md 참조)을 통해 의사코드를 렌더링하며 설치할 것이 없다; r2는 플러그인이 설치되면 자체적으로 더 완전한 디컴파일러를 제공할 수 있다.
앱 의존성은 tauri/에 있고, Rust는 워크스페이스 루트에서 온다. just가 둘 다 감싸거나(just --list 참조), 직접 구동할 수 있다.
just dev
# equivalent: cd tauri && npm install && npm run tauri dev
Vite 개발 서버를 시작하고 Tauri 창을 실행한다. 첫 컴파일은 시간이 걸리지만(Rust 빌드), 이후에는 빠르다.
just build
# equivalent: cd tauri && npm run tauri build
번들은 target/release/bundle/(워크스페이스 타깃)에 생성된다:
.deb / .rpm / .AppImagetarget/release/recurse의 독립 실행형 바이너리Arch 및 기타 롤링 배포판에서는 AppImage 단계에 일회성 로컬 수정이 필요하다(업스트림 linuxdeploy가 배포판 툴체인보다 뒤처짐) — docs/linux-appimage-build.md 참조.
just preview
# equivalent: cd tauri && npm run build && npm run preview
just lint # cargo clippy --workspace + eslint
just fmt # cargo fmt --all + prettier
just fmt-check # verify without writing
just test # cargo test --workspace + vitest
동등한 직접 명령: 루트에서 cargo clippy --workspace --all-targets, cargo test --workspace; tauri/ 안에서 npm run lint / npm run format / npm run build.
에이전트는 crackme 티어에 대해 헤드리스로 평가된다(crates/recurse-eval/README.md 참조). 티어는 YAML이다: 데이터셋에 대한 선택 필터 또는 고정된 hexid 목록, 그리고 실행 노브.
just eval-fetch # download the tier's binaries
just eval-test # harness self-tests (no API key needed, no LLM calls)
just eval-run # run the tier — the only way to execute an eval YAML
eval-run은 테스트가 아닌 바이너리이므로 cargo test가 에이전트에 돈이나 시간을 절대 쓰지 않는다. 엔드포인트 + 키는 crates/recurse-eval/.env에 넣는다(.env.example 복사). 각 실행은 target/eval-traces/<tier>/<backend>/run.log(전체 내러티브)와 함께 작업당 하나의 <hexid>.json에 턴별 전체 대화를 기록한다. 백엔드(native 또는 r2)는 실행별로 선택 가능하다 — 평가 README 참조.
에이전트 채팅 패널은 모든 OpenAI 호환 엔드포인트에서 실행된다. 앱 내 Model & Provider 대화상자(~/.recurse/recurse.db에 유지됨)에서 또는 환경 변수로 API 키, 베이스 URL, 모델을 구성한다:
# Hosted provider (default)
export RECURSE_LLM_API_KEY=sk-or-... # or OPENROUTER_API_KEY
export RECURSE_LLM_ENDPOINT=https://openrouter.ai/api/v1/chat/completions # optional
export RECURSE_LLM_MODEL=openrouter/auto # optional
에이전트를 모든 로컬 또는 자체 호스팅 OpenAI 호환 서버로 향하게 하라 — Ollama, LM Studio, llama.cpp의 llama-server, vLLM, text-generation-webui, 또는 원격 게이트웨이. 대화상자에서 Base URL을 설정하고(베어 베이스 URL 또는 전체 /chat/completions 경로 모두 작동) 해당 서버의 카탈로그에서 모델을 고르거나, 모델 id(llama3.1:8b, qwen2.5-coder, …)를 직접 입력하라:
export RECURSE_LLM_ENDPOINT=http://localhost:11434/v1 # Ollama
export RECURSE_LLM_MODEL=llama3.1:8b
export RECURSE_LLM_API_KEY= # usually unnecessary locally
로컬 엔드포인트는 API 키가 필요 없다: 키가 비어 있으면 요청은 Authorization 헤더 없이 전송되고, 모델 목록은 엔드포인트 자체의 {base}/models에서 읽는다. 사용자 정의 엔드포인트는 키 없이도 구성된 것으로 취급되므로, 채팅은 로컬 서버에 대해 즉시 작동한다.
자격 증명이 없으면 에코 클라이언트로 폴백하여 배선이 계속 실행 가능하게 유지된다.
에이전트는 라이브 바이너리 컨텍스트(아키텍처, 비트, 타입)를 보고 세션을 통해 전체 분석 표면(디스어셈블리, xref, 문자열, 임포트, 디컴파일)을 구동할 수 있다.
Apache-2.0 — © 2026 Aayush Khanna