Skip to content
Security
Skill

/analyzing-ios-binaries

Analyze iOS applications at the binary level — decrypting FairPlay-protected IPAs with frida-ios-dump or bagbak, inspecting Mach-O load commands, recovering Objective-C headers with class-dump, and reading Swift metadata. Use when working with an IPA or .app bundle, when a

BOOST
From plugin
secskills
17094 skills
Install
$ npx -y skills add trilwu/secskills --skill analyzing-ios-binaries --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/analyzing-ios-binaries

Context preview

The summary Claude sees to decide when to auto-load this skill.

Analyze iOS applications at the binary level — decrypting FairPlay-protected IPAs with frida-ios-dump or bagbak, inspecting Mach-O load commands, recovering Objective-C headers with class-dump, and reading Swift metadata. Use when working with an IPA or .app bundle, when a

SKILL.md

analyzing-ios-binaries.SKILL.md
name: analyzing-ios-binaries
description: Analyze iOS applications at the binary level — decrypting FairPlay-protected IPAs with frida-ios-dump or bagbak, inspecting Mach-O load commands, recovering Objective-C headers with class-dump, and reading Swift metadata. Use when working with an IPA or .app bundle, when a downloaded App Store binary shows cryptid=1, when class-dump returns nothing, or when analyzing iOS frameworks and app extensions.
verified: 2026-07-27

Analyzing iOS Binaries

App Store binaries are encrypted at rest and decrypted by the kernel at load time, so every static tool fails on a downloaded IPA until you dump the decrypted image from memory. That single step gates everything else, and it is the reason most iOS analysis stalls before it starts.

When to Use

  • You have an IPA or `.app` bundle and need to read the binary
  • `class-dump` returns nothing or garbage
  • `otool` shows `cryptid 1`
  • You need to enumerate Objective-C classes, Swift types, or exported symbols
  • Analyzing embedded frameworks, app extensions, or dynamic libraries

When NOT to Use

  • **Android targets** — use `testing-mobile-applications` or the relevant

`reversing-*` skill

  • **The wider iOS assessment** (storage, keychain, IPC) — use

`testing-mobile-applications`

  • **TLS interception** — use `bypassing-mobile-pinning`
  • **Jailbreak detection blocking your tooling** — use

`bypassing-root-jailbreak-detection` first

  • **Cross-platform frameworks** — Flutter, Unity, and Xamarin have their own

skills; use them for the managed layer and this one for the native shell

Check Encryption First

otool -l TargetApp | grep -A5 LC_ENCRYPTION_INFO
# cryptid 1  → FairPlay-encrypted, decrypt before anything else
# cryptid 0  → already decrypted (dev build, or you already dumped it)

Everything downstream is meaningless on an encrypted binary. `class-dump` returning nothing is almost always this, not obfuscation.

# Decrypt on a jailbroken device by dumping the loaded image
frida-ios-dump -l                 # list installed apps
frida-ios-dump com.target.app     # produces a decrypted IPA
bagbak com.target.app             # alternative, handles extensions/frameworks well

# Rootless jailbreaks and TrollStore installs work with the same tools
# Older devices: Clutch, flexdecrypt

Dump **frameworks and extensions too**, not just the main binary. `PlugIns/` (share sheets, widgets, keyboards) and `Frameworks/` carry their own encrypted Mach-Os, and app extensions frequently hold the interesting entitlements and a weaker security posture than the main app.

Mach-O Structure and Protections

file TargetApp                       # thin or fat/universal
lipo -info TargetApp                 # architectures present
lipo -thin arm64 TargetApp -o app64  # extract one before analysis

otool -hv app64                      # header flags: PIE
otool -l app64 | rg 'LC_LOAD_DYLIB|LC_RPATH|LC_CODE_SIGNATURE|LC_ENCRYPTION'
otool -Iv app64 | head               # indirect symbols
nm -m app64 | rg -v ' U ' | head     # defined symbols

# Protections at a glance
otool -hv app64 | rg PIE             # ASLR
otool -Iv app64 | rg stack_chk       # stack canaries
otool -Iv app64 | rg objc_release    # ARC in use

Extract the entitlements — they define what the app is allowed to do and often reveal the interesting attack surface:

codesign -d --entitlements :- TargetApp.app
# Look for: keychain-access-groups, App Groups, associated-domains,
# get-task-allow (debuggable!), custom URL scheme claims

`get-task-allow` set to true on a production build means the app is debuggable and is a finding on its own.

Objective-C

Objective-C keeps its full class metadata in the binary, so recovery is excellent — method names, selectors, class hierarchy, ivars.

class-dump -H app64 -o ./headers        # classic
class-dump-dyld                          # for dyld shared cache resident classes
dsdump --objc --color app64              # modern alternative, handles Swift too

# Then read the type map
rg -l 'Manager|Service|API|Auth|Crypto|Keychain|Payment' ./headers | head -20

In a disassembler, Objective-C calls go through `objc_msgSend`, so the callee is a selector string in a register rather than a direct branch. Both IDA and Ghidra have plugins that resolve this; without them the call graph is largely useless.

Swift

Swift is harder. Names are mangled, and method dispatch is often static or through witness tables rather than `objc_msgSend`.

# Demangle what you find
nm app64 | swift demangle
xcrun swift-demangle '$s10TargetApp11AuthManagerC5loginyyF'

# Swift type metadata lives in dedicated sections
otool -l app64 | rg '__swift5_types|__swift5_proto|__swift5_reflstr'
dsdump --swift app64

Practical approach for Swift-heavy apps: `@objc` and `@objcMembers` members still appear in the Objective-C metadata, so class-dump gives you a partial map. For the rest, work from string references and the reflection sections rather than trying to recover a full class list. Runtime enumeration with Frida is usually faster than static recovery:

frida -U -f com.target.app -l enumerate-swift-classes.js

Runtime Analysis

# Enumerate everything the runtime knows
objection -g com.target.app explore
#   ios hooking list classes
#   ios hooking search methods <keyword>
#   ios hooking watch method "-[AuthManager login:]" --dump-args --dump-return

# Direct Frida for anything objection does not cover
frida -U -f com.target.app -l hooks.js

Runtime beats static on iOS more often than on other platforms: the Objective-C runtime is introspectable, so listing classes and watching methods gets you to the logic faster than reading a disassembly of `objc_msgSend` dispatch.

What to Look For

  • **Entitlements over-provisioned** — App Groups shared with less-trusted

extensions, keychain groups shared too widely, `get-task-allow` in production

  • **H
Read more
Ships withsecskills

**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

Get the whole plugin

Other skills on secskills.