Reverse Engineering

forge analysis: class-dump, strings, symbols, security posture, and version diffing for any decrypted IPA.

General-purpose, read-only static analysis of any .ipa — not tied to a specific patch set or app. Built on the same Mach-O/ObjC analysis engine (ipa_forge/machO/objc.py) that forge hooks uses to verify hook targets; see Architecture for how the two relate. Every command accepts --app-dir <Payload/App.app> in place of --ipa to skip re-extraction while iterating, same as forge hooks.

Scope boundary

Two things are deliberately not implemented, by design rather than oversight:

  • FairPlay/App Store DRM decryption. Every command here assumes an already-decrypted .ipa, exactly like the rest of ipa-forge.
  • Instruction-level disassembly/decompilation. Static metadata (classes, strings, symbols) only — no capstone/Ghidra-style disassembly.

forge analysis classdump

Dumps the app's Objective-C runtime metadata as .h-style class-dump text: every class (superclass, protocol conformance, ivars, properties, full method signatures reconstructed from type encodings), protocol declarations, and categories.

Prop

Type

forge analysis classdump --ipa App.ipa
forge analysis classdump --ipa App.ipa --class MainPlayerViewController
forge analysis classdump --ipa App.ipa --search '^App' --output dump.h

--class/--search restrict output to matching classes only (protocols and categories are omitted in that case, matching forge hooks extract's --class/--search). A class/superclass defined in another image (system frameworks, or a framework you didn't point the tool at) is reported as «external» — the same honest-reporting convention forge hooks uses, rather than guessing.

The type-encoding decoder (ipa_forge/analysis/type_encoding.py) is best-effort: structs/unions render as just their tag name (no field expansion), and truly exotic encodings fall back to the raw string. Good enough to read; not good enough to regenerate a compilable header.

forge analysis strings

Printable-ASCII string extraction across every executable in the bundle (main + frameworks + dylibs + extensions), tagged with which binary each string came from.

Prop

Type

forge analysis strings --ipa App.ipa --min-len 6
forge analysis strings --ipa App.ipa --search 'https?://' --binary MainExecutable

Pipe to grep for anything --search doesn't cover directly — no output cap (unlike the GUI's /analysis page, which caps at 2000 matches for browser sanity).

forge analysis symbols

Linked libraries and imported/exported symbols for one executable in the bundle (otool -L + nm, backed by LIEF's structured symbol table instead of parsing text).

Prop

Type

forge analysis symbols --ipa App.ipa
forge analysis symbols --ipa App.ipa --binary SomeFramework

forge analysis security

Read-only build/security posture for one executable: PIE, an encryption-flag check (LC_ENCRYPTION_INFO's cryptiddetection only, never decryption), stack protector, an ARC heuristic (_objc_storeStrong/_objc_release imported — not definitive), min-OS, and platform.

Prop

Type

forge analysis security --ipa App.ipa

forge analysis diff

Survey of what changed between two builds of the same app: classes and protocols added/removed, per-class method churn, and Info.plist key changes. Purely informational — exit code is always 0 regardless of findings.

Prop

Type

forge analysis diff --old App_1.0.ipa --new App_2.0.ipa

forge analysis diff vs. forge hooks diff

This is broader but shallower than forge hooks diff (see Usage): forge hooks diff only re-checks one patch definition's declared hook targets and is a pass/fail gate (exit 1 on a required-hook regression); forge analysis diff surveys everything that changed, independent of any patch set, and never fails the exit code. Use forge hooks diff to gate a patch set's CI; use forge analysis diff to understand what changed before writing the patch set in the first place.

Entitlements are intentionally not diffed here: reading them requires shelling out to codesign/security, and signing/backend.py is the only module allowed to do that (Architecture's hard constraint) — a real entitlements diff belongs in that subsystem, not in this read-only, signing-independent package.

The web GUI (forge gui/analysis)

The same four views (class-dump, strings, security, diff), browsable without installing the CLI: forge gui → open the link in the main patcher page's subtitle, or navigate directly to http://127.0.0.1:8765/analysis. Unlike the main patcher page, /analysis needs no patch-set setup and works on any IPA — upload it and pick an action. Strings output is capped at 2000 matches in the browser (the CLI has no such cap). Single-user, local-only, same as the patch-flow page — see Usage.

On this page