Skip to content

azw413/Glass

Repository files navigation

Glass

as in transparent and smooth

A fast, native, mobile-app first interactive disassembler. Spiritual successor to IDA Pro for the Android / iOS reverse engineering workflow, built around:

  • smali for APK / DEX / smali handling
  • armv8-encode for AArch64 and ARMv7 (A32 / Thumb) — native .so, iOS Mach-O
  • gpui (Zed) for GPU-accelerated native UI
  • redb for content-addressed persistence
  • An in-built MCP server so any MCP-aware host (Claude Desktop, Cursor, Zed) can drive Glass directly
  • rquickjs for scriptable plugins (planned)

License: GPL-3.0-only (inherited from smali).

Why?

We’ve all used IDA Pro — it’s the industry standard for reversing and has years of plugins behind it, but it’s slow, expensive, and dated. Glass is 100% Rust native with a GPU-accelerated UI for fluid interaction. It’s also 100% free and open source — please contribute.

Features

  • Buttery smooth 120fps GPU accelerated rendering
  • Lightning fast analysis: 1-2 seconds for most larger binaries compared with minutes on IDA Pro
  • AArch64 and ARMv7 (ARM mode + Thumb) disassembly — covers iOS arm64 / arm64e and both common Android ABIs.
  • Fully linked and annotated disassemblies with control flow lines, data literals in comments, clickable links to other functions. All coloured for easy visibility.
  • Control flow graphs showing basic blocks and clickable links to other functions
  • Full project search for symbols or string literals across DEX, code and data sections
  • Native binary layout overview with section data
  • Xref search of callers, references to data
  • Binary and instruction search across every native artifact in the bundle (so both arm64-v8a and armeabi-v7a copies of a library are searched in one query). Byte-pattern grammar with masking + gaps; typed-assembly grammar for AArch64 and ARMv7, with an ISA-aware autocomplete dropdown.
  • Annotate any line (code or data) with a colour and/or comment so you can easily find it again later.
  • In-place editing of instructions and data (double-click an item). Smali class editor + AArch64 / ARMv7 instruction editor; right-click any listing row to open a byte-level hex view at the same address as an escape hatch.
  • MCP server exposes every analysis verb as a tool for any MCP-aware host — Claude Desktop, Cursor, Zed.
  • Themes for Glass and also selectable background colours for each workspace.

Screenshots

A walk through the main views — click any thumbnail to see it full size.

AArch64 disassembly listing with arrow gutter, resolved string literals, clickable symbol references
Disassembly listing
colour-coded operands, control-flow arrows, resolved string literals inline
Control flow graph for a native function showing basic blocks, conditional and unconditional edges
Control flow graph
per-function CFG with dotted conditional edges and routed multi-rank lanes
DEX method call graph rooted at a smali method; hover-expandable callee nodes
DEX call graph
hover-to-expand callees, click to jump to the method's smali
Section-map overview of a native binary with coloured proportional bar and per-section detail
Section-map overview
proportional bar by section size, click to jump to listing / hex view

Scripting

Every analysis Glass does in the GUI is also exposed as a CLI verb that emits structured JSON. The same glass binary is the automation entry point — pick a subcommand and you get a one-shot, scriptable result, perfect for jq pipelines and CI.

# What classes ship in this APK?
glass classes ./app.apk --package com.example. --text

# Who calls glass::main, by address?
glass callers ./libfoo.so --artifact libfoo.so --symbol "glass::main"

# Every `onCreate` across DEX, machine-readable:
glass search ./app.apk onCreate | jq '.data.hits[] | select(.kind=="method")'

# All ObjC + Swift types in an iOS bundle (filter by kind if you like):
glass types ./app.ipa --kind swift-class --text

# Drill into one type — methods, ivars, properties for ObjC;
# fields + vtable for Swift:
glass type ./app.ipa --artifact app --name blackjack.ContentView

Pass --text for a human-readable rendering, omit it for JSON.

Full reference: docs/cli-api.md.

This means you can script and automate common operations.

Skills and MCP

Every CLI verb is also exposed as a tool through an inbuilt MCP (Model Context Protocol) server, so any MCP-aware host — Claude Desktop, Cursor, Zed, your own client — can drive Glass directly to help with reversing tasks.

# Print the machine-readable skill catalog (one JSON object listing
# every verb with its schema and an example invocation).
glass skills

