Module 1 — iOS Basics & App Anatomy

Welcome — this module builds a practical, deep foundation for iOS mobile pentesting. We’ll cover how iOS apps are structured, what to look for during initial analysis, and the core runtime & storage primitives you’ll encounter when moving to static and dynamic analysis. Everything here is safe, practical, and intended to prepare you for hands-on work in an authorized lab.

Learning objectives

By the end of this module you will be able to:

  • Explain core iOS architecture concepts relevant to security (sandboxing, entitlements, code signing).
  • Locate and inspect key files inside an .ipa / .app bundle and interpret their meaning.
  • Identify common artifacts: Info.plist entries, embedded provisioning profiles, entitlements, and URL schemes.
  • Understand Mach-O binary basics and the high-level differences between Objective-C and Swift artifacts.
  • Locate where apps store sensitive data (UserDefaults, files, databases, Keychain) and the implications for security testing.
  • Prepare a checklist of the first static checks to run on any iOS app during reconnaissance.

Prerequisites

  • macOS host with Xcode command line tools installed (or a Linux host with relevant tools for some steps).
  • Basic knowledge of macOS terminal, file system, and basic programming concepts (functions, classes).
  • Access to an app binary for which you have written authorization (IPA or extracted .app directory).
  • Recommended: an isolated lab network and a disposable device or simulator for testing.

Tooling (recommended)

You don’t need all of these at once — pick what fits your workflow. Tools are grouped by purpose.

Inspection & static analysis

  • unzip, tar (extract IPA)
  • plutil (plist inspection)
  • codesign (verify signatures)
  • security (Certificate / provisioning profile inspection)
  • otool, nm, strings, ldid (binary inspection)
  • class-dump, class-dump-swift (Objective-C headers reconstruction)
  • hopper, ghidra, ida, binary-ninja (disassembly / decompilation)
  • mobSF (Mobile Security Framework) — automated static scanning

Runtime & dynamic basics (later modules)

  • frida, objection, lldb, cycript (for dynamic/runtime)

Storage inspection

  • sqlite3 (DB analysis)
  • plutil / defaults (plist and user defaults)
  • KeychainDump tools (only in authorized lab environment / jailbroken devices)

Misc

  • jq (JSON formatting), openssl (cert checks), curl (API testing)

High-level iOS architecture (security-relevant)

Sandboxing

  • Every iOS app runs inside a sandbox: a filesystem namespace and entitlements-limited environment.
  • Sandbox prevents arbitrary access to other apps’ data and many system resources.
  • Security implication: Misconfigured entitlements or shared app groups can create cross-app risks.

Code signing & provisioning

  • Apple requires binaries to be signed. The code signature binds executable code with certificates and provisioning profiles that describe allowed entitlements and devices.
  • Embedded provisioning profile (embedded.mobileprovision) contains team IDs, entitlements, and device UDIDs (for ad-hoc builds).
  • Security implication: Understanding signing helps when repackaging, or when analyzing enterprise/ad-hoc builds that may leak certificates or test endpoints.

Entitlements

  • Entitlements are key/value capabilities that alter app privileges (e.g., aps-environment, com.apple.developer.associated-domains, keychain-access-groups).
  • Many vulnerabilities arise from overly-broad entitlements (e.g., shared keychain access groups).

App lifecycle & processes

  • Apps launch, go background/foreground, and are subject to lifecycle events (didFinishLaunching, applicationWillResignActive, etc.). Hooks in these places are common for auth/session handling and for placing security checks (or mistakes).

Packaging: IPA and .app

IPA structure

An .ipa is just a ZIP archive with a Payload/ folder. Inside Payload/YourApp.app/ you’ll find:

  • YourApp (Mach-O executable binary)
  • Info.plist (app metadata)
  • embedded.mobileprovision (provisioning)
  • Assets.car, Assets.xcassets, images
  • Resource files, frameworks (Frameworks/), PlugIns/, app extensions

Quick extraction

unzip AppName.ipa -d AppName_extracted
ls AppName_extracted/Payload/YourApp.app

Info.plist (what to inspect)

Info.plist is XML/JSON-like metadata. Security-relevant keys:

  • CFBundleIdentifier — app bundle identifier (used in many auth flows)
  • CFBundleURLTypes / CFBundleURLSchemes — custom URL schemes (deep links, potential open-URL attacks)
  • NSAppTransportSecurity — ATS exceptions that may allow insecure HTTP
  • UIBackgroundModes — background capabilities (networking, voip)
  • LSApplicationQueriesSchemes — other apps the app queries (inter-app comms)
  • CFBundleShortVersionString, CFBundleVersion — versioning (useful for known CVEs)

Inspect:

plutil -p Payload/YourApp.app/Info.plist

