Skip to content

0.9.0

Choose a tag to compare

@github-actions github-actions released this 21 May 09:03
· 529 commits to main since this release

Address notes (new)

Every address in the disassembly pane now grows a chat-style note
surface. Right-click a row and pick Notes & AI… (or click the
gutter breadcrumb when a thread already exists) to open a popover
with the address's threads; the user can leave plain notes or ask
the LLM with the disassembly and pdc around the anchor seeded
into the system prompt.

  • Threads are anchored to an address with a chain of
    user / assistant / system messages. Notes carry an editor chain,
    individual messages carry a single immutable author. The gutter
    renders a breadcrumb per address with active threads.
  • Replies stream token-by-token in both frontends; an in-flight
    reply can be cancelled.
  • Each AI roundtrip runs against the session's ambient mission,
    billing token usage and recording the call as a MissionAction
    so the chain is reviewable from the mission view.
  • Threads can be renamed (pencil button in the popover header) and
    individual user messages can be edited or deleted inline, with
    destructive actions confirmed.
  • Notes sync via collaboration (AddressNoteOp: upsert / remove
    plus message append / edit / remove) and persist across detach,
    so threads remain readable and writable when the session isn't
    live.

LLM-backed reverse-engineering tools (new)

Four typed mission tools layered on radare2 + the mission's LLM:
suggest_function_name, suggest_function_signature,
suggest_local_names, and find_vulnerabilities. Suggestions are
proposals — the agent applies them via r2_cmd if it wants.

  • New r2_cmd mission tool runs ad-hoc radare2 commands against
    the session's r2 context (output capped by
    max_output_chars).
  • Address-note threads run through the shared mission tool catalog
    so they have the same surface area as the standalone agent.
  • rename_insight is now LLM-callable and auto-runs in the mission
    loop; the agent dedupes resolver matches sharing an address and
    picks friendly names for AI-installed hooks.
  • Sessions created by the agent notify the sidebar so they appear
    immediately instead of waiting for the next refresh.

Detach-resilient inspection (new)

Disassembly, backtraces, and address notes now keep working when
the process is gone.

  • Per-session module analysis (executable ranges + known
    functions, keyed by module name + LC_UUID) is persisted, so
    on-demand analysis runs once per binary and rebases cleanly on
    reattach.
  • Basic blocks per analyzed function are persisted alongside, used
    to answer enclosingFunction offline.
  • Memory pages are cached and survive detach: module pages are
    keyed by module UUID + offset so cached bytes survive ASLR;
    anonymous (JIT / heap) pages key on a process identity and are
    purged on every fresh attach.
  • Engine.symbolDisplay returns a richer SymbolDisplay (overlay,
    source, raw, primary) and persists every live symbolicate result
    into module_symbol. Offline rendering falls through to that
    table, then to enclosingFunction from the persisted block
    ranges, then to module+offset. Trace block annotation flows
    through the same path so detached traces still get names.
  • Backtrace popovers and "Open Insight" buttons resolve through a
    new Engine.anchor(sessionID:, address:) that falls back to
    lastKnownModules when the node is gone.
  • Insight detail refresh actions: Reread Bytes drops the
    pages overlapping the visible range; Reanalyze Module drops
    the module's analysis and pages, re-running r2 on next access.

Insight naming

Address insights gain a real identity.

  • userTitle replaces the auto-derived title; display name falls
    back to <parent.title>+0x<delta>, then sub_<offset> at
    function starts, then module+offset.
  • A parentInsightID link is maintained automatically: new
    insights link to the enclosing function-start insight, and
    adopt their siblings when they themselves are a function start.
    Fresh ModuleAnalysis runs reparent existing insights when new
    function starts appear.
  • Sidebar context menu Rename… and the rename_insight tool
    both route through Engine.renameInsight, which broadcasts via
    updateInsight and pushes the name into r2 as a flag (plus
    afn at function starts).
  • Dependents (tracer hooks, address notes, sidebar rows) are
    notified on rename so labels refresh live.