# Run as an MCP stdio server. Plug into any MCP host's tool list.
glass mcp

To register with Claude Desktop, add Glass to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "glass": { "command": "/usr/local/bin/glass", "args": ["mcp"] }
  }
}

The model can then call inspect, symbols, disasm, cfg-of, dex-callers, search and every other verb on any bundle you point it at. Tool results come back as the same JSON envelope you'd get from the CLI.

Searching

Three complementary engines, all available from the same ⌘F palette in the GUI and as CLI / MCP verbs.

Full text search

Bundle-wide fuzzy match across native symbols, DEX classes / methods / fields, and string literals in code and data sections. Live-filtered as you type; results dispatch to the right view (listing for native addresses, smali viewer for DEX targets, hex view for data hits). Indices build on a background thread after load — a progress chip shows while in flight.

glass search ./app.apk onCreate                 # all things named like "onCreate"
glass search ./libfoo.so init --limit 20

CLI reference: search verb in docs/cli-api.md.

Binary search

Byte-level pattern engine. Each atom is a 2-character hex mask (c0, e?, ?f, ??) or a gap (* = 0..=32 bytes, *(min..max) for explicit bounds). Matches don't span sections. In the GUI palette, ⌘2 switches to Binary mode; the Code only checkbox (default on) restricts the scan to text sections so you aren't drowning in data hits when looking for an instruction shape.

# returning-true stub finder — `mov w0, #1 ; ret`
glass bin-search ./libfoo.so --artifact libfoo.so --pattern '20 00 80 52 c0 03 5f d6'

# any ADRP+ADD pair with no intervening bytes
glass bin-search ./libfoo.so --artifact libfoo.so --pattern '?? ?? ?? 9? ?? ?? 4? 91'

# raw data: find embedded magic
glass bin-search ./libfoo.so --artifact libfoo.so --pattern 'de ad be ef'

Full grammar + worked examples: docs/BinSearch.md.

Instruction search

