Skip to main content

Application Structure

Every iOS app is a directory bundle. Understanding the bundle layout, the IPA format, and the code signature is the first step in static analysis.

The .app Bundle​

An app bundle is a directory ending in .app containing the executable and all resources:

MyApp.app/
├── MyApp # the Mach-O executable (main binary)
├── Info.plist # metadata, permissions, keys
├── Frameworks/ # embedded dynamic frameworks
├── .nib / .storyboardc/ # compiled Interface Builder UI
├── Assets.car # compiled asset catalog
├── embedded.mobileprovision # provisioning profile (dev builds)
├── PkgInfo # legacy 8-byte file
├── _CodeSignature/CodeResources # signature hashes
└── CodeSignature # code signature data

Info.plist​

The metadata plist drives a lot of security-relevant behavior. Read it first:

plutil -p MyApp.app/Info.plist

Pay attention to: CFBundleURLTypes (URL schemes), NSAppTransportSecurity, NSLocationUsageDescription (privacy strings), UIRequiredDeviceCapabilities, and any custom keys.

The executable​

  • A Mach-O binary (MH_EXECUTE), arm64 slice.
  • Inspect with otool -L (linked libraries), nm, strings, jtool2, or radare2/Ghidra for reversing.

Frameworks​

  • Embedded frameworks under Frameworks/ are bundled with the app (vs. system frameworks).
  • Embedded frameworks are a classic weak point: they are signed as part of the app and can be swapped/replaced to hijack behavior on jailbroken devices.

Compiled UI​

  • .nib and .storyboardc are compiled XIB/storyboard archives; use ibtool to dump their content, or just look at them with a plist editor.

Assets and provisioning​

  • Assets.car is the compiled asset catalog (images/icons); extract with assetutil or acextract.
  • embedded.mobileprovision is the provisioning profile (see publishing note).

IPA Files​

An IPA (iOS App) is just a ZIP archive containing a Payload/ folder with the .app bundle inside, plus optional SwiftSupport/ and WatchKitSupport/ directories.

unzip -l MyApp.ipa

Archive: MyApp.ipa
Length Date Time Name
--------- ---------- ----- ----
0 2024-05-11 09:32 Payload/
0 2024-05-11 09:32 Payload/MyApp.app/
8431424 2024-05-11 09:32 Payload/MyApp.app/MyApp
822 2024-05-11 09:32 Payload/MyApp.app/Info.plist
28761 2024-05-11 09:32 Payload/MyApp.app/Assets.car
... ...
4358 2024-05-11 09:32 Payload/MyApp.app/embedded.mobileprovision
32580 2024-05-11 09:32 Payload/MyApp.app/_CodeSignature/CodeResources
--------- -------

Extract an IPA with unzip, and read the bundle directly. Since an IPA is just a ZIP, you can even inspect it without an Apple device.

The Code Signature​

Every bundle is signed with a signature embedded in the Mach-O (LC_CODE_SIGNATURE) plus _CodeSignature/CodeResources for resources.

codesign -dvv MyApp.app            # dump signature info
codesign -d --entitlements - MyApp.app # dump entitlements
codesign --verify --deep MyApp.app # verify integrity
  • The signature binds the binary hash, entitlements, and provisioning profile together.
  • On a jailbroken device you can resign or patch: tools (like ldid) re-sign modified binaries, and resource-hash checks are relaxed, this is exactly what lets testers tamper with apps and observe the result.

Pentest workflow​

  1. Unzip the IPA and read Info.plist for attack surface (schemes, permissions, ATS).
  2. Dump linked frameworks and the binary's entitlements.
  3. Extract embedded frameworks for standalone analysis.
  4. Re-sign and install the modified bundle on a test device to observe patched behavior.