Skip to content

Repository files navigation

Pypi version

Overview

Store both types of Apple's DeveloperDiskImage files:

  • DeveloperDiskImage.dmg & DeveloperDiskImage.dmg.signature
    • Used for each iOS version < 17.0
  • The new Personalized images, but splitted to:
    • APFS
    • BuildManifest.plist
    • Trustcache
  • The Cryptex1 assets, for installing the same DDI through cryptexd instead of the image mounter:
    • APFS
    • BuildManifest.plist
    • Trustcache
    • Cryptex info plist
    • Volume root hash

The split of the new format is requires for OS* other than macOS that will have trouble extracting the original APFS image inside: ~/Library/Developer/DeveloperDiskImages.

Layout

DirectoryConsumed by
DeveloperDiskImages/<version>/iOS < 17.0
PersonalizedImages/Xcode_iOS_DDI_Personalized/the image mounter (mounter auto-mount)
PersonalizedImages/Xcode_iOS_DDI_Cryptex/cryptexd (cryptex auto-install)

Every payload is published under a fixed file name, so download URLs stay predictable across releases:

FilePersonalizedCryptex
BuildManifest.plistyesyes
Image.dmgPersonalizedDMGCryptex1,GenericDmg
Image.dmg.trustcacheLoadableTrustCacheCryptex1,GenericTrustCache
Image.dmg.cryptex_info--Cryptex1,CryptexInfoPlist
Image.dmg.root_hash--Cryptex1,GenericVolume

Apple's own paths embed a build number (022-22107-072.dmg), so the published BuildManifest.plist is rewritten to declare the fixed names instead. Only Info.Path is adjusted -- the digests personalization depends on are untouched -- which keeps a downloaded cryptex directory usable as a drop-in Restore directory.

Updating

update_ddi.py refreshes every variant from a local Xcode installation. macOS only, no dependencies, run it with uv:

uv run --script update_ddi.py # refresh every variant of the iOS DDI
uv run --script update_ddi.py --dry-run # report what would change, write nothing
uv run --script update_ddi.py --platform tvOS --variant cryptex

Pass --script so uv runs it as a standalone script rather than treating this repository as a uv project (which would leave a stray uv.lock and .venv behind).

It reads Xcode's bundle from /Library/Developer (falling back to attaching CoreDevice/CandidateDDIs/<platform>_DDI.dmg when no expanded copy exists), verifies every payload against the SHA-384 digests in the build manifest before publishing it, and removes stale files left over from a previous build. Remember to bump LATEST_DDI_BUILD_ID in pymobiledevice3 to match whatever build it reports.

Python package

Additionally, this repo provides a python API for accessing this repository. You can install it as follows:

python3 -m pip install -U developer_disk_image

Example usage

Payloads are fetched from raw.githubusercontent.com, which is not subject to the REST API's 60-requests-per-hour anonymous quota, so no GitHub token is needed. create() accepts a ref (branch, tag or commit) to read a revision other than main.

fromdeveloper_disk_image.repoimportDeveloperDiskImageRepositoryrepo=DeveloperDiskImageRepository.create()
# will get both the APFS and the signature filedeveloper_disk_image=repo.get_developer_disk_image('16.4')
# will get all necessary files for mountpersonalized_disk_image=repo.get_personalized_disk_image()
# will get all necessary files for installing the DDI as a cryptexcryptex_disk_image=repo.get_cryptex_disk_image()

Writing the cryptex assets back out under their published names produces a directory that cryptexd clients accept as-is:

frompathlibimportPathfromdeveloper_disk_image.repoimportCRYPTEX_IMAGE_PAYLOADSrestore=Path('Xcode_iOS_DDI_Cryptex')
restore.mkdir(parents=True, exist_ok=True)
(restore/'BuildManifest.plist').write_bytes(cryptex_disk_image.build_manifest)
forfield, nameinCRYPTEX_IMAGE_PAYLOADS.items():
(restore/name).write_bytes(getattr(cryptex_disk_image, field))

About

Home for both DeveloperDiskImage files (iOS < 17.0) and Personalized files (iOS >= 17.0)

Topics

Resources

Stars

151 stars

Watchers

6 watching

Forks

Releases

Used by

Contributors

Languages