Write the assembly, Glass compiles it to bytes. A ;-separated sequence is encoded via armv8-encodeAArch64 (mov w0, #1, adrp x1, *) and ARMv7 in both modes (Thumb mov r1, r7 / bxeq lr / push {r4-r7, lr} and A32). Any wildcards are translated to operand-bit masks before the byte engine takes over. The scan is global — every native artifact in the bundle gets the right ISA's atoms (Android apps with both arm64-v8a and armeabi-v7a libraries are searched in a single query).

Inside Binary mode in the GUI, ⌘B toggles between Bytes and Asm grammars; an ISA-aware autocomplete dropdown shows variants that still match what you've typed — r1 filters out AArch64 candidates, w0 filters out ARMv7 ones.

Wildcards:

Token Meaning
* any operand (kind inferred from the chosen opcode)
#* any immediate (hints the opcode picker)
x, w any AArch64 X- or W-class register
r any ARMv7 GPR (r0..r15, sp, lr, pc)
<*>, <X>, <W>, <R>, <imm> bracketed equivalents, useful nested in other syntax ([x, #*], [r, #*])
# AArch64 — every `mov w0, #N` (any N)
glass insn-search ./libfoo.so --artifact libfoo.so --pattern 'mov w0, #*'

# AArch64 — any ADRP into x1 followed immediately by ADD into the same reg
glass insn-search ./libfoo.so --artifact libfoo.so --pattern 'adrp x1, * ; add x1, x1, #*'

# ARMv7 (Thumb) — `mov r1, r*` followed by a return
glass insn-search ./libfoo.so --artifact libfoo.so --pattern 'mov r1, r* ; bx lr'

# ARMv7 (any cond) — conditional bx in literal-pool callers
glass insn-search ./libfoo.so --artifact libfoo.so --pattern 'bxeq lr'

# every `ret x30` — concrete, no wildcards
glass insn-search ./libfoo.so --artifact libfoo.so --pattern 'ret'

The response carries bytes_hex showing the compiled mask (e.g. 01/1f ?? ?? 90/9f for adrp x1, *) so you can see exactly which bits are pinned vs wildcarded. Captures (<name:kind> cross-referencing the same operand later in the pattern) are designed but not yet implemented.

Full design + phasing: docs/InsnPattern.md. CLI/MCP reference: insn-search in docs/cli-api.md.

Current Status

Glass is usable today for reversing Android (APK / DEX / native .so) and iOS (IPA / Mach-O) apps targeting AArch64 and 32-bit ARMv7 (armeabi-v7a libraries, A32 + Thumb).

What works

File loading

  • Open Android bundles (.apk, .aab), iOS bundles (.ipa), or any standalone ELF / Mach-O binary (.so, .dylib, raw executables) directly — Glass auto-detects the format.
  • Fat / universal Mach-O is handled transparently: arm64e is preferred, plain arm64 is the fallback. Works on bundles and on standalone files alike (e.g. glass gui /usr/lib/dyld).
  • Loader pipeline reports progress (Reading archive → Parsing DEX / Disassembling native → Building symbols).
  • Per-artifact content-addressed IDs (blake3, rayon-parallel for large libs). Annotations follow the artifact, not the container — the same libfoo.so shipped in two APKs (or the same libswiftCore.dylib across two IPAs) shares analysis state.
  • AndroidManifest viewer (binary XML decoded via smali).
  • Info.plist viewer for iOS bundles — bundle id, executable name, version, min OS, and the rest of the plist rendered as colour-coded XML.

iOS — IPA / Mach-O

  • Unzip the IPA, locate Payload/*.app/, parse Info.plist, and pick the arm64 / arm64e slice from any fat binary inside.
  • Main executable and every Frameworks/*.framework + *.dylib is loaded as its own native artifact, with the same Overview + per-section disassembly views used for Android .so files.
  • Objective-C class browser sourced from __objc_classlist — classes, categories, methods, ivars, properties — with demangled names (legacy _TtC... Swift mangling included) and clickable jumps from method addresses into the listing.
  • Swift type browser sourced from __swift5_types — classes, structs, enums with their fields and (for classes) vtables, also clickable into the listing.
  • Symbol map enriched with ObjC method symbols and Swift type symbols, so listing rows that previously fell back to raw addresses now show resolved names.

Android — APK / DEX / native

  • Class tree across all DEX files in the APK.
  • Smali listing per class with syntax-aware tokenization (directives, types, method names, string literals, etc.).
  • Method cross-references resolve to the right class + line.
  • Native .so files under lib/<abi>/ loaded per ABI; AArch64 (arm64-v8a) and ARMv7 (armeabi-v7a) both get full disassembly views. Other ABIs (x86 / x86_64) route to the hex view until a decoder lands.

Editing

  • Smali class editor (double-click a class header / field / method to open inline editors).
  • AArch64 in-place instruction editing: type new assembly, Glass encodes it back to bytes; staged changes show as a green tint in the listing until you Export to a new APK / IPA.
  • ARMv7 in-place editing: handles same-width swaps, 4-byte → 2-byte shrinks (auto-pads with a Thumb-1 NOP), and 2-byte → 4-byte grows that consume a following NOP. Refuses unsafe grows that would shift downstream code.
  • ISA-aware autocomplete in the inline editor — typing r1 shows ARMv7 variants only; w0 shows AArch64 only.
  • Right-click any listing row → Open hex view here to drop into a byte-level hex editor at the same address when the typed-assembly editor can't express what you need.

AArch64 native (ELF + thin Mach-O)

  • Linear-sweep disassembly with virtualized rendering — large libraries open in seconds, not minutes.
  • Symbol map merged from ELF symtab, dynsym, DWARF, .eh_frame FDEs, and synthesized <name>@plt entries. C++/Rust/Swift demangling via symbolic-demangle.
  • Branch operands rendered as clickable symbol references; adrp + add/ldr pairs resolved to data targets, including string literals shown inline as comments.
  • Per-section views (code sections get disassembly; data sections get a hex view).

ARMv7 native (ELF)

  • Recursive-descent disassembly from symbol entry points so literal pools, jump tables and inline data don't get mis-decoded as instructions. Per-symbol mode (ARM vs Thumb) honoured via the low-bit marker.
  • Variable-width Thumb rendering: 16-bit Thumb-1 rows show 2 bytes (no phantom 00 00 padding), 32-bit Thumb-2 and A32 show 4.
  • Symbol map: ELF symtab, DWARF, .eh_frame, and synthesized <name>@plt entries (12-byte stubs).
  • movw + movt fusion: movw R, #lo16 ; movt R, #hi16 is detected across instruction pairs and the resolved 32-bit constant gets a ; "..." rodata-string comment on the movt row.
  • Thumb ldr Rt, [pc, #imm] literal-pool loads dereference one level into rodata for the same kind of inline string comment AArch64's ADRP+ADD path produces.
  • Control-flow arrow gutter on conditional and unconditional branches (same lane assignment as AArch64).

UI

  • Tabbed right pane with overflow-safe dropdown, close buttons, click-to-activate.
  • Horizontal + vertical scrollbars on listing, hex, and manifest views.
  • Cmd-F symbol palette with fuzzy filter. Multi-token queries are AND-matched in order (change me finds changeMessage and change_me_count but not dispatchMenuVisibilityChanged).
  • Binary / instruction palette (⌘2 to switch into it) scans every native artifact globally — Android apps with arm64-v8a + armeabi-v7a get unified results with the artifact + section labelled per match.
  • Right-click cross-references in every view: References to address / Callers of function / Open hex view here in the listing, hex and CFG; Callers of method / References to field in smali. Results show in the palette with a scope chip; Esc clears the scope back to bundle-wide search. Indices build on a background thread after load — a progress chip shows while in flight.
  • Themes (View → Theme) with selectable per-window background tints.
  • Cmd-O open, Cmd-N new window, Cmd-W close window, Cmd-⇧W close file (return window to launched-empty state) — on Linux / Windows the same shortcuts use Ctrl instead of Cmd. File → Open Recent (last 10 bundles, deduplicated by path) and View → Theme. On macOS these live in the native menu bar; on Linux / Windows (where gpui draws no native menu) Glass renders its own Glass / File / View menu bar in the window header.
  • Window bounds + open tabs + tree expansion state persisted per-bundle in redb; relaunching reopens where you left off.

What's missing

  • x86 / x86_64 disassembly (those code sections currently route to the hex view).
  • ARMv7 in-place edits that need to grow without an adjacent NOP — refused with a clear error today; would need section-level relayout + branch-target rebinding to support.
  • iOS entitlements and embedded.mobileprovision parsing.
  • Cross-references DEX ↔ native via JNI signatures.
  • QuickJS scripting host.
  • Drag-to-scroll on scrollbars (currently visual-only — use trackpad / wheel).
  • Resource ID decoding in the manifest (would need resources.arsc parsing).
  • ARMv7 typed-assembly editor: works for the common forms; shifted operands (r0, lsl #2) and pre/post-index memory ([rN, #imm]!, [rN], #imm) parse but only concretely — no wildcards inside brackets.

Building

Glass runs on macOS 13+ (the primary target, GPU-accelerated via Metal — no extra SDK needed, the Metal framework ships with the OS), Linux (X11 or Wayland via gpui_linux, Vulkan-backed), and Windows 10/11 (Direct3D-backed via gpui, built with the MSVC toolchain).

There is a release prebuilt binary for macOS under Releases but if you need to build from source: the good news: it's two commands.

  1. Install Rust (if you don't already have it):

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  2. Linux only — install gpui's native dependencies. The easiest way is to run Zed's setup script, which knows about apt / dnf / pacman / etc:

    curl -sSL https://raw.githubusercontent.com/zed-industries/zed/main/script/linux | bash

    This pulls in libxkbcommon-dev, the Wayland and XCB headers, Vulkan, ALSA, and the rest of the toolchain gpui_linux needs to link. Without these the build fails at link time with missing xkbcommon / wayland-client symbols.

    If you'd rather not run the script, the equivalent packages on Debian / Ubuntu (amd64) are:

    sudo apt-get update && sudo apt-get install -y \
      build-essential clang cmake pkg-config \
      libfontconfig-dev libfreetype-dev \
      libwayland-dev libxkbcommon-x11-dev \
      libasound2-dev libvulkan-dev \
      libzstd-dev libsqlite3-dev libssl-dev \
      libglib2.0-dev

    The build fails early in a dependency build script (fontconfig was not found in the pkg-config search path) if libfontconfig-dev is missing, and later at link time for the X11/Wayland/Vulkan libraries. libglib2.0-dev is needed because the Frida driver links GLib dynamically on Linux (on macOS the Frida devkit bundles it statically) — without it the link fails with undefined symbol: g_object_unref.

    Windows only — install the native build toolchain. gpui requires the MSVC toolchain (the GNU/MinGW target is not supported). Using winget:

    # 1. MSVC compiler, linker, and Windows SDK (the "Desktop development with C++" workload).
    winget install --id Microsoft.VisualStudio.2022.BuildTools `
      --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
    
    # 2. CMake — tree-sitter (via the Zed `language` crates) builds wasmtime's C API with it.
    winget install --id Kitware.CMake
    
    # 3. LLVM/Clang — `bindgen` (frida-sys, gpui, media) needs libclang.dll.
    winget install --id LLVM.LLVM

    The LLVM installer does not add itself to PATH, so point bindgen at libclang.dll before building (set it permanently via System → Environment Variables, or per-shell):

    $env:LIBCLANG_PATH = "C:\Program Files\LLVM\bin"

    Without these the build fails in dependency build scripts: linker 'link.exe' not found (no MSVC), failed to spawn 'cmake' (no CMake), or Unable to find libclang (no LIBCLANG_PATH). The glass binary's stack reserve is bumped automatically on MSVC (see crates/glass-cli/build.rs) so the CLI doesn't overflow Windows' small default main-thread stack — no action needed.

  3. Clone and build:

    git clone https://github.com/azw413/Glass.git
    cd glass
    cargo build --release -p glass-cli
    cp target/release/glass <to somewhere on your PATH>

    The first build will compile gpui and friends and will take several minutes. Subsequent builds are fast.

  4. Run it:

    # Open the GUI on an Android APK or iOS IPA — no subcommand needed.
    glass ~/path/to/app.apk
    glass ~/path/to/app.ipa
    
    # Or on a standalone binary — ELF .so, Mach-O .dylib, or raw
    # executable. Fat / universal Mach-O is sliced automatically.
    glass ~/path/to/libfoo.so
    glass ~/path/to/libBar.dylib
    glass /usr/lib/dyld
    
    # No args → opens an empty Glass window; use File → Open.
    glass
    
    # Headless bundle inspect
    glass bundle ~/path/to/app.apk
    
    # Inspect persisted state for a bundle
    glass db-dump ~/path/to/app.apk

Always use the release build — debug builds disassemble orders of magnitude slower.

Packaging a .app bundle

To wrap the release binary in a Glass.app bundle for double-click launch from Finder:

cargo build --release -p glass-cli
./packaging/make-app.sh
open dist/Glass.app

The bundle is ad-hoc signed (not Developer-ID signed / notarized), so on first launch macOS will refuse to open it; right-click → Open to bypass Gatekeeper once.

Two ways to grab a prebuilt zip without building locally:

  • Latest main — every push uploads a Glass-app-<sha>.zip as a 14-day workflow artifact. Pull it from the Actions tab.
  • Tagged release — pushing a v* tag (e.g. v0.1.0) triggers the same workflow and additionally publishes a Glass-<tag>-macOS.zip to the Releases page with auto-generated release notes.

Workspace

Crate Purpose
glass-core Shared types (CodeKind, IDs)
glass-arch-arm AArch64 + ARMv7 disassembly, symbol map, PLT synthesis, demangling
glass-arch-dex DEX / smali facade over smali
glass-mobile APK + IPA bundle loading, native-lib extraction, manifest
glass-db Content-addressed persistence (redb): bundles, tabs, settings
glass-device Android (adb) + iOS (usbmux) device discovery
glass-api Analysis verbs (search, xrefs, CFG, edits) shared by CLI + MCP + GUI
glass-ui gpui front-end: tree, listing, hex, manifest, palette
glass-cli Headless inspector + GUI launcher
glass-mcp MCP server exposing every CLI verb as a tool
glass-script QuickJS plugin runtime (placeholder)

Roadmap

  • iOS deeper — Entitlements and embedded.mobileprovision parsing. (ObjC __objc_classlist and the Swift __swift5_types metadata pass have landed — see glass types / glass type.)
  • x86 / x86_64 — Disassembly for emulator-builds of Android .so files.
  • Internal Scripting — QuickJS plugin host with a stable API for analysis passes.
  • Advanced — Signed APK rebuilding, downstream-shift on ARMv7 in-place edits (so 2→4-byte grows can splice past adjacent code instead of refusing).

About

Glass - a fast and free IDA Pro alternative

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors