iOS App Analysis

iOS App Analysis

Static and dynamic analysis of iOS applications, working with IPA files, decrypting App Store binaries, inspecting the sandbox, and tooling around the iOS keychain.

May 13, 2026
Updated Apr 8, 2026
2 min read

Getting the IPA

Three sources, in order of how often I use them:

  1. The client provides a debug or ad-hoc IPA, easiest case
  2. Pull a decrypted IPA off a jailbroken device with frida-ios-dump or bagbak
  3. Sideload an IPA from IPA Library or similar archive sites for research

App Store binaries are encrypted with FairPlay. You cannot reverse the binary directly, you need to dump a decrypted copy from a running process.

# frida-ios-dump (works on most jailbreaks)
git clone https://github.com/AloneMonkey/frida-ios-dump
cd frida-ios-dump
pip install -r requirements.txt

# SSH must be configured to the device
./dump.py com.target.app
# Outputs target.ipa

What's Inside an IPA

unzip target.ipa -d target/
# target/Payload/Target.app/
#   Target              <- the Mach-O binary
#   Info.plist
#   embedded.mobileprovision
#   _CodeSignature/
#   en.lproj/
#   ... assets, frameworks, plugins

The interesting bits:

  • Target, the Mach-O binary, what you actually disassemble
  • Info.plist, app metadata, permissions, URL schemes, ATS settings
  • embedded.mobileprovision, entitlements and provisioning info
  • Frameworks/, third-party libraries

First Pass: Info.plist

# Convert binary plist to XML
plutil -convert xml1 target/Payload/Target.app/Info.plist -o /tmp/info.xml
cat /tmp/info.xml

What I look for:

  1. NSAppTransportSecurity, look for NSAllowsArbitraryLoads, cleartext exceptions
  2. CFBundleURLTypes, registered URL schemes (deep link surface)
  3. UIFileSharingEnabled, exposes the Documents directory over iTunes
  4. NSCameraUsageDescription, NSLocationUsageDescription, etc., maps the privacy surface
  5. LSApplicationQueriesSchemes, schemes the app probes for, often hints at what it talks to

Entitlements

codesign -d --entitlements :- target/Payload/Target.app/Target

Look for:

  • keychain-access-groups, shared keychain access
  • com.apple.security.application-groups, shared containers
  • aps-environment, push environment
  • get-task-allow, debuggable build

get-task-allow set to true on a production build is a finding worth raising, it means the binary is debuggable.

Static Analysis

Hopper, Ghidra, IDA

For full disassembly. Hopper is the cheapest of the three and works well on iOS. Ghidra is free and good. IDA is the gold standard if you can afford it.

What I look at first in the disassembly:

  • Methods on classes named *Login*, *Auth*, *Token*, *Crypto*
  • String references to API endpoints
  • Calls to SecItemAdd, SecItemCopyMatching (keychain operations)
  • Calls to NSURLSession and URLSessionDelegate methods (TLS pinning)
  • NSUserDefaults reads and writes
  • Anti-debug calls, ptrace, sysctl, task_get_exception_ports

class-dump

class-dump -H target/Payload/Target.app/Target -o headers/
ls headers/

Gives you Objective-C class headers. Useless for Swift binaries (Swift symbols are mangled), useful for ObjC.

Strings

strings -a target/Payload/Target.app/Target | grep -i "api\|key\|secret\|http"

The bar for finding API URLs and hardcoded secrets is very low.

Dynamic Analysis

Connect to the device

# After installing OpenSSH from Cydia/Sileo
ssh root@<device-ip>
# Password: alpine (CHANGE IT IMMEDIATELY)

Inspect the sandbox

The app's container is at /var/mobile/Containers/Data/Application/<UUID>/. Finding the right UUID is annoying, so use a tool:

# On the jailbroken device
which find-app  # objection or similar

# Or with Objection from your laptop
objection -g com.target.app explore
> env
# Documents:    /var/mobile/Containers/Data/Application/<UUID>/Documents
# Library:      ...
# tmp:          ...

Inspect the keychain

The keychain is per-app (or per access group). Dump everything the app can see:

objection -g com.target.app explore
> ios keychain dump
> ios keychain dump --json /tmp/keychain.json

NSUserDefaults

> ios nsuserdefaults get

Apps love to stash auth state and feature flags here. Sometimes including refresh tokens.

Cookies

> ios cookies get

Watch a method

> ios hooking watch method "-[LoginViewController checkPinIsValid:]" --dump-args --dump-return --dump-backtrace

Console.app and idevicesyslog

Stream the device's system log. Apps log far more than they should.

# From macOS, with libimobiledevice installed
idevicesyslog | grep -i target

Common Findings

FindingWhere I find it
Hardcoded API keysstrings, Hopper string view
get-task-allow=true in productioncodesign -d --entitlements :-
Cleartext exceptions in ATSInfo.plist, NSAppTransportSecurity
Tokens in NSUserDefaultsObjection, ios nsuserdefaults get
Unprotected keychain itemsios keychain dump
Deep link bypassesURL schemes in Info.plist, then test handlers
UIWebView (deprecated, vulnerable)class-dump for UIWebView references
Logging tokens to system logidevicesyslog, Console.app

Bypassing Detections

iOS apps frequently check for:

  • Jailbreak (cydia URL scheme, /Applications/Cydia.app, write tests, suspicious dylib loads)
  • Debugger (ptrace, sysctl, exception ports)
  • Hooking (Frida loaded modules, frida-server presence)

For the lazy implementations, Objection's ios jailbreak disable handles the common patterns. For custom checks, write a Frida hook against the specific function. Use frida-trace to find what gets called early in the app lifecycle.

Last updated on