### Install PyIMG4 Locally Source: https://github.com/m1stadev/pyimg4/blob/master/README.md Install PyIMG4 directly from the source code repository. ```bash pip install --force-reinstall . ``` -------------------------------- ### Install PyIMG4 from PyPI Source: https://github.com/m1stadev/pyimg4/blob/master/README.md Use this command to install the PyIMG4 library from the Python Package Index. ```bash python3 -m pip install pyimg4 ``` -------------------------------- ### Install pyimg4 Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Install the pyimg4 library using pip. For development, use the --force-reinstall option with optional dependencies. ```bash pip install pyimg4 ``` ```bash pip install --force-reinstall . ``` -------------------------------- ### Example Usage of KeybagType Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/types.md Demonstrates how to instantiate a Keybag object specifying the type of key material to use. ```python keybag = pyimg4.Keybag(iv=iv_bytes, key=key_bytes, type_=pyimg4.KeybagType.PRODUCTION) ``` -------------------------------- ### Complete IMG4 Usage Example Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Demonstrates parsing an existing IPSW file, accessing IMG4 components like payload and manifest, analyzing embedded images, and constructing a new IMG4 file with a modified payload. This example covers a wide range of functionalities within the pyimg4 library. ```python import pyimg4 # Parse an existing firmware file with open('iPhone11,2_16.3_20D5217g_Restore.ipsw/Firmware/iPhone11,2_16.3_20D5217g_Restore.ipsw.ipsw', 'rb') as f: img4_data = f.read() img4 = pyimg4.IMG4(img4_data) # Access components print(f"Payload type: {img4.im4p.fourcc}") print(f"Manifest ECID: {img4.im4m.ecid}") print(f"Device chip: 0x{img4.im4m.chip_id:04x}") # Decompress payload if needed if img4.im4p.payload.compression != pyimg4.Compression.NONE: print(f"Compression: {img4.im4p.payload.compression.name}") # img4.im4p.payload.decompress() # Extract and analyze images for image in img4.im4m.images: print(f"Image: {image.fourcc}") if image.digest: print(f" Hash: {image.digest.hex()}") # Build new IMG4 (e.g., with modified payload) new_payload = pyimg4.IM4P( fourcc='iBSS', description='SecureBootStage1', payload=modified_boot_data ) new_img4 = pyimg4.IMG4(im4p=new_payload, im4m=img4.im4m, im4r=img4.im4r) with open('modified.img4', 'wb') as f: f.write(new_img4.output()) ``` -------------------------------- ### Set IM4R boot_nonce Example Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Demonstrates how to instantiate IM4R and set its boot_nonce property with a hexadecimal byte string. The value will be automatically reversed. ```python im4r = pyimg4.IM4R() im4r.boot_nonce = bytes.fromhex('0123456789abcdef') ``` -------------------------------- ### Example Usage of Payload Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/types.md Shows how to create an IM4PData object and obtain the serialized payload, including its data and keybags. ```python im4p_data = pyimg4.IM4PData(firmware_bytes) payload = im4p_data.output() # payload.data = firmware bytes # payload.keybags = None (if unencrypted) or ASN.1 bytes (if encrypted) ``` -------------------------------- ### Markdown Cross-Reference Example Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/README.md Demonstrates how to create internal links within markdown documentation using standard markdown syntax. Paths are relative to the output directory root. ```markdown See: [Class Documentation](path/to/file.md#heading) ``` -------------------------------- ### Parse IMG4 File Info Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Use this command to get information about an IMG4 file. No specific setup is required beyond having the tool installed. ```bash # Parse IMG4 file pyimg4 img4 info --input firmware.img4 ``` -------------------------------- ### Parse Manifest File Info Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Get information about a manifest file. This is useful for understanding the contents of the manifest. ```bash # Parse manifest pyimg4 im4m info --input manifest.im4m ``` -------------------------------- ### Use Default Compression Libraries Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Example of unsetting the PYIMG4_FORCE_LZFSE environment variable to revert to the default compression library selection logic, which uses native libraries on macOS and lzfse on other platforms. ```bash # Use default (native) libraries unset PYIMG4_FORCE_LZFSE python3 my_script.py ``` -------------------------------- ### IM4R boot_nonce Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Allows getting and setting the device-specific boot nonce. The setter automatically handles byte reversal for storage and transmission, and manages BNCN properties. ```python @property def boot_nonce(self) -> Optional[bytes] @boot_nonce.setter def boot_nonce(self, boot_nonce: bytes) -> None: ``` -------------------------------- ### Query PyIMG4 Version Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/index.md Import the pyimg4 library and print its __version__ attribute to get the current version of the library at runtime. Versioning follows semantic versioning (major.minor.patch). ```python import pyimg4 print(pyimg4.__version__) # e.g., "1.2.3" ``` -------------------------------- ### Force LZFSE on macOS Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Example of setting the PYIMG4_FORCE_LZFSE environment variable to 1 to force the use of the lzfse library on macOS, overriding the default native apple_compress module. This is useful for testing purposes. ```bash # Use lzfse library on macOS (not recommended) export PYIMG4_FORCE_LZFSE=1 python3 my_script.py ``` -------------------------------- ### Determine SoC from Chip ID Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Use the chip_id property to identify the specific SoC of a device. This example demonstrates how to map different chip ID ranges to their corresponding SoC names. ```python manifest = pyimg4.IM4M(data) if 0x8720 <= manifest.chip_id <= 0x8960: soc = f"S5L{manifest.chip_id:02x}" elif manifest.chip_id in range(0x7002, 0x8003): soc = f"S{manifest.chip_id:02x}" else: soc = f"T{manifest.chip_id:02x}" print(f"Device: {soc}") ``` -------------------------------- ### Get _Property FourCC Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Retrieves the 4-character identifier for the property. Examples include 'DGST' or 'BNCH'. ```python @property def fourcc(self) -> str ``` -------------------------------- ### IM4P Constructor Options Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Initialize an IM4P component by parsing existing data or by providing a four-character type code, a description, and the firmware payload. ```python IM4P( data: Optional[bytes] = None, # Parse existing IM4P fourcc: Optional[str] = None, # 4-char type identifier description: Optional[str] = None, # Human-readable description payload: Optional[Union[IM4PData, bytes]] = None, # Firmware data ) ``` -------------------------------- ### Get and Set IM4PData Extra Data Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md The extra property allows getting or setting optional extra data, such as KPP segments. The setter validates the input type. ```python @property def extra(self) -> Optional[bytes]: # ... implementation details ... @extra.setter def extra(self, extra: Optional[bytes]) -> None: # ... implementation details ... ``` -------------------------------- ### Get Serialized Size of PyIMG4 Object Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Use the len() operator to get the size in bytes of the serialized Image4 object. This returns the length of the object's output. ```python img4 = pyimg4.IMG4(data) size_bytes = len(img4) print(f"IMG4 file size: {size_bytes} bytes") ``` -------------------------------- ### Get and Set IM4PData Uncompressed Size Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md The size property allows getting or setting the uncompressed data size. The setter includes validation for non-negative values and re-detects compression if the payload is encrypted. ```python @property def size(self) -> int: # ... implementation details ... @size.setter def size(self, size: int) -> None: # ... implementation details ... ``` -------------------------------- ### Create IM4R with Boot Nonce Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/examples.md Generate an IM4R file containing a boot nonce. The boot nonce must be exactly 8 bytes long. The output includes the hex representation of the nonce. ```python #!/usr/bin/env python3 import pyimg4 from pathlib import Path def create_restore_info(boot_nonce_hex, output_path): """Create IM4R with boot nonce.""" # Parse nonce (remove 0x prefix if present) nonce_hex = boot_nonce_hex.replace('0x', '') boot_nonce = bytes.fromhex(nonce_hex) # Validate length if len(boot_nonce) != 8: raise ValueError(f"Boot nonce must be 8 bytes, got {len(boot_nonce)}") # Create IM4R im4r = pyimg4.IM4R() im4r.boot_nonce = boot_nonce # Write Path(output_path).write_bytes(im4r.output()) print(f"Created restore info: {output_path}") print(f"Boot nonce: 0x{boot_nonce.hex()}") create_restore_info('0x0123456789abcdef', 'restore.im4r') ``` -------------------------------- ### Build IMG4 from Components Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/examples.md Assemble an IMG4 file from separate payload, manifest, and optional restore components. Ensure all component files exist before execution. ```python #!/usr/bin/env python3 import pyimg4 from pathlib import Path def build_img4(payload_path, manifest_path, output_path, restore_path=None): """Assemble IMG4 from separate components.""" # Load payload with open(payload_path, 'rb') as f: im4p = pyimg4.IM4P(f.read()) # Load manifest with open(manifest_path, 'rb') as f: im4m = pyimg4.IM4M(f.read()) # Optionally load restore info im4r = None if restore_path: with open(restore_path, 'rb') as f: im4r = pyimg4.IM4R(f.read()) # Create IMG4 img4 = pyimg4.IMG4(im4p=im4p, im4m=im4m, im4r=im4r) # Write Path(output_path).write_bytes(img4.output()) print(f"Built IMG4: {output_path}") build_img4('payload.im4p', 'manifest.im4m', 'firmware.img4') ``` -------------------------------- ### IM4P.payload Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-payload.md Gets or sets the payload data for the IM4P component. ```APIDOC ## IM4P.payload Property ### Description Gets or sets the payload data for the IM4P component. ### Method - Getter: `payload` - Setter: `payload` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **payload** (Optional[Union[IM4PData, bytes]]) - The payload. Accepts an IM4PData object or raw bytes (which will be auto-wrapped). ### Request Example ```python # Get payload object payload_data = im4p.payload # Set payload with raw bytes im4p.payload = firmware_bytes ``` ### Response #### Success Response (200) - **payload** (Optional[IM4PData]) - The IM4PData object or None if not set. #### Response Example ```json { "data": "..." } ``` ``` -------------------------------- ### IM4P.description Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-payload.md Gets or sets the human-readable description of the IM4P payload. ```APIDOC ## IM4P.description Property ### Description Gets or sets the human-readable description of the IM4P payload. ### Method - Getter: `description` - Setter: `description` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **description** (str) - The description string. Accepts None (converted to an empty string) or a string. ### Request Example ```python # Get description current_description = im4p.description # Set description im4p.description = 'Bootloader Stage 1' ``` ### Response #### Success Response (200) - **description** (str) - The description string. #### Response Example ```json "Bootloader Stage 1" ``` ``` -------------------------------- ### Initialize IMG4 Class Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Instantiate the IMG4 class either by parsing raw data from an existing file or by building a new IMG4 from its constituent components (IM4P, IM4M, and optionally IM4R). ```python import pyimg4 # Parse an existing IMG4 file with open('firmware.img4', 'rb') as f: img4 = pyimg4.IMG4(f.read()) # Build a new IMG4 from components payload = pyimg4.IM4P(fourcc='iBSS', description='Boot1', payload=boot_data) manifest = pyimg4.IM4M(manifest_bytes) img4 = pyimg4.IMG4(im4p=payload, im4m=manifest) ``` -------------------------------- ### IM4PData Constructor Options Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Construct IM4PData with raw firmware bytes, optionally specifying the uncompressed size and any extra appended data. ```python IM4PData( data: bytes, # Raw firmware (possibly compressed/encrypted) size: int = 0, # Uncompressed size (required for some formats) extra: Optional[bytes] = None, # Extra appended data ) ``` -------------------------------- ### IM4P.fourcc Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-payload.md Gets or sets the 4-character type identifier for the IM4P payload. ```APIDOC ## IM4P.fourcc Property ### Description Gets or sets the 4-character type identifier for the IM4P payload. ### Method - Getter: `fourcc` - Setter: `fourcc` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **fourcc** (Optional[str]) - The fourcc identifier. Accepts None or a 4-character string. Validation is performed on the setter. ### Request Example ```python # Get fourcc current_fourcc = im4p.fourcc # Set fourcc im4p.fourcc = 'iBEC' ``` ### Response #### Success Response (200) - **fourcc** (Optional[str]) - The fourcc identifier. #### Response Example ```json "iBEC" ``` ``` -------------------------------- ### Import pyimg4 Library Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/README.md Demonstrates the standard import statement for the pyimg4 library. This is the recommended way to import the library for use in your projects. ```python import pyimg4 ``` -------------------------------- ### IM4R Constructor Options Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Initialize an IM4R component by parsing existing data or by specifying the four-character code, which defaults to 'IM4R'. ```python IM4R( data: Optional[bytes] = None, # Parse existing IM4R fourcc: Optional[str] = 'IM4R', # Always IM4R ) ``` -------------------------------- ### Create Restore Info Blob Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Generate a restore info blob, which requires a boot nonce. This is typically used in restore processes. ```bash # Create restore info pyimg4 im4r create --boot-nonce 0x0123456789abcdef --output restore.im4r ``` -------------------------------- ### Get IM4PData Compression Type Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Access the compression property to determine the compression algorithm used for the payload. The type is an IntEnum. ```python @property def compression(self) -> Compression: # ... implementation details ... ``` -------------------------------- ### Get IM4PData Keybags Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Access the keybags property to retrieve a tuple of Keybag objects used for decryption. Returns an empty tuple if the payload is unencrypted. ```python @property def keybags(self) -> Tuple[Optional[Keybag]]: # ... implementation details ... ``` -------------------------------- ### Inspect Manifest Details Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Read and inspect details from an IM4M manifest file, including chip ID, board ID, ECID, nonces, and lists of images and properties. ```python import pyimg4 with open('manifest.im4m', 'rb') as f: im4m = pyimg4.IM4M(f.read()) # Get basic device info print(f"Chip ID: 0x{im4m.chip_id:04x}") print(f"Board ID: {im4m.board_id}") print(f"ECID: 0x{im4m.ecid:016x}") # Check nonces if im4m.apnonce: print(f"ApNonce: {im4m.apnonce.hex()}") if im4m.sepnonce: print(f"SepNonce: {im4m.sepnonce.hex()}") # List all images in manifest print(f"\nManifest images ({len(im4m.images)}):") for image in im4m.images: print(f" {image.fourcc}") if image.digest: print(f" Hash: {image.digest.hex()}") # List all manifest properties print(f"\nManifest properties:") for prop in im4m.properties: if isinstance(prop.value, bytes): print(f" {prop.fourcc}: {prop.value.hex()}") else: print(f" {prop.fourcc}: {prop.value}") ``` -------------------------------- ### Get IM4PData Raw Data Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Access the data property to retrieve the raw payload bytes, including any compression headers. This returns the internal buffer. ```python @property def data(self) -> bytes: # ... implementation details ... ``` -------------------------------- ### output Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Serializes the manifest to ASN.1 binary format. Returns the ASN.1-encoded IM4M bytes, including signature and certificates. Raises an error if no properties or images are set. ```APIDOC ## output ### Description Serialize manifest to ASN.1 binary format. ### Method ```python def output(self) -> bytes ``` ### Returns ASN.1-encoded IM4M bytes (with signature and certificates). ### Raises - `ValueError` — if no properties or no images are set. ### Example ```python im4m = pyimg4.IM4M(manifest_bytes) im4m.add_property(pyimg4.ManifestProperty(fourcc='TEST', value=42)) output_bytes = im4m.output() with open('updated_manifest.im4m', 'wb') as f: f.write(output_bytes) ``` ``` -------------------------------- ### Create IMG4 File Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Create a new IMG4 file from a payload binary, a FourCC code, and a manifest. Specify all required input and output files. ```bash # Create IMG4 from payload and manifest pyimg4 img4 create --input payload.bin --fourcc iBSS --im4m manifest.im4m --output new.img4 ``` -------------------------------- ### Get _Property Value Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Retrieves the value stored within the property. This can be of various types, including bytes, integers, strings, or any type compatible with ASN.1 encoding. ```python @property def value(self) -> Any ``` -------------------------------- ### Get Image4 Type Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/data-classes.md Identify the Image4 file type using the get_type method. This method returns the specific Image4 type class or None if not identified. ```python def get_type(self) -> Optional[Union[IMG4, IM4P, IM4M, IM4R]] ``` ```python import pyimg4 with open('image4.img4', 'rb') as f: data = pyimg4.Data(f.read()) img4_type = data.get_type() if img4_type == pyimg4.IMG4: print("This is a complete IMG4 file") ``` -------------------------------- ### Python Function Signatures with Type Hints Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/README.md Illustrates Python function signatures using type hints as per Python 3.9+ conventions. These hints aid in code clarity and static analysis. ```python def compress(self, compression: Compression) -> None ``` ```python def add_keybag(self, keybag: Keybag) -> None ``` ```python @property def compression(self) -> Compression ``` -------------------------------- ### Initialize IM4PData with Raw Payload Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Use this to parse raw firmware bytes into an IM4PData object. This is the most basic initialization. ```python import pyimg4 # Parse raw payload bytes raw_data = b'...' # firmware data payload = pyimg4.IM4PData(raw_data) ``` -------------------------------- ### Configure Compression Backend with Environment Variable Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Force the use of the lzfse compression backend on non-macOS platforms or explicitly on macOS by setting the PYIMG4_FORCE_LZFSE environment variable before importing pyimg4. ```python from os import getenv from sys import platform FORCE_LZFSE = getenv('PYIMG4_FORCE_LZFSE', None) is not None if platform != 'darwin' or FORCE_LZFSE is True: import lzfse # Define _lzfse_compress and _lzfse_decompress using lzfse module else: import apple_compress # Define _lzfse_compress and _lzfse_decompress using apple_compress module ``` ```python import os os.environ['PYIMG4_FORCE_LZFSE'] = '1' import pyimg4 # Now uses lzfse even on macOS ``` -------------------------------- ### Combine IM4P and IM4M into IMG4 Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Illustrates how to create an IMG4 file by combining an IM4P (payload) and an IM4M (manifest) using the overloaded '+' operator. ```python import pyimg4 # Create or load payload im4p = pyimg4.IM4P(fourcc='iBSS', description='Boot', payload=boot_bytes) # Load manifest with open('manifest.im4m', 'rb') as f: im4m = pyimg4.IM4M(f.read()) # Use the + operator (IM4P + IM4M = IMG4) img4 = im4p + im4m # Or equivalently img4 = im4m + im4p # Operator is symmetric with open('combined.img4', 'wb') as f: f.write(img4.output()) ``` -------------------------------- ### Keybag Constructor Options Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Create a Keybag by parsing existing data or by providing an initialization vector, an encryption key, and the keybag type (PRODUCTION or DEVELOPMENT). ```python Keybag( data: Optional[bytes] = None, # Parse existing keybag iv: bytes = None, # 16-byte initialization vector key: bytes = None, # 32-byte AES encryption key type_: KeybagType = KeybagType.PRODUCTION, # Key classification ) ``` -------------------------------- ### Build New IMG4 File Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/index.md Construct a new IMG4 file by creating an IM4P object for the payload and an IM4M object for the manifest, then combining them in the IMG4 constructor. ```python im4p = pyimg4.IM4P(fourcc='iBSS', description='Boot', payload=data) im4m = pyimg4.IM4M(manifest_bytes) img4 = pyimg4.IMG4(im4p=im4p, im4m=im4m) ``` -------------------------------- ### IM4R Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Initializes an IM4R object, optionally parsing ASN.1-encoded data. The boot nonce is automatically byte-reversed on construction. ```APIDOC ## IM4R Constructor ### Description Initializes an IM4R object, optionally parsing ASN.1-encoded data. The boot nonce is automatically byte-reversed on construction. ### Method ```python __init__(self, data: Optional[bytes] = None) ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **data** (bytes) - Optional - ASN.1-encoded IM4R bytes to parse ``` -------------------------------- ### IM4P Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-payload.md Use the constructor to either parse an existing IM4P file by providing its raw bytes, or to create a new IM4P object by specifying its fourcc, description, and payload data. Ensure either 'data' is provided or 'fourcc' along with 'description' or 'payload'. ```python import pyimg4 # Parse an existing IM4P file with open('payload.im4p', 'rb') as f: im4p = pyimg4.IM4P(f.read()) # Create a new IM4P with raw payload data im4p = pyimg4.IM4P( fourcc='iBSS', description='SecureBootStage1', payload=firmware_bytes ) ``` -------------------------------- ### Build a New IMG4 File Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Construct a new IMG4 file by combining payload, manifest, and optional restore information. The output can then be written to a file. ```python import pyimg4 # Read firmware data with open('boot.bin', 'rb') as f: boot_data = f.read() # Create payload im4p = pyimg4.IM4P( fourcc='iBSS', description='SecureBootStage1', payload=boot_data ) # Read manifest (or create a new one if you have the components) with open('manifest.im4m', 'rb') as f: im4m = pyimg4.IM4M(f.read()) # Optionally create restore info im4r = pyimg4.IM4R() im4r.boot_nonce = bytes.fromhex('0123456789abcdef') # Combine into IMG4 img4 = pyimg4.IMG4(im4p=im4p, im4m=im4m, im4r=im4r) # Write to file with open('boot.img4', 'wb') as f: f.write(img4.output()) ``` -------------------------------- ### IM4R.output Method Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Serializes the IM4R object to ASN.1 format, including automatic boot nonce reversal. Raises a ValueError if no properties are set. ```APIDOC ## IM4R.output Method ### Description Serializes the IM4R object to ASN.1 format, including automatic boot nonce reversal. Raises a ValueError if no properties are set. ### Method ```python def output(self) -> bytes ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **bytes** - ASN.1-encoded IM4R bytes. ``` -------------------------------- ### PyIMG4 CLI Usage Source: https://github.com/m1stadev/pyimg4/blob/master/README.md This shows the general command-line interface structure for PyIMG4, including available options and commands for different Image4 components. ```bash Usage: pyimg4 [OPTIONS] COMMAND [ARGS]... A Python CLI tool for parsing Apple's Image4 format. Options: --version Show the version and exit. -h, --help Show this message and exit. Commands: im4m Image4 manifest commands. im4p Image4 payload commands. im4r Image4 restore info commands. img4 Image4 commands. ``` -------------------------------- ### Parse Existing IMG4 File Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/index.md Use the IMG4 constructor to load an existing IMG4 file from binary data. Ensure the file is opened in binary read mode. ```python import pyimg4 img4 = pyimg4.IMG4(open('firmware.img4', 'rb').read()) ``` -------------------------------- ### Serialize IM4M Manifest to Binary Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Serializes the manifest into ASN.1 binary format, including signature and certificates. This method requires that at least one property and one image are set in the manifest; otherwise, it raises a ValueError. The output can be written to a file. ```python im4m = pyimg4.IM4M(manifest_bytes) im4m.add_property(pyimg4.ManifestProperty(fourcc='TEST', value=42)) output_bytes = im4m.output() with open('updated_manifest.im4m', 'wb') as f: f.write(output_bytes) ``` -------------------------------- ### Import PyIMG4 Classes and Types Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/index.md Import all public classes, types, enums, and exceptions from the top-level pyimg4 package. This is the standard way to begin using the library. ```python from pyimg4 import ( # Classes IMG4, IM4P, IM4PData, IM4M, IM4R, Keybag, ManifestProperty, ManifestImageProperties, PayloadProperty, Data, # Enums Compression, KeybagType, Payload, # Exceptions AESError, CompressionError, UnexpectedDataError, UnexpectedTagError, ) ``` -------------------------------- ### IMG4 Constructor Options Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Use this constructor to parse existing IMG4 data or build a new IMG4 component using its constituent parts (payload, manifest, restore info). ```python IMG4( data: Optional[bytes] = None, # Parse existing IMG4 im4p: Optional[Union[IM4P, bytes]] = None, # Payload component im4m: Optional[Union[IM4M, bytes]] = None, # Manifest component im4r: Optional[Union[IM4R, bytes]] = None, # Restore info (optional) ) ``` -------------------------------- ### Initialize _PropertyGroup Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Instantiate a _PropertyGroup object. Provide either ASN.1 encoded data for parsing or a FourCC string for building a new group. Both parameters cannot be omitted. ```python class _PropertyGroup(_PyIMG4): _property = _Property # Subclasses override this def __init__( self, data: Optional[bytes] = None, *, # Force keyword-only arguments fourcc: Optional[str] = None ) -> None ``` -------------------------------- ### Initialize Data Class Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/data-classes.md Instantiate the Data class with raw Image4 data. This is used for parsing Image4 files. ```python class Data(_PyIMG4): def __init__(self, data: Optional[bytes] = None) -> None ``` -------------------------------- ### Extract and Reassemble IMG4 Components Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/quick-start.md Demonstrates how to extract the payload (IM4P) and manifest (IM4M) from an IMG4 file and then reassemble them into a new IMG4 file. ```python import pyimg4 # Extract components from IMG4 with open('firmware.img4', 'rb') as f: img4 = pyimg4.IMG4(f.read()) # Save components separately with open('payload.im4p', 'wb') as f: f.write(img4.im4p.output()) with open('manifest.im4m', 'wb') as f: f.write(img4.im4m.output()) # Reassemble from components with open('payload.im4p', 'rb') as f: im4p = pyimg4.IM4P(f.read()) with open('manifest.im4m', 'rb') as f: im4m = pyimg4.IM4M(f.read()) # Combine back new_img4 = pyimg4.IMG4(im4p=im4p, im4m=im4m) ``` -------------------------------- ### Serialize PyIMG4 Component to Bytes Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md The output() method serializes an Image4 component into bytes ready for file output. Subclasses must implement this method. ```python im4p = pyimg4.IM4P(fourcc='iBSS', description='Boot', payload=firmware) binary = im4p.output() with open('payload.im4p', 'wb') as f: f.write(binary) ``` -------------------------------- ### Create IM4P with Compressed Payload Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/examples.md Create an IM4P file with a compressed payload using LZSS or LZFSE compression. The script reports original, compressed, and ratio sizes. ```python #!/usr/bin/env python3 import pyimg4 from pathlib import Path def create_compressed_im4p(data_path, fourcc, description, output_path, compression_type): """Create IM4P with specified compression.""" # Read firmware data firmware_data = Path(data_path).read_bytes() # Create IM4P im4p = pyimg4.IM4P( fourcc=fourcc, description=description, payload=firmware_data ) # Apply compression if compression_type == 'lzss': comp = pyimg4.Compression.LZSS elif compression_type == 'lzfse': comp = pyimg4.Compression.LZFSE else: raise ValueError(f"Unknown compression: {compression_type}") print(f"Compressing with {comp.name}...") im4p.payload.compress(comp) # Report sizes print(f"Original: {len(firmware_data)} bytes") print(f"Compressed: {len(im4p.payload.data)} bytes") print(f"Ratio: {len(im4p.payload.data) / len(firmware_data) * 100:.1f}%") # Write Path(output_path).write_bytes(im4p.output()) print(f"Saved to: {output_path}") create_compressed_im4p( 'kernelcache.bin', 'krnl', 'Kernelcache', 'kernelcache.im4p', 'lzfse' ) ``` -------------------------------- ### _Property Class Initialization Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Initializes the base _Property class for IM4M key-value properties. It can accept data, a fourcc identifier, or a direct value. ```python class _Property(_PyIMG4): def __init__( self, data: Optional[bytes] = None, *, fourcc: Optional[str] = None, value: Any = None, ) -> None ``` -------------------------------- ### IMG4.output() Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/img4-complete.md Serializes the complete IMG4 object into its binary ASN.1 representation, suitable for writing to firmware files. This method requires that the IM4P and IM4M components have been set. ```APIDOC ## output() ### Description Serializes the complete IMG4 to binary format. ### Method Signature ```python def output(self) -> bytes ``` ### Returns ASN.1-encoded IMG4 bytes suitable for writing to firmware files. ### Raises - `ValueError` — if IM4P or IM4M not set before output - Parsing exceptions if component serialization fails ### Example ```python img4 = pyimg4.IMG4(im4p=payload, im4m=manifest) with open('firmware.img4', 'wb') as f: f.write(img4.output()) ``` ``` -------------------------------- ### PyIMG4 Parser State Initialization Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Each Image4 object maintains its own ASN.1 decoder and encoder instances for thread-safe operation. ```python class _PyIMG4: def __init__(self, data: Optional[bytes] = None) -> None: self._data = data self._decoder = asn1.Decoder() # Per-instance decoder self._encoder = asn1.Encoder() # Per-instance encoder ``` -------------------------------- ### images Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Retrieves the image components within the manifest, such as iBoot, iBEC, and kernelcache. ```APIDOC ## images Property ### Description Retrieves the image components within the manifest, such as iBoot, iBEC, and kernelcache. ### Method images ### Parameters None ### Request Example None ### Response #### Success Response (200) - **images** (Tuple[Optional[ManifestImageProperties]]) - Tuple of ManifestImageProperties objects (each with DGST hash and metadata). #### Response Example ```python manifest = pyimg4.IM4M(data) for img_props in manifest.images: if img_props: print(f"Image Digest: {img_props.digest}, Metadata: {img_props.metadata}") ``` ``` -------------------------------- ### IM4PData Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Initializes an IM4PData object with raw payload data. It automatically detects compression and handles uncompressed size and extra data. ```APIDOC ## IM4PData Constructor ### Description Initializes an IM4PData object with raw payload data. It automatically detects compression and handles uncompressed size and extra data. ### Signature ```python IM4PData(data: bytes, *, size: int = 0, extra: Optional[bytes] = None) ``` ### Parameters #### Parameters - **data** (bytes) - Required - Raw payload data (possibly compressed/encrypted) - **size** (int) - Optional - Uncompressed data size (required if LZFSE-compressed). Defaults to 0. - **extra** (Optional[bytes]) - Optional - Extra data appended (e.g., KPP for older iOS kernels). Defaults to None. ### Initialization Process 1. Detects compression type from data headers. 2. For LZSS: parses complzss header to extract uncompressed size and optional extra data. 3. For LZFSE: decompresses to determine uncompressed size. 4. For uncompressed: uses provided `size` parameter. ### Example ```python import pyimg4 # Parse raw payload bytes raw_data = b'...' # firmware data payload = pyimg4.IM4PData(raw_data) # With known uncompressed size (for LZFSE) payload = pyimg4.IM4PData(lzfse_data, size=10485760) ``` ``` -------------------------------- ### Initialize IM4PData with LZFSE Compressed Data and Size Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Initialize IM4PData when the payload is LZFSE compressed and the uncompressed size is known. This is required for LZFSE payloads. ```python import pyimg4 # With known uncompressed size (for LZFSE) payload = pyimg4.IM4PData(lzfse_data, size=10485760) ``` -------------------------------- ### Initialize _Property Class Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Initializes a _Property object. Use 'data' for parsing existing ASN.1 encoded properties, or 'fourcc' and 'value' to build a new property. Both modes cannot be provided simultaneously. ```python class _Property(_PyIMG4): def __init__( self, data: Optional[bytes] = None, *, fourcc: Optional[str] = None, value: Any = None, ) -> None ``` -------------------------------- ### properties Property Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Retrieves device-level manifest properties, including CHIP, ECID, BNCH, and snon. ```APIDOC ## properties Property ### Description Retrieves device-level manifest properties, including CHIP, ECID, BNCH, and snon. ### Method properties ### Parameters None ### Request Example None ### Response #### Success Response (200) - **properties** (Tuple[Optional[ManifestProperty]]) - Tuple of ManifestProperty objects attached to MANP section. #### Response Example ```python manifest = pyimg4.IM4M(data) for prop in manifest.properties: if prop: print(f"Property: {prop.key}, Value: {prop.value}") ``` ``` -------------------------------- ### Import Types from Top-Level Package Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/types.md Illustrates the equivalent import statements for accessing pyimg4 types directly from the package or from the internal types module. ```python # Equivalent to: from pyimg4.types import Compression, KeybagType, Payload # Is the same as: from pyimg4 import Compression, KeybagType, Payload ``` -------------------------------- ### Keybag Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Initialize a Keybag object by parsing ASN.1 encoded data or by providing the IV and key directly. Ensure either 'data' is provided or both 'iv' and 'key' are supplied. ```python class Keybag(_PyIMG4): def __init__( self, data: Optional[bytes] = None, *, iv: bytes = None, key: bytes = None, type_: KeybagType = KeybagType.PRODUCTION, ) -> None ``` -------------------------------- ### Validate IMG4 Against Build Manifest Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/examples.md Verifies an IMG4 file against a BuildManifest.plist by matching board and chip IDs and checking component hashes. Returns True if all components are verified, False otherwise. Requires paths to the IMG4 file and the build manifest. ```python #!/usr/bin/env python3 import pyimg4 import plistlib from pathlib import Path def validate_img4(img4_path, build_manifest_path): """Verify IMG4 against BuildManifest.plist.""" img4 = pyimg4.IMG4(Path(img4_path).read_bytes()) manifest_data = plistlib.loads(Path(build_manifest_path).read_bytes()) # Find matching build identity for identity in manifest_data['BuildIdentities']: if (int(identity['ApBoardID'], 16) == img4.im4m.board_id and int(identity['ApChipID'], 16) == img4.im4m.chip_id): print(f"Found matching identity:") print(f" Device: {identity['Info']['DeviceClass']}") print(f" Build: {identity['Info']['BuildNumber']}") # Verify component hashes all_valid = True for name, info in identity['Manifest'].items(): if 'Digest' not in info: continue expected_hash = info['Digest'] found = any( img.digest == expected_hash for img in img4.im4m.images ) status = "✓" if found else "✗" print(f" {status} {name}") if not found: all_valid = False if all_valid: print("\n✓ All components verified!") else: print("\n✗ Some components do not match") return all_valid print("No matching build identity found") return False validate_img4('firmware.img4', 'BuildManifest.plist') ``` -------------------------------- ### Add Boot Nonce to Existing IMG4 Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/examples.md Add or update the boot nonce in an existing IMG4 file. This is often required for firmware signing processes. ```python #!/usr/bin/env python3 import pyimg4 from pathlib import Path def add_boot_nonce(img4_path, boot_nonce_hex, output_path): """Add or update boot nonce in IMG4.""" img4 = pyimg4.IMG4(Path(img4_path).read_bytes()) # Parse nonce nonce = bytes.fromhex(boot_nonce_hex.replace('0x', '')) # Create or update IM4R if img4.im4r is None: img4.im4r = pyimg4.IM4R() img4.im4r.boot_nonce = nonce # Write Path(output_path).write_bytes(img4.output()) print(f"Updated IMG4 with boot nonce: {output_path}") add_boot_nonce('firmware.img4', '0xdeadbeefcafebabe', 'with_nonce.img4') ``` -------------------------------- ### Define ManifestProperty Class Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Defines the ManifestProperty class, inheriting from _Property, to store IM4M manifest-level key-value pairs. ```python class ManifestProperty(_Property): pass ``` -------------------------------- ### IM4R Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md A subclass of `_PropertyGroup` designed for handling restore information. It specializes in boot nonce handling, including automatic byte reversal. ```APIDOC ## IM4R ### Description Subclass of `_PropertyGroup` for restore info. Specializes in boot nonce handling with automatic byte reversal. ### Class Signature ```python class IM4R(_PropertyGroup): _property = RestoreProperty ``` ``` -------------------------------- ### IM4M Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md This constructor is used exclusively for parsing ASN.1-encoded manifest data; it does not support building new IM4M components. ```python IM4M(data: bytes) # ASN.1-encoded manifest (no build mode) ``` -------------------------------- ### _Property Initialization Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4m-manifest.md Initializes a _Property object, which serves as the base class for key-value properties in Image4 structures. It can be initialized with data, a fourcc identifier, or a value. ```APIDOC ## _Property.__init__ ### Description Base class for key-value properties in Image4 structures. ### Method ```python def __init__( self, data: Optional[bytes] = None, *, fourcc: Optional[str] = None, value: Any = None, ) -> None ``` ### Parameters #### Parameters - **data** (bytes) - Optional - ASN.1-encoded property bytes - **fourcc** (str) - Optional - 4-character property identifier - **value** (Any) - Optional - Property value (bytes, int, etc.) ``` -------------------------------- ### IM4PData Constructor Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/configuration.md Represents the raw firmware data within an IM4P object. It holds the actual payload, which can be compressed or encrypted. ```APIDOC ## IM4PData Constructor ### Description Represents the raw firmware data, potentially compressed or encrypted, along with its uncompressed size and optional extra data. ### Parameters - **data** (bytes) - Required - The raw firmware data. - **size** (int) - Optional - Defaults to 0. The uncompressed size of the firmware data, required for some formats. - **extra** (Optional[bytes]) - Optional - Any extra data appended to the firmware. ``` -------------------------------- ### output Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/im4p-data.md Generates the serialization format of the IM4P payload as a Payload tuple. This tuple contains the payload data and its associated keybags. ```APIDOC ## output ### Description Generate serialization format (Payload tuple). ### Method ```python def output(self) -> Payload ``` ### Returns: `Payload` named tuple with fields: - `data`: payload bytes (including extra if present) - `keybags`: ASN.1-encoded keybag sequence bytes, or None if unencrypted ### Example: ```python payload_obj = im4p_data.output() # payload_obj.data contains the firmware # payload_obj.keybags contains ASN.1 keybag encoding or None ``` ``` -------------------------------- ### output Source: https://github.com/m1stadev/pyimg4/blob/master/_autodocs/api-reference/base-classes.md Abstract method that must be implemented by subclasses to serialize the component into bytes. This method is used for file output. ```APIDOC ## output ### Description Abstract method for serialization (overridden in subclasses). ### Method ```python def output(self) -> bytes ``` ### Returns Serialized bytes ready for file output. ### Raises Must be implemented by subclasses; base implementation returns `self._data`. ### Example ```python im4p = pyimg4.IM4P(fourcc='iBSS', description='Boot', payload=firmware) binary = im4p.output() with open('payload.im4p', 'wb') as f: f.write(binary) ``` ```