ipapatch

repository·main·Indexed 41 days ago

https://github.com/asdfzxcvbn/ipapatch

A cross-platform CLI tool for patching iOS IPAs and their plugins to fix system-level issues such as share sheet or widget malfunctions. Written in Go, it uses native load command injection and zxPluginsInject to remain portable across macOS, Linux, and iOS, with Windows support starting from v2.1.0.

Tokens
2.8K
Snippets
8
Records
11
Agent score
99%

What's inside ipapatch

  1. Overview of ipapatch

    main

    ipapatch is a CLI tool designed to patch IPAs and their plugins. It is used to fix issues related to the share sheet, widgets, VPNs, and other iOS-specific functionalities.

    By default, it uses zxPluginsInject (a rewrite of the original Chocolate Fluffy patch) to perform injections. Because it is written in Go and utilizes native load command injection, it is cross-compatible with macOS, Linux, and iOS. Windows support is expected to work correctly from version v2.1.0 onwards.

  2. Use the ipapatch CLI

    main

    Run ipapatch with the required --input flag to specify the IPA file you wish to patch. You can specify an output path, overwrite the original file, or target only plugin binaries.

    # Basic usage: patch an IPA and save to a new file
    ipapatch --input input.ipa --output patched.ipa
    
    # Overwrite the original file (inplace)
    ipapatch --input input.ipa --inplace
    
    # Patch only the plugin binaries
    ipapatch --input input.ipa --output patched.ipa --plugins-only
  3. Install ipapatch

    main

    To use ipapatch, download the latest binaries from the official release page.

    As of version v2.0.0, ipapatch is a fully portable, native binary and no longer requires the zip command as an external dependency. However, if you encounter issues with certain signing apps or tools being unable to extract the output IPA, you can explicitly use the --zip flag to utilize the system's zip CLI tool.

  4. Use the ipapatch CLI

    main

    The ipapatch tool is a CLI utility used to apply patches. It requires an --input file and allows for specifying an --output file, or using --inplace to overwrite the input file. It also supports using a specific dynamic library via --dylib and can use zip for compression if --zip is enabled.

    Key CLI behaviors:

    • Input/Output: If --output is not provided, the tool will prompt to overwrite the input file unless --inplace or --no-confirm is used.
    • In-place mode: Using --inplace sets the output destination to be the same as the input.
    • Zip support: If --zip is requested, the zip command must be available in your system's PATH.
    • Dylib: If --dylib is provided, the tool verifies that the specified path exists before proceeding.
    # Example usage (assuming binary is named ipapatch)
    # Patch an input file and save to a new output file
    ./ipapatch --input my_file.ipa --output patched_file.ipa
    
    # Patch an input file in-place (overwriting the original)
    ./ipapatch --input my_file.ipa --inplace
    
    # Patch using a specific dylib and enable zip compression
    ./ipapatch --input my_file.ipa --dylib my_plugin.dylib --zip
  5. Reference the ipapatch CLI flags

    main

    The following flags are available for the ipapatch command:

    FlagDescription
    --input <path>The path to the IPA file to patch (Required)
    --output <path>The path to the patched IPA file to create
    --dylib <path>The path to a custom .dylib to use instead of the embedded zxPluginsInject
    --inplaceOverwrites the input file (takes priority over --output)
    --noconfirmSkips interactive confirmation when overwriting files
    --plugins-onlyOnly injects into plugin binaries, skipping the main executable
    --zipUses the system zip CLI tool for file removal (useful if output extraction fails)
    --help, -hShow usage and exit
    --versionShow version and exit
    usage: ipapatch [-h/--help] --input <path> [--output <path] [--dylib <path>] [--inplace] [--noconfirm] [--plugins-only] [--zip] [--version]
    
    flags:
      --input path      the path to the ipa file to patch
      --output path     the path to the patched ipa file to create
      --dylib path      the path to the dylib to use instead of the embedded zxPluginsInject
      --inplace         takes priority over --output, use this to overwrite the input file
      --noconfirm       skip interactive confirmation when not using --inplace, overwriting a file that already exists, etc
      --plugins-only    only inject into plugin binaries (not the main executable)
      --zip             use the zip cli tool to remove files (shouldnt be needed anymore)
    
    info:
      -h, --help        show usage and exit
      --version         show version and exit
  6. Patch an executable and its plugins using Patch()

    main

    The Patch function is the core entrypoint for applying modifications to an IPA (iOS App Store Package). It performs the following workflow:

    1. Extraction and Injection: It extracts necessary components and injects them into a temporary directory using injectAll.
    2. File Preparation: If the Output path differs from the Input path, it copies the input file to the output destination.
    3. Zip Management: If UseZip is enabled, it uses the system zip command to manage files within the output archive.
    4. IPA Re-assembly: It opens the output file and uses a zip updater to append the injected files and any specified dynamic libraries (Dylib) back into the IPA structure (specifically under Payload/[AppName]/Frameworks/).
    5. Plugin Injection: It automatically injects zxPluginsInject.dylib into the IPA's Frameworks directory.

    To use this function, you must provide an Args struct containing the input/output paths, injection settings, and optional dylib paths.

    err := Patch(args)
    if err != nil {
    	// handle error
    }
  7. Reference the ipapatch CLI flags

    main

    The following flags are available for the ipapatch command:

    flags:
      --input path      the path to the ipa file to patch
      --output path     the path to the patched ipa file to create
      --dylib path      the path to the dylib to use instead of the embedded zxPluginsInject
      --inplace         takes priority over --output, use this to overwrite the input file
      --noconfirm       skip interactive confirmation when not using --inplace, overwriting a file that already exists, etc
      --plugins-only    only inject into plugin binaries (not the main executable)
      --zip             use the zip cli tool to remove files (shouldnt be needed anymore)
    
    info:
      -h, --help        show usage and exit
      --version         show version and exit
  8. Configure Patch arguments via Args struct

    main

    The Patch function requires an Args object to define the patching operation. Based on the implementation in patch.go, the following fields are utilized:

    • Input: The path to the source IPA file.
    • Output: The destination path for the patched IPA.
    • UseZip: A boolean flag that determines whether to use the system zip command for file manipulation.
    • Dylib: An optional string path to an additional dynamic library that should be injected into the Payload/[AppName]/Frameworks/ directory of the IPA.

    Note: The appName is derived from the file structure during the patching process.

  9. Handle IPA metadata errors

    main

    When working with IPA files, the following error variables are used to indicate missing components:

    • ErrNoPlist: Returned when no .app/Info.plist is found in the IPA (and pluginsOnly mode is disabled).
    • ErrNoPlugins: Returned when no .appex/Info.plist files are found in the IPA (when pluginsOnly mode is enabled).
    var (
    	ErrNoPlist   = errors.New("no Info.plist found in ipa")
    	ErrNoPlugins = errors.New("no plugins found")
    )
  10. Reference the ipapatch CLI arguments

    main

    The following arguments are used to control the behavior of the ipapatch command line interface.

    # Note: Exact flag names and descriptions are derived from the Args struct implementation in main.go
    
    --input <path>      (Required) The path to the input file to be patched.
    --output <path>     The path where the patched file will be saved.
    --inplace           Overwrite the input file with the patched version.
    --dylib <path>      Path to a dynamic library (.dylib) to inject.
    --zip               Use the 'zip' command to compress the output.
    --no-confirm        Disable interactive prompts for overwriting files.
    --help              Show help text.
    --version           Show version information.
  11. Use PlistInfo to parse IPA metadata

    main

    The PlistInfo struct is used to unmarshal and represent metadata extracted from an Info.plist file within an IPA. It specifically captures the main executable name and the bundle identifier required for library injection.

    To use it, you can pass the raw bytes of an Info.plist file to a plist unmarshaler (like howett.net/plist) targeting this struct.

    type PlistInfo struct {
    	Executable string `plist:"CFBundleExecutable"` 
    	BundleID   string `plist:"CFBundleIdentifier"` 
    }