Mapping of the obfuscated keys (or questions) used by iOS's MobileGestalt to the de-obfuscated, easier-to-understand ones. To obfuscate a key, Apple calculates the base64 of MGCopyAnswer{theKey}, truncates the last two characters and calculates the MD5 from the resulting string.
It is our job to de-obfuscate them all.
The keys are currently based on iOS 27.0b5.
There are a few certain patterns of the key names, which can be useful for de-obfuscation.
- Kebab case
some-key-namehas-xxxsupports-xxx
- Pascal case of
DeviceSupportsXXX(common) - Pascal case of
XXXCapability(common)FrontFacing(Camera)XXXCapabilityRearFacing(Camera)XXXCapability
- Pascal case of
SupportsXXX - Pascal case of
HasXXX - Pascal case of
IsXXX - Pascal case of
XXXData(usually come alongside another key withoutDatasuffix in it)
There are also keys which are obfuscated the same way but are not considered as MobileGestalt keys. That is, you can't use MGCopyAnswer to get the value of the key. Instead, they are used for retrieving the value from the IODeviceTree, in an obfuscated manner. These keys are mostly in the kebab case, having their pascal case equivalent which is actually used by MGCopyAnswer. In the mapping files, these keys are marked with a comment // non-gestalt-key.
iOS 27.0+ libMobileGestalt strings suggests that iOS 27 no longer obfuscates some keys that are used to query IODeviceTree.
For example, the legacy non-Gestalt hash wAbB2fAjUqUc6lNBelfWMA was removed while the readable no-als-period-update string appeared.
Therefore, it is expected that there will be less non-Gestalt keys in iOS 27.0+ than in previous versions.
# Clone the repository
git clone https://github.com/PoomSmart/MGKeys.git
cd MGKeys
# Install dependencies (optional, for development)
pip3 install -r requirements.txtAll scripts support --help flags for detailed usage information. Run any script with --help to see available options and examples.
Use discover-version.sh to automate downloading an IPSW, extracting libMobileGestalt.dylib, and running discovery:
./discover-version.sh <DEVICE> <VERSION> [ARCH] [OPTIONS]
# Examples
./discover-version.sh iPhone15,2 16.5
./discover-version.sh iPhone15,2 16.5 --build 20F66 --remote-extract
./discover-version.sh iPhone16,1 27.0 --build 24A5408d --ipsw-url <APPLE_IPSW_URL>
./discover-version.sh iPhone15,2 26.4 --post-process-onlyUse --build for beta build identifiers, including identifiers with lowercase
seed suffixes such as 24A5408d. Use --ipsw-url when the beta is not yet
indexed by ipsw.me. Beta releases are recorded under their final version
(for example, iOS 27.0 beta 5 produces versions/version-27.0.txt).
--post-process-only skips IPSW extraction and key discovery, and only runs post-processing steps on current local artifacts. This is useful when you want to validate or rerun:
versions/version-<VERSION>.txtgeneration fromhashes.txt- syncing
discover-obfuscated-mapped.txtintodeobfuscated.py - syncing known missing hashes into
hashes_legacy.txt gen_mapping.pyandpopulate_versions.py
To extract hashes for version tracking without running discovery or updating mappings:
./extract-version-hashes.sh <DEVICE> <VERSION> [ARCH] [OPTIONS]
# Examples
./extract-version-hashes.sh iPhone15,2 18.0
./extract-version-hashes.sh iPhone13,1 17.4 arm64e --remote-extract
./extract-version-hashes.sh iPhone16,1 27.0 --build 24A5408d --ipsw-url <APPLE_IPSW_URL>This script:
- Downloads/extracts the IPSW and
libMobileGestalt.dylib - Generates
versions/version-XX.txtwith extracted hashes - Does NOT run discovery or update mapping files
- Useful for populating version history and key tracking
versions/version-sim.txt is the set of hashes that appear in the simulator dylib but not in any physical iOS snapshot. populate_versions.py uses that file to emit // Simulator comments.
Do not run discover-version.sh, deobfuscate.sh, or extract-hashes.sh against a simulator dylib — those overwrite device hashes.txt.
./extract-sim-hashes.sh
./extract-sim-hashes.sh libMobileGestalt_sim.dylib arm64
./extract-sim-hashes.sh --no-post-processThis script:
- Extracts hashes from
libMobileGestalt_sim.dylib(default arch:arm64) - Rewrites
versions/version-sim.txtwithout touchinghashes.txt - Adds brand-new simulator-only hashes to
hashes_legacy.txt - Discovers
_MobileGestalt_*symbol names and syncs them intodeobfuscated_legacy.py - Regenerates mapping headers unless
--no-post-processis set
For manual key discovery from an extracted dylib:
# Run discovery with default architecture (arm64e)
./discover.sh
# Specify architecture
./discover.sh --arch arm64
# See all options
./discover.sh --helpIf you have hints about unknown keys (from keys_desc.py):
# Attempt to guess all unknown keys
python3 guess_keys.py
# Target a specific key with verbose output
python3 guess_keys.py --key <OBFUSCATED_KEY> --verbose
# See all options
python3 guess_keys.py --helpExtract keys from IODeviceTree properties:
# 1. Dump DeviceTree to JSON
./dump-dtree.sh <path/to/ipsw_or_dtree>
# Or from remote IPSW
./dump-dtree.sh -d <DEVICE> -v <VERSION>
# 2. Recover keys from the JSON
python3 recover_from_dtree.py
# See all options
./dump-dtree.sh --help
python3 recover_from_dtree.py --helpFor difficult unknowns, prefer the IDA database generated from the dyld shared cache over the extracted dylib. It preserves the shared-cache data tables and cross-references:
# After IPSW extraction
ida64 dyld_shared_cache/<BUILD>__<DEVICE>/dyld_shared_cache_arm64e.i64Search unresolved hash strings, inspect their data cross-references, and
decompile the associated MobileGestalt registration or lookup functions. Add
only evidence-based hints to keys_desc.py; do not guess a key name from the
hash alone.
Use hashcat to brute-force unknown obfuscated keys:
# 1. Prepare hashcat input files
python3 gen_md5.py # Generate MD5 hashes from all-hashes.txt
python3 gen_mapping.py # Generate potfile for known keys
# 2. Run hashcat with appropriate attack mode
# See hashcat documentation for advanced usage and attack modes
# 3. After recovery, update deobfuscated.py with discovered keysThe workflow generates:
md5hashes.txt- MD5 hashes of all obfuscated keys for hashcat inputpotfile- Known key mappings in hashcat potfile format for reference
# Install dependencies
pip3 install -r requirements.txt
# Run all tests
pytest
# Run with coverage
pytest --cov=. test_*.py
# Run specific test file
pytest test_obfuscate.py -vThe Python scripts include comprehensive type hints:
# Install mypy (included in requirements.txt)
pip3 install -r requirements.txt
# Run type checker
mypy *.pyAll scripts support --help for detailed usage. Features:
- Python scripts (
*.py): Type hints, pathlib, argparse, comprehensive error handling - Shell scripts (
*.sh): Help messages, prerequisite checks, input validation - Tests (
test_*.py): Comprehensive unit tests for core logic - Shared library (
lib-ipsw-extract.sh): Common IPSW extraction functions used by discovery scripts
Run any script with --help to see available options and examples.
- Jonathan Levin
- Timac
- Siguza
- Elias Limneos
- PoomSmart
- JackoPlane