Contact

Dumping and repacking decrypted iOS binaries

Overview

App Store binaries are protected by FairPlay DRM on disk. When an app starts, iOS decrypts the executable pages in memory so the process can run. A reverse engineering workflow can use that runtime state to copy the decrypted Mach-O data, replace the encrypted copy in the app bundle, and package the result for analysis.

frida-ios-dump automates that workflow with Frida and SSH. This article explains the parts of the Mach-O format that matter for the dump process and how the decrypted binary is reconstructed into an IPA.

iOS app encryption and decryption

How FairPlay DRM encrypts iOS applications

When an iOS app is downloaded from the App Store, the executable Mach-O binary is encrypted with Apple’s FairPlay DRM. The protected data is typically the __TEXT segment, which contains executable instructions.

Example otool -l output for an encrypted binary:

Load command 9
      cmd LC_ENCRYPTION_INFO
  cmdsize 20
  cryptoff 16384
 cryptsize 102400
   cryptid 1  # Indicates encryption is active

How decryption happens at runtime

When an encrypted app is launched, iOS decrypts it in memory so the operating system can execute it:

  1. The kernel loads the encrypted Mach-O binary into memory.
  2. If the app is FairPlay-protected, the kernel decrypts the encrypted segments in memory.
  3. The decrypted instructions are executed as normal by the CPU.

The decrypted bytes are available in process memory while the app runs. The file on disk remains encrypted.


Mach-O load commands

What are load commands?

Mach-O load commands describe the structure and behavior of an executable. The dynamic linker uses them to map segments, load libraries, locate entry points, and interpret metadata.

Each Mach-O binary has a header that contains:

Common load commands include:

Understanding __TEXT and __DATA segments

In every Mach-O binary, there are multiple segments, each containing different types of data. Two of the most important segments are:

__TEXT segment

__DATA segment

Key differences between __TEXT and __DATA

| Feature            | `__TEXT` Segment  | `__DATA` Segment  |
|--------------------|-----------------|-----------------|
| Stores            | Executable code  | Modifiable data (variables, metadata) |
| Memory Permissions | Read-only (`r-x`) | Read-Write (`rw-`) |
| Encrypted by FairPlay? | Yes | No |

How frida-ios-dump uses these segments

When extracting a decrypted binary, frida-ios-dump targets the __TEXT segment because that is the encrypted region. The tool:

  1. Reads the LC_SEGMENT commands to locate the __TEXT segment.
  2. Extracts the __TEXT segment’s virtual memory address and size.
  3. Dumps the decrypted contents from memory into a new Mach-O file.
var text_segment;
for (var i = 0; i < segments.length; i++) {
    if (segments[i].name == "__TEXT") {
        text_segment = segments[i];
        break;
    }
}
var decrypted_data = Memory.readByteArray(modbase.add(text_segment.vmaddr), text_segment.vmsize);

The decrypted Mach-O binary is saved to disk. An iOS app bundle can contain additional Mach-O binaries, frameworks, and resources, so the dump process must preserve the bundle structure.

Reconstructing the IPA file

Once all decrypted Mach-O binaries have been dumped, frida-ios-dump restructures them into an IPA file:

  1. Replaces the encrypted Mach-O binaries inside the app bundle with the decrypted ones.
  2. Maintains the app’s original structure, including Info.plist, frameworks, and resources.
  3. Packages everything into a new IPA file that can be sideloaded or analyzed.

Summary

The resulting IPA is useful for static analysis, instrumentation, and repeatable reverse engineering workflows.