Collaboration

The on-disk RE state is now part of the lab snapshot:

  • New SessionOps: updateProcessInfo, updateModuleAnalysis,
    updateInsight, updateModuleSymbols, plus a side-channel
    publish-memory-page / +fetch-memory-page request. The
    driver write-throughs every page it fetches; non-drivers pull
    on miss and persist locally. Late-joiner snapshots ingest the
    whole module_symbol table, all module analyses, and process
    info.
  • Process instances carry a deterministic identity (per-OS, with a
    Process.mainModule + pid fallback) stashed on
    ProcessSession.processInfo, used to key the anon-page cache.

Action Queue (new)

A global Action Queue surfaces in the toolbar as a popover. It
auto-closes when empty.

Project persistence

GTK opens each document into a fresh working copy and exports a
VACUUM INTO snapshot to the user-facing path on save and on
close. Because the engine never moves, hooks stay attached across
Save As. The window-close handler holds the GApplication
while the snapshot and shutdown drain; Engine.shutdown flushes
EventLog and awaits chained event-store writes so events.log
is durable.

The event log moves from a directory of segments to a single
events.log file; EventStore takes a file URL directly.

Tracer

  • Hook switcher in the tracer config view on both frontends, with
    the menu factored into a shared builder on GTK.
  • New mission tools: read_tracer_hook / edit_tracer_hook and
    read_custom_instrument_file / edit_custom_instrument_file
    return line_count so the agent can target line ranges
    instead of rewriting whole files.
  • Add All in the API picker coalesces into one binding write —
    the JSON-roundtripping config binding had been dropping
    intermediate state so only the last hook landed.

MCP

  • tool_call_id is wrapped into a JSON envelope alongside the
    tool result body. MCP clients don't surface _meta to the
    model, so findings could never be grounded; the unused field
    is gone.

UI / UX

  • Arm actions are hidden on sessions that don't go through the arm flow.
  • Editor avatars (the stack used by notebook entries) are reused
    on the mission list / detail and in the address-note popover
    header and message rows.
  • JS inspector tightens up: nested expanders default to collapsed
    via a depth counter; children show in chunks of 5; rows align on
    first text baseline. The previous SwiftUI recursion bug from a
    bare platformLinkButtonStyle() is fixed.
  • HookPack and custom-instrument detail panes are scrollable so
    widgets past the visible area can be reached.
  • Browse for program path action on the local-device new
    session sheet.
  • Live mission text is restored on view re-entry.
  • New mission rows highlight when they first appear (GTK).
  • isDarkMode is replaced by a LumaCore.Appearance enum
    threaded through the disassembler and theme watchers; CFG views
    use themeAppearance to avoid clashing with NSView's
    inherited appearance.
  • iOS editor background now goes through a platform helper so it
    picks up UIColor.secondarySystemBackground.
  • GTK: detached banner stays hidden while attaching; stdio toggle
    tracks state; execution section content inset; New Session
    toolbar button restyled to match the SwiftUI target glyph.

Internal

  • Author extracted into a shared model; REPLCell, Mission,
    and address notes all attribute through it.
  • Note threads run through the shared LLM tool catalog.
  • LLM prompts share a code-style preamble.
  • runCommand / decompile return R2CommandResult so callers
    see r2's log entries; findFunctionStart runs aap once per
    session before giving up; disasm bounds at function end via
    $FB/$FE and pDJ when available.
  • Disassembler is decoupled from ProcessNode via MemoryReader
    and ModuleIntrospector protocols, with a per-session page
    store routing r2 reads.
  • GTK ContextMenu now goes through SwiftGtk bindings instead of
    raw C; destructive confirmations switched from Adw.AlertDialog
    to inline popovers so they no longer steal focus from their
    parent.

Dependencies

  • SwiftyR2 rolled forward to pick up the analysis surfaces the
    new RE tools depend on.