How to Extract, Analyze, and Patch OTA Updates with ipsw

ipsw treats OTA updates as ZIP containers containing a post.bom manifest and encrypted payloads, providing CLI commands and Go libraries to download, inspect, extract files, and apply RSR patches using raw image diffing.

The blacktop/ipsw repository provides a comprehensive toolkit for working with Apple firmware files. Whether you need to extract, analyze, and patch OTA updates with ipsw, the tool offers both command-line interfaces and Go libraries to handle encrypted payloads, cryptex volumes, and Rapid Security Response patches.

Understanding the OTA Update Structure

Apple OTA updates are ZIP archives containing a post.bom manifest, encrypted payload files (often AEA-encrypted IMG4), and optionally cryptex volumes for Rapid Security Response patches. The ipsw tool models this structure in pkg/ota/ota.go, where the OTA type provides methods to access the ZIP contents, decrypt payloads, and parse the BOM manifest.

Downloading and Decrypting OTA Updates

The ipsw download ota command retrieves OTA files from Apple's servers. When dealing with encrypted updates, ipsw handles AEA (Apple Encrypted Archive) decryption automatically.

Handling AEA Encryption

In pkg/ota/ota.go, the Open() function creates an *ota.OTA object and calls ResolveAEAKeyFromFlags to obtain decryption keys from Apple's servers or a local ota_fcs_keys.json database. This lazy-loading approach ensures the ZIP structure is parsed before attempting decryption of the payload.

Analyzing OTA Metadata

To inspect update metadata without extracting files, use ipsw ota info. This command leverages the ota.Info() method in pkg/ota/ota.go to parse the embedded Info.plist and post.bom manifest, returning version, build numbers, supported devices, and signed components.

Extracting Files from OTA Updates

The extraction pipeline supports individual files, pattern matching, and cryptex volume handling.

Listing and Extracting Individual Files

The Files() method in pkg/ota/ota.go returns a filtered slice of zip.File entries based on the post.bom manifest. To extract a specific file, open it via o.Open(name, decompress) and copy the bytes to your destination.

Working with Cryptex Volumes

For Rapid Security Response updates, ipsw handles cryptex volumes containing cryptex-app and cryptex-system-* DMGs. The ExtractFromCryptexes method in pkg/ota/ota.go walks these volumes and extracts files matching a regex pattern. Low-level cryptex unpacking logic resides in pkg/ota/aa.go.

Pattern-Based Extraction

