ipa-forge
A generic, data-driven iOS IPA patcher framework: extract a user-supplied
.ipa, apply version-aware patches from external YAML definitions (binary
byte patches, resource replacement, dylib injection), and re-sign the result
into a standard-structure .ipa that AltStore Classic can install and
refresh on a real iPhone.
Documentation
Start at docs/README.md — the index.
| Doc | What it covers |
|---|---|
docs/adding-an-app.md |
Port a new app end-to-end (the "give me an IPA" playbook) |
docs/adding-a-feature.md |
Add a feature to a hook dylib (conventions) |
docs/usage.md |
End-to-end workflow, full CLI + GUI reference, signing identity/profile setup |
docs/patch-reference.md |
Complete patch-definition reference — every operation type, field, matching rule, and the hooks: block |
docs/troubleshooting.md |
Every error message mapped to its cause and fix |
docs/reverse-engineering.md |
forge analysis: class-dump, strings, symbols, security posture, version diffing for any IPA |
docs/architecture.md |
Design rationale, the 17-stage pipeline, hard constraints, hook verification (for developers) |
docs/extensibility.md |
How to add new patch operation types (for developers) |
docs/altstore_device_testing.md |
Manual AltStore Classic device-test checklist |
Worked patch sets
Current status (which features are shipped vs. beta/untested) is tracked in
STATE.md, not repeated here.
| Set | Runbook | Features | Repo |
|---|---|---|---|
| YouTube 21.32.4 | patches/youtube/PLAYBOOK.md |
patches/youtube/README.md |
nandan-varma/ipa-forge-patches-youtube (private) |
| Spotify 9.1.72 | patches/spotify/PLAYBOOK.md |
patches/spotify/README.md |
nandan-varma/ipa-forge-patches-spotify (private) |
| Instagram 442.0.0 | patches/instagram/PLAYBOOK.md |
patches/instagram/README.md |
nandan-varma/ipa-forge-patches-instagram (private) |
Quick start (novice — the GUI)
- Install:
python3 -m venv .venv && source .venv/bin/activate && pip install -e . - Launch the GUI:
forge gui→ open http://127.0.0.1:8765 - Drop your .ipa into the box. The GUI detects the app and the matching patch set, shows a small warning if the patch set targets a different version (patching is still allowed — hook verification is the safety net), and presents one Patch button.
- Download the patched IPA (unsigned — ready for AltStore).
No YAML editing, no signing identity, no provisioning profiles needed for the AltStore path.
Requirements
- macOS with Xcode Command Line Tools (
xcode-select -pshould print a path) -- signing requires Apple's owncodesign/securitytools and is not reimplemented. Everything up through patch dry-run also works on Linux; seedocs/extensibility.md. - Python 3.11+
- A codesigning identity in your Keychain (
security find-identity -v -p codesigning) and a matching.mobileprovision, obtained the normal way through Xcode or AltServer's own account pairing.
Install
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
This installs the forge CLI.
Quickstart
# Inspect an IPA's bundle id, version, and executable inventory
forge inspect path/to/App.ipa
# Validate structure without touching anything
forge validate path/to/App.ipa
# Dry-run a patch definition (no mutation, no signing; --identity/--profile optional)
forge patch --ipa path/to/App.ipa --patches patches.yaml \
--output patched.ipa --dry-run
# Patch and re-sign for real
forge patch --ipa path/to/App.ipa --patches patches.yaml \
--identity "Apple Development" --profile path/to/profile.mobileprovision \
--output patched.ipa --verbose
# Launch the local web GUI (wraps the same pipeline)
forge gui
--identity accepts either a full SHA-1 hash or a unique substring of the
identity's name (as shown by security find-identity -v -p codesigning) --
it fails loudly, listing candidates, if the substring is ambiguous or
matches nothing.
Try it against the checked-in synthetic test fixture (no real app required):
forge patch --ipa fixtures/synthetic_app.ipa --patches fixtures/patches/example.yaml \
--identity "Apple Development" --profile <your .mobileprovision> \
--output /tmp/patched.ipa --verbose
Writing a patch definition
target:
bundle_id: "com.example.synthetic"
version:
exact: "1.0.0" # or: { min: "1.0.0", max: "2.0.0" }
patches:
- id: "zero-marker-bytes"
type: binary_replace
executable: "TestApp"
arch: "arm64" # required for fat/universal binaries
pattern: "ca fe f0 0d" # space-separated hex, ?? = wildcard byte
replacement: "00 00 00 00"
expected_matches: 1 # fails loudly on 0 or >1 matches
- id: "swap-asset"
type: resource_replace # also: resource_add, resource_remove
path: "asset.txt" # bundle-relative
source: "assets/patched_asset.txt" # relative to the patch definition file
- id: "inject-hook"
type: dylib_inject
executable: "TestApp"
arch: "arm64"
install_name: "@rpath/libInjectable.dylib" # the dylib must already be in the bundle
load_command: "LC_LOAD_DYLIB" # or LC_LOAD_WEAK_DYLIB
- id: "set-verbose-logging"
type: plist_edit
action: "set" # or "remove" (no value needed)
key: "CFBundleDisplayName"
value: "Patched App"
path: "Info.plist" # bundle-relative; defaults to Info.plist
See fixtures/patches/example.yaml and fixtures/patches/example_dylib_inject.yaml
for complete, working examples run by the test suite against
fixtures/synthetic_app.ipa.
This is a teaser. The full reference — every operation type (binary_replace,
resource_replace/add/remove, dylib_inject, plist_edit), every field,
version-matching semantics, the dry-run gate, ordering rules, and a
common-mistakes checklist — is in
docs/patch-reference.md.
Getting certificates and provisioning profiles for AltStore
AltStore Classic re-signs and installs apps using your own Apple ID's
development credentials, obtained through AltServer's own pairing flow --
ipa-forge doesn't manage your Apple account. How to find your codesigning
identity and a matching .mobileprovision, and how ipa-forge selects
profiles (exact match, wildcard, per-extension), is documented in
docs/usage.md. In short:
- Pair AltServer with your device (or use a certificate + profile from your own Xcode account).
- Locate your identity:
security find-identity -v -p codesigning. - Locate a profile under
~/Library/MobileDevice/Provisioning Profiles/*.mobileprovision. - The profile's
application-identifiermust authorize the IPA's bundle id (exactly or via a wildcardTEAMID.*profile).
forge patch validates the profile up front (expiry, bundle-id match) and
fails with an actionable error before touching your IPA if it doesn't
qualify.
Testing
pytest tests/ # everything, including real codesign signing
pytest tests/ -m "not macos" # skip real-signing tests (e.g. on Linux)
fixtures/synthetic_app.ipa is a real, from-scratch iOS app built via
scripts/rebuild_fixture.sh against the iOS SDK -- a main executable, a
linked framework, an unlinked standalone dylib
(the dylib-injection target), and a resource file. It's checked in as a
binary artifact; re-run the script only if you need to change its shape.
Real-device AltStore Classic install/launch/refresh cannot be automated in
this environment -- see
docs/altstore_device_testing.md for the
manual checklist.
Disclaimer
For educational and research purposes only. You must supply your own legally obtained .ipa. Not affiliated with Apple, Google/YouTube, Spotify, or Meta/Instagram. No copyrighted binaries are distributed — patch definitions only. Sideloading may violate an app's Terms of Service.
License
GPLv3-or-later. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ipa_forge-0.1.0.tar.gz.
File metadata
- Download URL: ipa_forge-0.1.0.tar.gz
- Upload date:
- Size: 329.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07f7c82f818d2c0d883c3da3cd4feafc3d2758eace0ddff41e8d195b127d70f3
|
|
| MD5 |
3190f260b77d404e5499b65991fb776f
|
|
| BLAKE2b-256 |
3906567aae2debe3c19a1b60ac98bb9de5b8b5cf79624e39d20288ad32d216ee
|
File details
Details for the file ipa_forge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ipa_forge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 109.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62754107110b6860ca853b5cd9cf3ac1fbc87098de2f299c94f287002c31f57a
|
|
| MD5 |
4ea8c2be559a4b44b66d1a2357d26f34
|
|
| BLAKE2b-256 |
b977faaffe43e90a473d8e39a507ab82e922e6a03f4b35afb668366ec3e60e82
|