Provisioning profile & certificates

  • The embedded.mobileprovision can be decoded to readable XML/JSON. It contains: developer team, app identifier patterns, allowed devices, entitlements, and certificates.
  • Check for:
    • Entitlements section (overlaps with Info.plist entitlements)
    • Any leftover test team IDs or developer emails (may leak internal info)
    • application-identifier and keychain-access-groups

Inspect:

security cms -D -i Payload/YourApp.app/embedded.mobileprovision > provision.plist
plutil -p provision.plist

Mach-O binary basics

The main executable in the .app is a Mach-O file (possibly a fat/universal binary). Important concepts:

  • Architectures: arm64, armv7, x86_64 (simulator). Production apps for iPhones will have ARM slices.
  • Load commands: otool -l shows segments, load paths, and linked libraries.
  • Symbol tables: nm and otool -Iv help locate exported symbols and functions.
  • Objective-C metadata: Objective-C stores class and selector names in the binary — often readable as strings.

Useful commands:

file Payload/YourApp.app/YourApp
lipo -info Payload/YourApp.app/YourApp   # checks architectures
otool -L Payload/YourApp.app/YourApp     # linked libraries
nm -gj Payload/YourApp.app/YourApp       # global symbols
strings Payload/YourApp.app/YourApp | less

Security notes:

  • String and symbol leaks often reveal secrets (API endpoints, crypto keys, class names used for auth).
  • Swift binaries are more mangled; use swift-demangle or specialized tools to recover readable names.

Objective-C vs Swift artifacts

Objective-C

  • Retains class names and method selectors in runtime metadata — easy to enumerate.
  • Tools like class-dump or objc-runtime inspection can reconstruct header-like declarations.

Example workflow:

class-dump -H Payload/YourApp.app/YourApp -o headers/

Swift

  • Uses name mangling and richer metadata; newer Swift versions complicate decompilation.
  • class-dump-swift, swift-demangle, or decompilers (Ghidra/Hopper) can help.
  • Swift’s runtime metadata still exposes function names and types but in a different format.

Implication for testing: Objective-C apps often leak more immediately useful info; Swift apps require more effort but still reveal seeds of logic and endpoints.


App protections & where they appear

High-level protections you will see and where they live:

  • Obfuscation / symbol stripping — usually at compilation time (binary has few symbols).
  • Encryption / string encoding — strings appear scrambled in binary/resources, decoded at runtime.
  • Detect anti-debug / anti-tamper checks — code in didFinishLaunching or in critical flows.
  • Certificate pinning — usually in network stack code (NSURLSession delegates, custom sockets).
  • Keychain usage — calls to Keychain APIs; look for Keychain entitlement misuse.

You’ll detect these with static inspection (strings, class-dump) and confirm them via dynamic tests later.


iOS storage primitives (what to look for)

Understanding where apps persist data is crucial.

UserDefaults (NSUserDefaults)

  • Simple key/value store for preferences.
  • Often used (and sometimes abused) to store tokens or flags.
  • Located at Library/Preferences/<bundle-id>.plist in app container.

Inspect:

plutil -p Library/Preferences/<bundle-id>.plist

Files / Caches

  • Documents/, Library/Caches/, tmp/ — may store files or exported data.
  • Unencrypted files or debug logs can leak secrets.

SQLite / Realm / Core Data

  • Databases often located in Library/Application Support/ or Documents/.
  • Use sqlite3 to open .sqlite files and list tables.

Keychain

  • iOS Keychain is intended for secure storage; however, misuse (like weak access control or shared keychain groups) can expose secrets.
  • Keychain entries are not trivially extractable on non-jailbroken devices — but on jailbroken devices or via misconfigured access groups, risk exists.

Keychain vs Local Storage checklist:

  • Check for tokens stored in plaintext in files/plists.
  • Check for use of Keychain; note keychain-access-groups and team IDs.

Networking stack & where to find endpoints

  • API endpoints are often present in Info.plist, config files, or as constants in code.
  • Look for typical networking classes: NSURLSession, AFNetworking, Alamofire.
  • TLS/SSL settings: ATS exceptions in Info.plist may permit HTTP or weak TLS.

Search strings:

strings Payload/YourApp.app/YourApp | egrep -i 'https?://|api|auth|token|login|baseUrl'

Also inspect .plist or *.json config files inside the bundle for environment switches (dev/test/prod) and hardcoded keys.


Quick static checklist (first-pass on any app)

Run these checks immediately after extracting the IPA:

  1. Extract IPA and list contents.
  2. plutil -p Info.plist — inspect URL schemes, ATS exceptions, version, bundle ID.
  3. security cms -D -i embedded.mobileprovision — extract entitlements and provisioning metadata.
  4. lipo -info and otool -L on binary — check architectures and linked libs.
  5. strings / grep for endpoints, keys, and interesting patterns (password, secret, token, apikey, client_secret).
  6. class-dump for Objective-C headers (if available).
  7. Run mobSF static scan if you need an automated baseline.
  8. Note suspicious files (e.g., .sqlite, .plist with secrets, unminified JS, config files).