The RemoteExtract function (approximately lines 115-140 in pkg/ota/ota.go) enables regex-based extraction across the entire payload. This function iterates over payload files, runs Parse() (which uses Apple's aa binary when available, otherwise a Go implementation), and writes matches to the destination folder.

Patching OTA Updates with RSR (Rapid Security Response)

Rapid Security Response updates patch existing OTA files without requiring full system reinstalls. The ipsw ota patch rsr command applies these differential updates to AppOS and SystemOS cryptexes.

Understanding the RSR Patching Process

RSR patches use raw image diffing to modify existing DMG files. The process extracts the original cryptex-app and cryptex-system-* DMGs from the base OTA, applies binary diffs from the RSR update using ridiff.RawImagePatch, and writes the patched DMGs back to disk.

Applying Patches with ipsw ota patch rsr

The command implementation in cmd/ipsw/cmd/ota/ota_patch_rsr.go orchestrates the workflow. It calls ridiff.RawImagePatch (located in pkg/ota/ridiff) to perform the actual binary patching, handling both the AppOS and SystemOS cryptexes in a single operation.

Programmatic Usage with Go

The ipsw library exposes the OTA pipeline as a Go API for integration into custom tools.

Listing OTA Files

package main

import (
	"fmt"
	"log"

	"github.com/blacktop/ipsw/pkg/ota"
)

func main() {
	// Open (auto-decrypt if needed)
	o, err := ota.Open("myOTA.zip", nil)
	if err != nil {
		log.Fatal(err)
	}
	// Print all entries
	for _, f := range o.Files() {
		if f.IsDir() {
			continue
		}
		fmt.Println(f.Name())
	}
}

The Files() method in pkg/ota/ota.go returns the filtered zip.File slice based on the post.bom manifest.

Extracting dyld_shared_cache Files

package main

import (
	"log"
	"path/filepath"

	"github.com/blacktop/ipsw/pkg/ota"
)

func main() {
	o, _ := ota.Open("myOTA.zip", nil)
	info, _ := o.Info()
	output := filepath.Join(".", info.GetFolder())
	_ = o.ExtractFromCryptexes(`dyld_shared_cache.*`, output) // uses RIDIFF10 cryptexes
}

ExtractFromCryptexes walks cryptex volumes and extracts files matching the provided regex.

Patching RSR Updates Programmatically

package main

import (
	"log"
	"path/filepath"

	"github.com/blacktop/ipsw/pkg/ota"
	"github.com/blacktop/ipsw/pkg/ota/ridiff"
)

func main() {
	basePath := "BaseOTA.zip"
	rsrPath := "RSR_OTA.zip"

	// Parse base OTA to locate the DMGs
	baseInfo, _ := ota.ParseInfo(basePath)
	appDMG, _ := baseInfo.GetAppOsDmg()
	sysDMG, _ := baseInfo.GetSystemOsDmg()

	// Patch app cryptex
	if err := ridiff.RawImagePatch(appDMG, rsrPath, appDMG+"_patched.dmg", 0); err != nil {
		log.Fatal(err)
	}
	// Patch system cryptex (optionally filter architectures)
	if err := ridiff.RawImagePatch(sysDMG, rsrPath, sysDMG+"_patched.dmg", 0); err != nil {
		log.Fatal(err)
	}
}

This mirrors the CLI workflow in cmd/ipsw/cmd/ota/ota_patch_rsr.go, using ridiff.RawImagePatch to apply binary diffs.

Summary

  • ipsw models OTA updates as ZIP archives containing post.bom manifests and encrypted payloads, handling AEA decryption automatically via pkg/ota/ota.go.
  • The download phase retrieves updates and resolves decryption keys using ResolveAEAKeyFromFlags, supporting both remote Apple key servers and local ota_fcs_keys.json databases.
  • Analysis commands like ipsw ota info leverage the Info() method to parse metadata without extraction, reading embedded plists and BOM manifests.
  • Extraction supports individual files, regex patterns via RemoteExtract, and cryptex volumes through ExtractFromCryptexes, with low-level handling in pkg/ota/aa.go.
  • RSR patching applies differential updates to AppOS and SystemOS cryptexes using ridiff.RawImagePatch in pkg/ota/ridiff, enabling rapid security fixes without full OS reinstalls.

Frequently Asked Questions

How does ipsw handle AEA encryption for OTA files?

ipsw automatically detects AEA encryption headers when opening OTA files via ota.Open(). The tool calls ResolveAEAKeyFromFlags to fetch decryption keys from Apple's servers or a local ota_fcs_keys.json database, then transparently decrypts the payload during extraction operations.

What is the difference between regular OTA extraction and cryptex extraction?

Regular OTA extraction pulls files directly from the main payload ZIP using the post.bom manifest. Cryptex extraction specifically handles Rapid Security Response volumes containing cryptex-app and cryptex-system-* DMGs. The ExtractFromCryptexes method in pkg/ota/ota.go walks these specialized volumes to extract patched system files.

Can I patch an existing OTA with a newer RSR update using the Go library?

Yes, the pkg/ota/ridiff package exposes RawImagePatch for programmatic RSR patching. You parse the base OTA to locate AppOS and SystemOS DMGs, then apply the RSR diff using ridiff.RawImagePatch(baseDMG, rsrOTA, outputPath, flags). This mirrors the ipsw ota patch rsr CLI command implemented in cmd/ipsw/cmd/ota/ota_patch_rsr.go.

Where does ipsw store decryption keys for OTA files?

ipsw checks for AEA decryption keys in a local JSON database named ota_fcs_keys.json before querying Apple's remote key servers. The ResolveAEAKeyFromFlags function in pkg/ota/ota.go handles this resolution logic, caching keys locally to avoid repeated network requests for the same firmware files.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →