{"slug": "easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers", "title": "EasyRE-Agent – an AI agent that solves crackmes and checks its own answers", "summary": "EasyRE-Agent, a new open tool, runs an AI agent inside a Docker container preloaded with a reverse-engineering toolchain (Ghidra, Detect It Easy, Wine, and .NET, Python, Java and JavaScript decompilers) to solve crackmes and CTF binaries, accepting only answers that pass a regex, success message or user-supplied command. The agent works with Claude Code, OpenAI Codex, or any OpenAI-compatible API including OpenRouter, Ollama, LM Studio and vLLM, and adds hint and tutor modes that guide users without revealing the answer, plus per-job time and token budgets, resumable jobs, and reports logging the exact model, time and tokens used. The project requires about 10 GB of free disk space and is intended for crackmes, CTF reversing challenges and puzzle binaries, not for analyzing real malware.", "body_md": "**Give it a binary and a task. Pick any model. Get the answer, or learn how to find it yourself.**\n\nEasyRE-Agent runs an AI agent inside a Docker container. The container holds your reverse engineering toolchain, and the agent uses it to solve a task you give it.\n\n```\n📁 tasks/crackme ─► 🔎 triage ─► 🤖 agent (your model) ─► ✅ verifier ─► 📄 report.md / 💡 hints.md\n```\n\n|  | Feature |  | \n|---|---|---|\n| 🤖 | **Any model** | Claude Code, OpenAI Codex, or any OpenAI-compatible API: OpenRouter, Ollama, LM Studio, vLLM | \n| ✅ | **Verified answers** | Checks against a regex, a success message, or your own command. The agent keeps working until a candidate passes. | \n| 🎓 | **Hint mode** | The agent solves privately and gives you graded hints, one at a time. The answer stays hidden, including in the console output. | \n| 🧑🏫 | **Tutor mode** | An interactive tutor: you tell it what you did, and it guides you step by step without spoiling the answer | \n| 💰 | **Stats** | Totals of time, tokens and cost per model over all jobs | \n| ⏱️ | **Budgets** | Time and token limits per job | \n| 🔁 | **Resumable** | Continue a job later with more time or a different model | \n| 🔎 | **Triage** | File types, runtimes and packers detected up front | \n| 📄 | **Reports** | Answer, solution path, scripts, dead ends, exact model, time and tokens | \n| 🧰 | **Your toolchain** | Plug-in install script plus Markdown skills (playbooks) the agent reads on demand | \n\nReversing a crackme or a CTF binary is mostly the same loop every time: figure out what the file is, pick the right tools, find the check, pull out the constants, write a small solver, and confirm the answer. An AI agent can do much of that loop, but in practice three things get in the way:\n\n- **The toolchain.** A typical task needs a mix of Ghidra, Detect It Easy, Wine, and decompilers for .NET, Python, Java or JavaScript. Installing and wiring all of that on every machine is slow and fragile. EasyRE-Agent ships it as one Docker image that behaves the same on Windows, Linux and macOS.\n- **Guessing.** Without tools and a checker, a model tends to produce an answer that only looks plausible. Here the agent works on the real file with real tools, follows a playbook (skill) for that kind of target, and an answer counts only when the program or your checker accepts it.\n- **Lock-in.** It works with Claude, Codex or any OpenAI-compatible model, including local ones, so you can use what you already have and compare models on the same task.\n\nIt is also built for learning. Being handed the answer teaches little, so hint and tutor modes let the agent solve the task privately and then guide you toward the solution without spoiling it.\n\nEasyRE-Agent is meant for crackmes, CTF reversing challenges and puzzle binaries, not for analyzing real malware (see \n\nPick your system: [💻 Windows](#-windows) · [🐧 Linux](#-linux) · [🍎 macOS](#-macos)\n\nYou need about 10 GB of free disk space (see [💾 Disk space](#-disk-space)).\n\n1. **Install Docker.** Get[Docker Desktop](https://www.docker.com/products/docker-desktop/) , install it with the default settings (WSL 2), and start it.\n2. **Run the setup.** Double-click**`setup.cmd`** in the project folder. It builds the image, asks which model to use, logs you in and checks everything (see[⚙️ What the setup does](#%EF%B8%8F-what-the-setup-does) ).\n3. **Add a task.** Put the files into a folder under`tasks` :\n\n```\ntasks\\crackme\\crackme.exe\ntasks\\crackme\\task.md      (description, optional)\n```\n\n4. **Solve it.** Open PowerShell or Command Prompt in the project folder:\nThe first command solves the task. The second opens the report.\n\n```\n.\\easyre.cmd run crackme --success \"Correct\"\n.\\easyre.cmd open\n```\n\n1. **Install Docker.** Install[Docker Engine](https://docs.docker.com/engine/install/) with the Compose plugin. Then let your user run Docker without`sudo` , and log out and back in:\n\n```\nsudo usermod -aG docker $USER\n```\n\n2. **Run the setup** in the project folder:\n\n```\nsh setup.sh\n```\n\n3. **Add a task:** put its files into`tasks/crackme/` (plus an optional`task.md` with the description).\n4. **Solve it:**\n\n```\nsh easyre.sh run crackme --success \"Correct\"\nsh easyre.sh open\n```\n\nThe image is x86-64 (Wine needs 32-bit x86 libraries). On ARM Linux it runs only with x86 emulation (qemu/binfmt) and is slow.\n\n1. **Install Docker.** Get[Docker Desktop for Mac](https://www.docker.com/products/docker-desktop/) and start it. On Apple Silicon (M1–M4), enable**Settings → General → Use Rosetta for x86_64/amd64 emulation** . The image is x86-64, so it runs emulated there: it works, but builds and runs more slowly.\n2. **Run the setup** in Terminal, in the project folder:\n\n```\nsh setup.sh\n```\n\n3. **Add a task:** put its files into`tasks/crackme/` (plus an optional`task.md` with the description).\n4. **Solve it:**\n\n```\nsh easyre.sh run crackme --success \"Correct\"\nsh easyre.sh open\n```\n\n📝 The examples below use the Windows form `.\\easyre.cmd`. On Linux and macOS, write `sh easyre.sh` instead; everything else is the same.\n\n1. \nChecks that Docker runs.\n2. \nBuilds the image (the first build takes several minutes).\n3. \nAsks which model you want to use and logs you in: Choice You need 🟠 Claude subscription (recommended) Claude Pro or Max account 🟠 Claude API key Anthropic API key 🟢 ChatGPT account via Codex ChatGPT account 🟢 OpenAI API key OpenAI API key 🔵 OpenRouter OpenRouter API key 💎 Google Gemini Gemini API key from aistudio.google.com 🦙 Ollama (local, free) Ollama running with a model that supports tool calling 🖥️ LM Studio (local, free) LM Studio server running\n4. \nRuns `easyre doctor` to check that everything works.\n\n`--success` is the text the program prints when the answer is right. Leave it out if the program prints nothing like that.\n\n```\n.\\easyre.cmd doctor\n```\n\n`doctor` checks your model profile, credentials, API connection, Wine and skills. It shows each problem together with how to fix it. To switch models later, run the setup again, or see [🎛️ Profiles](#%EF%B8%8F-profiles).\n\n**Colors:** the output is colored. If you see codes like `←[32m` instead of colors, use Windows Terminal, or add `NO_COLOR=1` to `.env`.\n\n```\neasyre run TARGET [options]     solve a task (folder or file under ./tasks)\neasyre resume JOB [options]     continue a job\neasyre hint JOB [--answer]      next hint (or reveal the answer)\neasyre tutor JOB                continue a tutor conversation\neasyre jobs                     list jobs\neasyre open [JOB] [folder]      open a job's report (or tutor chat, or folder)\neasyre profiles                 list model profiles\neasyre doctor                   check that the setup works\neasyre stats                    time, tokens and cost per model\neasyre close JOB                mark a job as closed (resume reopens it)\neasyre rm JOB... | --FILTER     delete job folders; filters: --open --closed --unsolved --solved --all\neasyre login claude|codex       authenticate a backend\n```\n\n| Option | Description | \n|---|---|\n| `--desc` /`--desc-file` | Task description. Default: `task.md` ,`opis.txt` or`README.md` from the task folder. | \n| `--success REGEX` | Output that means the answer was accepted | \n| `--verify CMD` | Checker command. `{}` is replaced by the candidate; otherwise the candidate goes to stdin. | \n| `--flag-format REGEX` | Required answer shape, e.g. `\"flag\\{.+\\}\"` | \n| `--profile` | Model profile from `config/backends.toml` | \n| `--backend` | `claude` (default),`codex` or`openai` | \n| `--model` | Model name for the backend | \n| `--mode` | `solve` (default),`hint` or`tutor` | \n| `--budget-min` /`--budget-tokens` | Time budget in minutes (default 120) and output-token budget | \n| `--logs` | Stream the agent's commands live instead of the progress bar | \n| `-i` | Interactive session (Claude Code / Codex UI) | \n\n```\n.\\easyre.cmd run crackme --success \"(?i)correct\"\n.\\easyre.cmd run keygenme --verify \"wine /work/src/app.exe {}\" --success \"Valid\"\n.\\easyre.cmd run ctf-rev --flag-format \"CTF\\{.+\\}\"\n.\\easyre.cmd run crackme --mode hint\n.\\easyre.cmd hint crackme\n.\\easyre.cmd run crackme --mode tutor --success \"Correct\"\n.\\easyre.cmd tutor crackme\n.\\easyre.cmd run crackme --backend openai --model qwen3-coder --budget-min 30\n.\\easyre.cmd resume crackme --budget-min 60\n.\\easyre.cmd open\n.\\easyre.cmd open crackme\n.\\easyre.cmd open crackme folder\n```\n\n1. Opens the newest job's `report.md` (or`tutor.md` for tutor jobs) in your default app.\n2. Opens the newest job whose name starts with `crackme` .\n3. Opens that job's folder in Explorer.\n\n`open` runs on your computer, not in Docker, so it starts instantly.\n\n```\n.\\easyre.cmd run crackme --mode tutor --success \"Correct\"\n```\n\n1. The agent first solves the task privately. The console shows only progress, so nothing spoils the answer.\n2. Then a chat starts. Tell it what you did and what you see, and it replies to where **you** are: it confirms the right path, warns about dead ends, and suggests one small next step.\n\n```\ntutor> This is a small 64-bit console program. What have you tried so far?\nyou> I found main, it calls checkPassword. What next?\ntutor> Good. Look at what checkPassword compares its argument with...\n```\n\n| Command | What it does | \n|---|---|\n| `/hint` | Ask for a nudge | \n| `/answer` | Reveal the answer (asks for confirmation) | \n| `/quit` | Leave. Continue later with `easyre tutor <job>` | \n\nThe conversation is saved to `tutor.md` in the job folder. If a reply accidentally contains the answer, it is replaced with `[hidden]`.\n\n1. `--flag-format` must match, if set.\n2. `--verify` runs, and its output is matched against`--success` . Without`--success` , exit code 0 counts as success.\n3. If only `--success` is set and the task has exactly one`.exe` or ELF file, that file is run automatically with the candidate on stdin (through Wine for`.exe` ).\n4. With no verifier, the agent must prove the answer itself, and the report marks it `unverified` .\n\n`easyre --help` also lists two commands marked `(agent)`. The agent runs them inside the job's container; you do not need them:\n\n| Command | What it does | \n|---|---|\n| `easyre check '<answer>'` | Runs the verifier above on a candidate. Exit 0 = accepted: the answer is stored in the job and the agent writes the report. Any other exit = rejected, and the agent keeps working. Every attempt is logged in `.easyre/attempts.log` . | \n| `easyre done` | Hint mode only: confirms `hints.md` has enough sections and does not contain the answer, then marks the hints as finished. | \n\nRun from your own console, they only print a note, because there is no job to check against. Use `easyre jobs` and `easyre open` to see results.\n\nThe example is a console crackme that asks for a serial and prints `Correct!` or `Wrong`:\n\n```\ntasks/keygenme/keygenme.exe\ntasks/keygenme/task.md        Find the valid serial.\n.\\easyre.cmd run keygenme --success \"Correct\"\n```\n\nSteps 1–3 and 5–7 are fixed code in `easyre`. Step 4 is what a model typically does: it is not scripted. The model picks its tools itself, guided by the skills and the rules in `config/AGENT.md`.\n\n**1. Start.** `easyre.cmd` runs `docker compose run --rm easyre easyre run …` in a fresh container. `tasks/` and `jobs/` are mounted, and so are `easyre`, `config/` and `skills/` (live, so edits need no rebuild).\n\n**2. Job setup.**\n\n- Creates `jobs/keygenme-<timestamp>/` with`src/` (a copy of the task, archives extracted),`agent/` and`.easyre/` .\n- Takes the description from `task.md` (or`opis.txt` ,`README.md` ).\n- Links the job as `/work` , the agent's working directory.\n- Picks the verifier: `--success` is set and the task has exactly one`.exe` , so the verifier is`wine /work/src/keygenme.exe` , with the candidate on stdin.\n\n**3. Triage.** For every file: `file`, byte markers (PyInstaller, .NET, UPX, Go, Rust, Delphi, AutoIt, WASM, Electron, …), repair of a broken `MZ` header, and `diec`. On the main native binary, the Ghidra prefetch starts in the background. It writes `functions.txt`, `strings.txt`, `imports.txt`, `decompiled.c` and finally `DONE` to `agent/prefetch/`. The result goes into `triage.md`:\n\n```\n- keygenme.exe (48213 B): PE32 executable (console) Intel 80386, for MS Windows\n  - DIE: Compiler: MinGW\nBackground Ghidra analysis of `keygenme.exe` started -> /work/agent/prefetch/ ...\n```\n\n**4. The agent works.** It gets instructions (the rules from `AGENT.md`, the report format for its mode, the list of skills, the toolchain notes and this job's verifier) and a prompt with the task description and the triage. With the Claude backend, easyre runs `claude -p --output-format stream-json --model claude-opus-5-5 …` and logs every event to `.easyre/log.jsonl`. A typical run:\n\n|  | What the agent does | Tools | \n|---|---|---|\n| a | Reads the general plan, then the skill for this kind of target | `re-methodology` →`native-binaries` ,`ghidra-headless` | \n| b | Runs the program once | `printf 'test\\n' \\| wine /work/src/keygenme.exe` →`Wrong` | \n| c | Finds the success and failure strings | `strings -n 6` ,`strings -el` ,`agent/prefetch/strings.txt` | \n| d | Finds the function that checks the input | `grep -n Correct agent/prefetch/decompiled.c` | \n| e | Reads the check, and the disassembly when the C looks wrong | `decompiled.c` ,`objdump -d -M intel` ,`r2` | \n| f | Pulls the constants out of the file instead of guessing | `xxd` at the offset, or the bytes from Ghidra | \n| g | Records findings and dead ends | `agent/notes.md` :`hypothesis \\| evidence \\| result` | \n| h | Solves it the cheapest way | an inversion in Python ( `agent/solve.py` );`z3` for tangled constraints;`unicorn` ,`angr` ,`WINEDEBUG=+relay` or`winedbg` when running beats reading | \n| i | Confirms the candidate on the real program | `printf 'SERIAL\\n' \\| wine keygenme.exe` →`Correct!` | \n| j | Submits the answer | `easyre check 'SERIAL'` | \n| k | Writes the report | `/work/report.md` | \n\nSteps e–h on this example. The decompiled check:\n\n```\nif (strlen(s) != 12) return 0;\nfor (i = 0; i < 12; i++)\n    if (((s[i] ^ 0x5A) + i) != expected[i]) return 0;\nreturn 1;\n```\n\nThe agent reads `expected` from `.rdata` and inverts the check:\n\n```\nexp = bytes.fromhex(\"1b2a3c...\")\nprint(bytes(((e - i) & 0xff) ^ 0x5A for i, e in enumerate(exp)).decode())\n```\n\nOther targets change only the skill in step a and the tools: UPX → `upx -d`; .NET / Unity → `ilspycmd`, `de4dot`, `il2cppdumper`; PyInstaller → `pyinstxtractor-ng` + `pycdc`; APK / JAR → `jadx`, `apktool`, `cfr`; Electron → `asar` + `webcrack`; AutoIt → `autoit-ripper`; WebAssembly → `wasm-decompile` + Node; crypto → `capa`, `yara`, `pycryptodome`; a custom VM → handler map → disassembler → `z3`.\n\n**5. Verification.** `easyre check` runs the verifier (see [✅ How verification works](#-how-verification-works)). Here it runs `wine /work/src/keygenme.exe` with the candidate on stdin (up to 120 s) and matches the output against `Correct`. Accepted: the answer is stored in `.easyre/ANSWER` and the agent is told to write the report. Rejected: the agent keeps working. Every attempt is logged in `.easyre/attempts.log`.\n\n**6. Guard rails.**\n\n- **Stop hook:** if the agent tries to stop without an accepted answer, a hook sends it back to work (up to 30 times). The only early exit is writing`HELP.md` when a human is really needed.\n- **Resume loop:** if the model process exits, easyre resumes the same session (up to 12 times). It waits 15 minutes on a rate limit, and starts a fresh session if the old one is gone; files and notes stay.\n- **Budget:** 120 minutes by default (`--budget-min` ), plus an optional token limit (`--budget-tokens` ). When it runs out, the report says`not solved (time)` .\n- **Ctrl+C** stops the job with a report;`easyre resume keygenme` continues it.\n\n**7. Result.** easyre puts a header on top of the agent's `report.md`: status, backend and exact model, time, tokens, cost, and the answer with its check result. `easyre open` opens it.\n\n```\njobs/keygenme-20261030-201500/\n├── report.md     the result\n├── TASK.md\n├── src/          the task, never modified\n├── agent/        notes.md, solve.py, prefetch/, patched copies\n└── .easyre/      job.json, triage.md, log.jsonl, attempts.log, ANSWER\n```\n\nIn hint and tutor mode, steps 1–5 are the same: the model solves the task first, but the answer goes to a private `.easyre/answer`. Then it writes graded hints (` hints.md`, checked by `easyre done`) or starts the tutor chat.\n\n|  | Backend | Runs | Setup in `.env` | \n|---|---|---|---|\n| 🟠 | `claude` | Claude Code (headless, subagents, skills) | `CLAUDE_CODE_OAUTH_TOKEN` (subscription) or`ANTHROPIC_API_KEY` | \n| 🟢 | `codex` | OpenAI Codex CLI | `easyre login codex` or`OPENAI_API_KEY` | \n| 🔵 | `openai` | Built-in agent loop ( `bash` ,`read_file` ,`write_file` ,`read_skill` ) | `OPENAI_BASE_URL` ,`OPENAI_API_KEY` ,`OPENAI_MODEL` | \n\nThe `openai` backend covers every OpenAI-compatible API, including Google Gemini (profile `gemini`), OpenRouter, Ollama and LM Studio.\n\n🦙 **Local model** (Ollama on the host):\n\n```\nEASYRE_BACKEND=openai\nOPENAI_BASE_URL=http://host.docker.internal:11434/v1\nOPENAI_MODEL=qwen3-coder\n```\n\nThe model must support tool calling.\n\nSave your models once in `config/backends.toml` and switch between them by name:\n\n```\ndefault = \"claude-opus\"\n\n[profiles.claude-opus]\nbackend = \"claude\"\nmodel = \"claude-opus-5-5\"\n\n[profiles.ollama-qwen]\nbackend = \"openai\"\nbase_url = \"http://host.docker.internal:11434/v1\"\nmodel = \"qwen3-coder\"\napi_key = \"ollama\"\n\n[profiles.openrouter]\nbackend = \"openai\"\nbase_url = \"https://openrouter.ai/api/v1\"\nmodel = \"deepseek/deepseek-chat\"\napi_key_env = \"OPENROUTER_API_KEY\"\n.\\easyre.cmd profiles\n.\\easyre.cmd run crackme --profile ollama-qwen\n.\\easyre.cmd resume crackme --profile claude-opus\n```\n\n- `easyre profiles` lists the profiles;`*` marks the default.\n- `run ... --profile ollama-qwen` uses a local model.\n- `resume ... --profile claude-opus` continues the same job with a stronger model.\n\n**Which exact model?** The Claude profiles use full model IDs (`claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`), so every job runs on a known version. When a new model comes out, change the ID in `config/backends.toml`. To always follow the newest model instead, use an alias: `model = \"opus\"` (or `sonnet`, `haiku`). Either way, the exact model the backend reported is saved per job and shown in `easyre jobs`, `easyre stats`, the report header and, as `last run`, in `easyre profiles`.\n\n`api_key_env` reads the key from `.env`, so secrets stay out of the profile file. If you omit `--profile`, the `default` profile is used, or `EASYRE_PROFILE` if it is set in `.env`. Passing `--backend` without `--profile` skips the profiles and uses the backend directly.\n\n```\n.\\easyre.cmd stats\n```\n\n`easyre stats` sums time, tokens and cost per model over all your jobs. Claude reports its cost itself; this is the API-equivalent price, and a subscription costs nothing extra. For other APIs, add `price_in` and `price_out` (USD per 1M tokens) to the profile in `config/backends.toml`.\n\nSkills are Markdown playbooks in `skills/<name>/SKILL.md`. The agent sees the list and loads the one that matches the target. Each skill is short and practical: when to use it, the steps, the commands, the pitfalls.\n\n|  | Skill | Covers | Status | \n|---|---|---|---|\n| 🧭 | `re-methodology` | General approach: orient, find the check, extract, solve, verify | ✅ | \n| ⚙️ | `native-binaries` | PE / ELF: C, C++, Go, Rust, Delphi, VB6 | ✅ | \n| 🟪 | `dotnet` | .NET and Unity (Mono / IL2CPP) | ✅ | \n| 🐍 | `python-targets` | Packaged Python apps and bytecode | ✅ | \n| ☕ | `jvm-android` | JAR and APK | ✅ | \n| 🌐 | `javascript-electron` | JS, Node, Electron | ✅ | \n| 🧾 | `autoit` | Compiled AutoIt scripts | ✅ | \n| 🕸️ | `wasm` | WebAssembly modules | ✅ | \n| 🎰 | `custom-vm` | Custom VMs and bytecode interpreters | ✅ | \n| 🍷 | `dynamic-wine` | Running and observing Windows programs under Wine | ✅ | \n| 🧮 | `solvers` | Constraint solving, symbolic execution, emulation | ✅ | \n| 🔐 | `crypto-id` | Recognizing crypto and encoding primitives | ✅ | \n| 🗂️ | `formats-forensics` | Documents, archives, images, captures, custom formats | ✅ | \n| 🐉 | `ghidra-headless` | Ghidra without the GUI (headless scripts) | ✅ | \n\n✅ ready · 🚧 in progress\n\nTo add a skill, copy `skills/_TEMPLATE.md` to `skills/<name>/SKILL.md`. It appears to the agent automatically.\n\nThe toolchain is installed by `toolchain/install.sh` during `docker compose build`. It is split into **modules** under `toolchain/modules/*.sh`, chosen with the `EASYRE_TOOLS` setting in `.env`. `toolchain/README.md` has the full tool-by-tool matrix, and the agent reads it.\n\nBy default (`EASYRE_TOOLS=all`) every module below is installed. For a smaller image, list only the modules you need in `.env` and rebuild:\n\n```\nEASYRE_TOOLS=core,die,ghidra\n```\n\n| Module | What you get | Size | \n|---|---|---|\n| `wine`*(always)* | Wine 32/64 + Xvfb + MinGW runtime DLLs: run `.exe` , incl. GUI | — | \n| `core` | binutils, gdb, radare2, upx, binwalk, yara, FLOSS, capa; py: capstone, keystone, unicorn, z3, lief, pefile, pwntools, pycryptodome | ~0.5 GB | \n| `die` | `diec` (Detect It Easy) — triage's compiler/packer detection | ~0.3 GB | \n| `ghidra` | Headless Ghidra + matching JDK + the `prefetch` hook | ~1.5 GB | \n| `dotnet` | .NET SDK, ilspycmd, Il2CppDumper, de4dot | ~1 GB | \n| `jvm` | jadx, apktool, cfr | ~0.2 GB | \n| `python` | pyinstxtractor-ng, pycdc/pycdas, decompyle3/uncompyle6 | ~0.1 GB | \n| `js` | @electron/asar, webcrack, js-beautify | ~0.1 GB | \n| `autoit` | autoit-ripper, AutoIt interpreter ( `autoit3` , under Wine) | ~0.05 GB | \n| `wasm` | wabt: wasm-objdump, wasm2wat, wasm-decompile, wasm-interp, wasm2c | ~0.02 GB | \n| `angr` | angr 9.x symbolic execution (pinned below 10, see `toolchain/README.md` ) | ~1 GB | \n\nEach module is standalone and idempotent, so the agent (root, with network) can also pull a missing one in mid-job: `sh /opt/easyre/toolchain/modules/ghidra.sh`. That install is lost when the job ends, because every job runs in a fresh container, so bake in what you use.\n\n**Prefetch hook:** the `ghidra` module installs `/opt/easyre/tools/prefetch`. When present, triage runs it in the background on the main native binary:\n\n```\nprefetch <binary> <output_dir>\n```\n\nIt drives Ghidra headless to drop `decompiled.c`, `functions.txt`, `strings.txt` and `imports.txt` into `agent/prefetch/`, so the agent can start reading decompiled code immediately. Without the `ghidra` module the hook is simply absent and triage skips it.\n\nRough estimates, not measured:\n\n| Part | Size | \n|---|---|\n| Ubuntu base + Python + basic utilities | ~0.4 GB | \n| Node.js + Claude Code + Codex CLI | ~0.5 GB | \n| `wine` module (Wine 32/64 + Xvfb + prepared prefix + MinGW DLLs) | ~2 GB | \n| All other modules ( `core` ,`die` ,`ghidra` ,`dotnet` ,`jvm` ,`python` ,`js` ,`autoit` ,`wasm` ,`angr` ) | ~4.8 GB | \n| **Image total (default `EASYRE_TOOLS=all`)** | **~8–9 GB** | \n| Build cache during `docker compose build` | +1–3 GB (free with `docker builder prune` ) | \n\nTo save space, set `EASYRE_TOOLS` in `.env` to a subset and rebuild (see the module table above). The biggest are `ghidra` ~1.5 GB, `dotnet` ~1 GB and `angr` ~1 GB; the rest are a few hundred MB or less. `core,die` alone gives a ~4–5 GB image. Jobs in `jobs/` also use space: each one holds a copy of the task plus the agent's files.\n\nEvery job gets its own folder, `jobs/<name>-<timestamp>/`:\n\n```\njobs/crackme-20260930-162257/\n├── 📄 report.md    ← the result: answer, solution path, scripts\n├── 💡 hints.md     ← graded hints (hint mode)\n├── 🧑‍🏫 tutor.md     ← tutor conversation (tutor mode)\n├── 📝 TASK.md      ← the task description\n├── 📦 src/         ← the extracted task files (never modified)\n├── 🛠️ agent/       ← the agent's workspace: notes.md, scripts, patched copies\n└── ⚙️ .easyre/     ← internal: settings, full log, attempts, instructions\n```\n\nUsually you only need `report.md` (or `hints.md`). `agent/notes.md` shows how the agent reasoned. `.easyre/log.jsonl` records every step, for debugging.\n\n```\neasyre                 CLI: jobs, triage, backends, verifier, reports, hints\nsetup.cmd / setup.sh   one-time setup: build, choose model, log in, check\neasyre.cmd / easyre.sh wrappers to run easyre from Windows / Linux / macOS\nconfig/                agent instructions, mode rules, stop hook, backend settings\nskills/                playbooks for the agent\ntoolchain/install.sh   module dispatcher (EASYRE_TOOLS)\ntoolchain/modules/     one install script per tool group\ntoolchain/README.md    tool matrix the agent reads\nDockerfile             base image: agent CLIs + toolchain + skills\ndocker-compose.yml     volumes: tasks/, jobs/, live-mounted easyre, config/, skills/\n```\n\n`easyre`, `config/` and `skills/` are mounted live, so edits take effect without rebuilding.\n\nThe container runs with `SYS_PTRACE` and `seccomp=unconfined`, has network access, and runs the targets. It is meant for crackmes and CTF challenges. Analyze real malware only in an isolated VM without network access.\n\nMIT, see [LICENSE](https://github.com/wojtas99/EasyRE-Agent/blob/main/LICENSE).", "url": "https://wpnews.pro/news/easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers", "canonical_source": "https://github.com/wojtas99/EasyRE-Agent", "published_at": "2026-10-30 19:54:48+00:00", "updated_at": "2026-10-30 20:16:53.071318+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "artificial-intelligence"], "entities": ["EasyRE-Agent", "Docker", "Ghidra", "Detect It Easy", "Wine", "Claude Code", "OpenAI Codex", "OpenRouter"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers", "markdown": "https://wpnews.pro/news/easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers.md", "text": "https://wpnews.pro/news/easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers.txt", "jsonld": "https://wpnews.pro/news/easyre-agent-an-ai-agent-that-solves-crackmes-and-checks-its-own-answers.jsonld"}}