Hands-on lab exercises (safe, reproducible)

These are safe first exercises you can perform in your authorized lab.

Lab 1 — Extract & inspect IPA metadata

  1. Place AppName.ipa in your working directory.
  2. Extract: unzip AppName.ipa -d App_extracted cd App_extracted/Payload/YourApp.app
  3. Inspect Info.plist: plutil -p Info.plist | sed -n '1,200p'
  4. Decode provisioning: security cms -D -i embedded.mobileprovision > provision.plist plutil -p provision.plist | sed -n '1,200p'
  5. Record findings: bundle id, URL schemes, ATS exceptions, entitlements.

Deliverable: Short note with these items and at least one screenshot of the plutil output.

Lab 2 — Binary architecture and strings reconnaissance

  1. Find the binary file: file YourApp lipo -info YourApp
  2. List linked libraries and load commands: otool -L YourApp otool -l YourApp | sed -n '1,200p'
  3. Search for obvious URLs/keys: strings YourApp | egrep -i 'https?://|api|auth|token|key|secret' | head -n 50
  4. Try class-dump (if Objective-C): class-dump -H YourApp -o headers/ ls headers | head

Deliverable: A small table with:

  • architectures,
  • 3-5 interesting strings (endpoints or suspicious keys),
  • whether class-dump produced headers.

Lab 3 — Local storage check (if you have the app container)

If you can obtain the application container (simulator or device backup), inspect persistent storage:

  1. Search for database files: find . -type f \( -name '*.sqlite' -o -name '*.db' -o -name '*.plist' \) -print
  2. Open a SQLite DB: sqlite3 path/to/file.db .tables sqlite3 path/to/file.db "SELECT name FROM sqlite_master WHERE type='table';"
  3. Inspect plist files: plutil -p path/to/file.plist

Deliverable: List of discovered storage files and notes on any plaintext-looking tokens.


What to capture as evidence in Module 1

  • Screenshots of Info.plist and embedded.mobileprovision outputs.
  • strings results showing API endpoints or suspicious plaintext.
  • lipo / otool outputs showing architectures and linked frameworks.
  • Notes on any suspicious entitlements or ATS exceptions.
  • A short threat-model note enumerating the most likely areas of concern (e.g., insecure storage, dev/test endpoints).

Common pitfalls & how to avoid them

  • Assuming simulator behavior equals device behavior. The iOS simulator uses x86_64 binaries and a macOS environment — behavior (and access to Keychain) differs from ARM device. Always validate findings on the intended platform if possible.
  • Overlooking resource files. Sometimes the juicy stuff is in .plist, .json, or .js assets rather than the binary.
  • Ignoring obfuscation layers. Stripping symbols or obfuscation can make class-dump fail; don’t assume absence of strings means absence of logic — the app may decode strings at runtime.
  • Confusing provisioning for secrets. Embedded provisioning can contain team IDs and entitlements; it’s sensitive metadata but not a direct “secret key” usually.

Developer recommendations (what devs should do)

  • Minimize sensitive data in plaintext within the bundle; use server-side secrets and short-lived tokens.
  • Use Keychain for secrets and configure access groups tightly.
  • Avoid ATS exceptions unless strictly necessary — and document the requirement.
  • Strip debug endpoints and developer/test keys from production builds.
  • Keep minimal entitlements and use associated domains or universal links rather than insecure custom URL schemes where possible.

Quick reference cheat sheet (commands)

# Extract IPA
unzip AppName.ipa -d App_extracted

# Inspect Info.plist
plutil -p App_extracted/Payload/YourApp.app/Info.plist

# Decode provisioning
security cms -D -i App_extracted/Payload/YourApp.app/embedded.mobileprovision > provision.plist
plutil -p provision.plist

# Binary info
file Payload/YourApp.app/YourApp
lipo -info Payload/YourApp.app/YourApp
otool -L Payload/YourApp.app/YourApp
strings Payload/YourApp.app/YourApp | egrep -i 'https?://|api|auth|token|key|secret' | head

# Generate Objective-C headers (if applicable)
class-dump -H Payload/YourApp.app/YourApp -o headers/

Next steps (where Module 1 prepares you to go)

  • Module 2 (Reconnaissance & Information Gathering): leverage findings here to map backends, enumerate endpoints, and build a targeted test plan.
  • Module 3 (Static Analysis): use the headers and string findings to do deeper reverse engineering and identify functions of interest.
  • Module 4 (Dynamic Analysis): confirm static observations at runtime, inspect network flows, and begin controlled instrumentation.