OPHANIM

Run an iOS app natively on macOS, then watch - or rewrite - what it does from the inside.

A runtime instrumentation and interception toolkit for iOS apps on Apple Silicon. It re-signs an .ipa, injects a runtime, hosts it as a Mac Catalyst process, and gives you a vantage point inside the target where plaintext, in-process state, and ObjC/Swift dispatch are all visible.

macOS 12+ · Apple Silicon SwiftUI front-end In-process runtime MCP scriptable GPLv3

// what it is

A dynamic-analysis lab for iOS apps, on your Mac

Ophanim is a macOS dynamic-analysis and security-testing tool. The analyst's UI and the target app are separate processes - so the only vantage point that sees decrypted traffic, in-process state, and ObjC/Swift dispatch is code running inside the target. Ophanim's core is an injected in-process agent, and everything flows from that.

Observe

Capture everything interesting an app does - with provenance and without crashing the host.

Intercept

Rewrite responses, block hosts, fake return values, defeat pinning and jailbreak checks - under a rule engine that is observe-by-default.

Script

Everything the GUI does is also available over an MCP server, so analysis can be driven programmatically.

// capabilities

What you can see and change

Every hook routes through a policy decision: observe by default, or - when a rule matches - block, replace the return/response, delay, or fault.

Network

HTTP(S) requests and decrypted response bodies, raw socket/DNS, Secure-Transport plaintext, and certificate-pinning bypass + logging.

Keychain & crypto

SecItem* access and CommonCrypto (CCCrypt / CCHmac) - observe keys, items, and crypto operations as they happen.

Device & privacy

Vendor/advertising IDs, location, pasteboard, App Attest / DeviceCheck, biometrics, and camera/mic/photos/contacts prompts - observe or fake.

Filesystem & process

File access and jailbreak-path probes, dlopen/fork/posix_spawn, and inter-app launches.

Custom hooks

Swizzle any ObjC (class, selector); patch overridable native-Swift methods at the vtable; or inline-hook arbitrary machine code by address, symbol, module+offset, or byte signature.

ƒ Rules & scripting

A static rule replaces the same thing every time; a JavaScriptCore rule body sees each call's context (URL, headers, body, fields) and can return a different result per call.

// the interface

Drop in an .ipa. Pick what to capture. Launch.

Ophanim's SwiftUI front-end carries a "hackery" terminal aesthetic - dark slate surfaces, phosphor-green accents, system monospace everywhere, with optional CRT theatrics. The interface elements below are rendered in that same theme.

App Library - Ophanim
TargetApp
Banking
SocialX
Wallet
GameCo
StreamR
DeliverX
VPN
The library is the whole window - drop an .ipa to re-sign, inject, and install.
Instrumentation - TargetApp
Enable hackingTurn the Ophanim engine on for this app
Enable inline hooksarm64 machine-code patch · OFF by default
Capture backtracesRecord the calling stack for ObjC events
Open log window on launch
CAPTURE CATEGORIES
network keychain crypto device privacy filesystem process jailbreak
Per-app instrumentation: master enable, injection method, categories, and sinks.
View log - be.ophanim · live
12:04:07networkNSURLSession.dataTask → POST api.target.app/v2/login 200 (1.2 KB)
12:04:07cryptoCCCrypt kCCEncrypt AES-256-CBC in=48 out=48
12:04:08keychainSecItemCopyMatching acct="auth.token" [returnReplaced]
12:04:08deviceidentifierForVendor → faked 00000000-DEAD-BEEF…
12:04:09jailbreakstat("/Applications/Cydia.app") [blocked] → ENOENT
12:04:09networkTLS pinning challenge api.target.app [bypassed + logged]
12:04:10processdlopen("/usr/lib/libobjc.A.dylib")
12:04:10networkSSL_read api.target.app ← {"session":"…","flags":3} (842 B)
12:04:11deviceCLLocationManager.requestLocation [faulted]
12:04:11cryptoCCHmac kCCHmacAlgSHA256 key=32 data=128
Captured events stream live - written as NDJSON, plain text, and/or os_log, and browsable here or over MCP.

// how it works

Three parts, one process boundary

Ophanim imports an .ipa, re-signs it, rewrites its Mach-O load commands to inject a runtime, converts it to Mac Catalyst, and runs it natively. From there the engine watches from inside.

Ophanim.app

The SwiftUI front-end. Imports/re-signs/injects .ipas, rewrites load commands, converts to Mac Catalyst, manages per-app instrumentation settings and the log viewer. Also exposes the MCP server.

Galgal.framework

The injected in-process runtime. Loads into the hosted app, provides the iPad-emulation/compatibility layer, and hosts the instrumentation engine in embedded mode.

OphanimCore

The shared instrumentation engine: hook modules, a lock-free capture ring, the rule/scripting engine, and the log sinks. Compiles into Galgal (embedded) and a standalone agent dylib (sibling).

Embedded mode (default)

The engine runs inside the Galgal runtime that's already in the app. Full capture, no extra re-sign.

Sibling mode

A standalone agent dylib is injected alongside the runtime via a second LC_LOAD_DYLIB (the app is re-signed). Use it when instrumentation should be independent of the runtime.

// coverage by mode

Capture coverage

The engine deliberately only interposes C symbols the runtime doesn't already own, so the two never collide - that's why keychain and raw C-level filesystem stay embedded-only.

CategoryEmbeddedSibling
Network (HTTP(S) bodies, socket/DNS, TLS plaintext, pinning bypass + log)
Process (dlopen/fork/posix_spawn, app/URL launches)
Device / Privacy (IDs, location, pasteboard, App Attest, biometrics, media prompts)
Crypto (CCCrypt / CCHmac)
Custom ObjC hooks (swizzle any class/selector)
Custom Swift hooks (native-Swift vtable patching)
Inline hooks (arm64 machine-code patch by address/symbol/offset/signature)
Rules engine + JavaScriptCore scripting + all sinks
Filesystem✔ full◑ NSFileManager
Keychain (SecItem*)
Jailbreak / root-detector bypass + loggingbypass only

// interception

Observe by default. Modify on purpose.

Instrumentation must never silently change behavior you didn't ask for. Active modification is available where it's safe to act before the call returns.

Can be actively modified

  • HTTP(S) responses - block / replace body + status + headers
  • Device & privacy values - fake vendor/ad IDs, pasteboard, canOpenURL
  • Inline-hooked functions - block / replace return / fault / delay
  • ObjC & Swift hooks - block / delay (void methods, no return to replace)

Observe-only (captured after return)

  • TLS read/write plaintext
  • Socket / DNS
  • Crypto & keychain
  • dlopen / fork / posix_spawn

These are captured through a lock-free ring on a drain thread - the original call has already returned by the time the event is processed.

Authorized use only. Ophanim is for analyzing software you own or are authorized to test (security research, app QA, CTF, reverse-engineering your own dependencies). Re-signing breaks server-side attestation by design, so it cannot be used to defeat licensing or impersonate a genuine device to a server.

// scripting

Drive it from an agent

Ophanim --mcp speaks the Model Context Protocol over stdio (or an HTTP port), exposing tools to list/launch apps, read & write per-app config, set rules and ObjC/Swift hooks, list and apply presets, enumerate jailbreak detectors, inspect a binary's import/symbol surface, and tail/query captured events.

# launch the MCP server over stdio
$ Ophanim --mcp

# then, from an MCP client / agent:
list_apps                     # find a bundle id
set_config  be.target.app     # enable categories + sinks
set_rules   be.target.app     # observe-by-default, block, replace…
launch_app  be.target.app
query_events --category network --disposition returnReplaced
MCP reference →