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:
smalifor APK / DEX / smali handlingarmv8-encodefor AArch64 and ARMv7 (A32 / Thumb) — native.so, iOS Mach-Ogpui(Zed) for GPU-accelerated native UIredbfor content-addressed persistence- An in-built MCP server so any MCP-aware host (Claude Desktop, Cursor, Zed) can drive Glass directly
rquickjsfor scriptable plugins (planned)
License: GPL-3.0-only (inherited from smali).
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.
- 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-v8aandarmeabi-v7acopies 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.
A walk through the main views — click any thumbnail to see it full size.
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.ContentViewPass --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.
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 mcpTo 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.
Three complementary engines, all available from the same ⌘F palette in the GUI and as CLI / MCP verbs.
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 20CLI reference: search verb in docs/cli-api.md.
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.
Write the assembly, Glass compiles it to bytes. A ;-separated sequence is encoded via armv8-encode — AArch64 (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.
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).
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:
arm64eis preferred, plainarm64is 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.soshipped in two APKs (or the samelibswiftCore.dylibacross 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/, parseInfo.plist, and pick the arm64 / arm64e slice from any fat binary inside. - Main executable and every
Frameworks/*.framework+*.dylibis loaded as its own native artifact, with the same Overview + per-section disassembly views used for Android.sofiles. - 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
.sofiles underlib/<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
r1shows ARMv7 variants only;w0shows 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_frameFDEs, and synthesized<name>@pltentries. C++/Rust/Swift demangling viasymbolic-demangle. - Branch operands rendered as clickable symbol references;
adrp+add/ldrpairs 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 00padding), 32-bit Thumb-2 and A32 show 4. - Symbol map: ELF symtab, DWARF,
.eh_frame, and synthesized<name>@pltentries (12-byte stubs). movw + movtfusion:movw R, #lo16 ; movt R, #hi16is detected across instruction pairs and the resolved 32-bit constant gets a; "..."rodata-string comment on themovtrow.- 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 mefindschangeMessageandchange_me_countbut notdispatchMenuVisibilityChanged). - Binary / instruction palette (⌘2 to switch into it) scans every native artifact globally — Android apps with
arm64-v8a+armeabi-v7aget 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.
- 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.mobileprovisionparsing. - 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.arscparsing). - 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.
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.
-
Install Rust (if you don't already have it):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
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 | bashThis pulls in
libxkbcommon-dev, the Wayland and XCB headers, Vulkan, ALSA, and the rest of the toolchaingpui_linuxneeds to link. Without these the build fails at link time with missingxkbcommon/wayland-clientsymbols.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-devThe build fails early in a dependency build script (
fontconfig was not found in the pkg-config search path) iflibfontconfig-devis missing, and later at link time for the X11/Wayland/Vulkan libraries.libglib2.0-devis needed because the Frida driver links GLib dynamically on Linux (on macOS the Frida devkit bundles it statically) — without it the link fails withundefined symbol: g_object_unref.Windows only — install the native build toolchain.
gpuirequires 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 pointbindgenatlibclang.dllbefore 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), orUnable to find libclang(noLIBCLANG_PATH). Theglassbinary's stack reserve is bumped automatically on MSVC (seecrates/glass-cli/build.rs) so the CLI doesn't overflow Windows' small default main-thread stack — no action needed. -
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
gpuiand friends and will take several minutes. Subsequent builds are fast. -
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.
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.appThe 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 aGlass-app-<sha>.zipas 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 aGlass-<tag>-macOS.zipto the Releases page with auto-generated release notes.
| 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) |
- iOS deeper — Entitlements and
embedded.mobileprovisionparsing. (ObjC__objc_classlistand the Swift__swift5_typesmetadata pass have landed — seeglass types/glass type.) - x86 / x86_64 — Disassembly for emulator-builds of Android
.sofiles. - 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).