mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-02 02:34:29 +00:00
* fix: build
* fix: remove [trusted=yes] from Havoc apt source
The inline [trusted=yes] option can cause issues with Sileo's
source parser. The apt-get calls already use AllowUnauthenticated
flags, making it redundant.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix: main actor crash in VPhoneControl + IPA extraction failures
VPhoneControl: pending request handlers are @MainActor-isolated closures
but were called from DispatchQueue.global() in the read loop and timeout
handler, causing dispatch_assert_queue_fail crashes. Wrap all
pending.handler() calls in DispatchQueue.main.async.
unarchive: the recent ARCHIVE_EXTRACT_SECURE_* hardening (ef02d50) broke
IPA extraction on iOS because:
- SECURE_NOABSOLUTEPATHS: we set absolute output paths on entries
- SECURE_SYMLINKS: iOS system paths (/var, /tmp) are symlinks
- archive_write_header failures were silently swallowed due to if/else if
structure, making extraction report success with no files extracted
Fix by keeping only SECURE_NODOTDOT, resolving symlinks in extraction
path, fixing header error handling, removing unnecessary ACL/FFLAGS
flags, and surfacing libarchive errors in the install response.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* remove dropbear SSH daemon from guest
Drop all dropbear setup: LaunchDaemon plist injection, host key
generation, daemon deployment, and SSH availability messages.
Guest communication is handled by vphoned over vsock.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* feat: liblaunch compat stub + automatic JB first-boot setup
liblaunch_compat.dylib: stub exporting _launch_active_user_switch
(missing from PCC VM's libSystem.B.dylib) so procursus binaries
like launchctl can load. Deployed to /cores/, loaded via
DYLD_INSERT_LIBRARIES in LaunchDaemon environment and JB profile.
vphone_jb_setup.sh: first-boot script replacing the SSH-based
cfw_install_jb_post.sh. Runs as a LaunchDaemon on first normal
boot and performs all JB finalization: /var/jb symlink,
prep_bootstrap, markers, Sileo, apt setup, TrollStore Lite.
Idempotent with done marker. Logs to /var/log/vphone_jb_setup.log.
Removes the cfw_install_jb_finalize make target and the entire
SSH/iproxy/sshpass-based post-boot flow from setup_machine.sh.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* chore: update AGENTS.md firmware table, gitignore build artifacts
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix: launchctl wrapper uses absolute path + timeout to prevent hangs
- Use absolute path to launchctl.real instead of relative dirname,
fixing "not found" when called via /var/jb/bin/launchctl symlink
- Add 5s timeout so launchctl doesn't hang when launchd is
unresponsive on PCC VMs — always exits 0 for dpkg postinst compat
- Symlink /var/jb/bin/launchctl -> /var/jb/usr/bin/launchctl so both
paths work (openssh postinst uses the /bin/ path)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix: replace liblaunch_compat dylib stub with iosbinpack64 launchctl symlink
Procursus launchctl crashes on PCC VMs due to missing
_launch_active_user_switch symbol. Rather than a custom dylib stub,
simply symlink iosbinpack64's launchctl into /var/jb — it talks to
launchd fine and always exits 0, which is all dpkg scripts need.
- Remove liblaunch_compat.c, its build target, signing, and deployment
- Remove DYLD_INSERT_LIBRARIES from setup script and plist
- Replace launchctl wrapper with symlinks to /iosbinpack64/bin/launchctl
- Both /var/jb/usr/bin/launchctl and /var/jb/bin/launchctl are covered
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>
138 lines
4.9 KiB
Python
Executable File
138 lines
4.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
cfw.py — Dynamic binary patching for CFW installation on vphone600.
|
|
|
|
Uses capstone for disassembly-based anchoring and keystone for instruction
|
|
assembly, producing reliable, upgrade-proof patches.
|
|
|
|
Called by cfw_install.sh during CFW installation.
|
|
|
|
Commands:
|
|
cryptex-paths <BuildManifest.plist>
|
|
Print SystemOS and AppOS DMG paths from BuildManifest.
|
|
|
|
patch-seputil <binary>
|
|
Patch seputil gigalocker UUID to "AA".
|
|
|
|
patch-launchd-cache-loader <binary>
|
|
NOP the cache validation check in launchd_cache_loader.
|
|
|
|
patch-mobileactivationd <binary>
|
|
Patch -[DeviceType should_hactivate] to always return true.
|
|
|
|
patch-launchd-jetsam <binary>
|
|
Patch launchd jetsam panic guard to avoid initproc crash loop.
|
|
|
|
inject-daemons <launchd.plist> <daemon_dir>
|
|
Inject bash/trollvnc into launchd.plist.
|
|
|
|
inject-dylib <binary> <dylib_path>
|
|
Inject LC_LOAD_DYLIB into Mach-O binary (thin or universal).
|
|
Equivalent to: optool install -c load -p <dylib_path> -t <binary>
|
|
|
|
Dependencies:
|
|
pip install capstone keystone-engine
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
# When run as `python3 scripts/patchers/cfw.py`, __name__ is "__main__" and
|
|
# relative imports fail. Add the parent directory to sys.path so we can import
|
|
# from the patchers package using absolute imports.
|
|
if __name__ == "__main__":
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
from patchers.cfw_patch_seputil import patch_seputil
|
|
from patchers.cfw_patch_cache_loader import patch_launchd_cache_loader
|
|
from patchers.cfw_patch_mobileactivationd import patch_mobileactivationd
|
|
from patchers.cfw_patch_jetsam import patch_launchd_jetsam
|
|
from patchers.cfw_daemons import parse_cryptex_paths, inject_daemons
|
|
else:
|
|
from .cfw_patch_seputil import patch_seputil
|
|
from .cfw_patch_cache_loader import patch_launchd_cache_loader
|
|
from .cfw_patch_mobileactivationd import patch_mobileactivationd
|
|
from .cfw_patch_jetsam import patch_launchd_jetsam
|
|
from .cfw_daemons import parse_cryptex_paths, inject_daemons
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print(__doc__)
|
|
sys.exit(1)
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == "cryptex-paths":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: patch_cfw.py cryptex-paths <BuildManifest.plist>")
|
|
sys.exit(1)
|
|
sysos, appos = parse_cryptex_paths(sys.argv[2])
|
|
print(sysos)
|
|
print(appos)
|
|
|
|
elif cmd == "patch-seputil":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: patch_cfw.py patch-seputil <binary>")
|
|
sys.exit(1)
|
|
if not patch_seputil(sys.argv[2]):
|
|
sys.exit(1)
|
|
|
|
elif cmd == "patch-launchd-cache-loader":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: patch_cfw.py patch-launchd-cache-loader <binary>")
|
|
sys.exit(1)
|
|
if not patch_launchd_cache_loader(sys.argv[2]):
|
|
sys.exit(1)
|
|
|
|
elif cmd == "patch-mobileactivationd":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: patch_cfw.py patch-mobileactivationd <binary>")
|
|
sys.exit(1)
|
|
if not patch_mobileactivationd(sys.argv[2]):
|
|
sys.exit(1)
|
|
|
|
elif cmd == "patch-launchd-jetsam":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: patch_cfw.py patch-launchd-jetsam <binary>")
|
|
sys.exit(1)
|
|
if not patch_launchd_jetsam(sys.argv[2]):
|
|
sys.exit(1)
|
|
|
|
elif cmd == "inject-daemons":
|
|
if len(sys.argv) < 4:
|
|
print("Usage: patch_cfw.py inject-daemons <launchd.plist> <daemon_dir>")
|
|
sys.exit(1)
|
|
inject_daemons(sys.argv[2], sys.argv[3])
|
|
|
|
elif cmd == "inject-dylib":
|
|
if len(sys.argv) < 4:
|
|
print("Usage: patch_cfw.py inject-dylib <binary> <dylib_path>")
|
|
sys.exit(1)
|
|
import subprocess, shutil
|
|
insert_dylib_bin = shutil.which("insert_dylib")
|
|
if not insert_dylib_bin:
|
|
# Check .tools/bin/ relative to project root
|
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
candidate = os.path.join(project_root, ".tools", "bin", "insert_dylib")
|
|
if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
|
|
insert_dylib_bin = candidate
|
|
if not insert_dylib_bin:
|
|
print("[-] insert_dylib not found. Run: make setup_tools")
|
|
sys.exit(1)
|
|
rc = subprocess.run(
|
|
[insert_dylib_bin, "--weak", "--inplace", "--all-yes", sys.argv[3], sys.argv[2]],
|
|
).returncode
|
|
if rc != 0:
|
|
sys.exit(rc)
|
|
|
|
else:
|
|
print(f"Unknown command: {cmd}")
|
|
print("Commands: cryptex-paths, patch-seputil, patch-launchd-cache-loader,")
|
|
print(" patch-mobileactivationd, patch-launchd-jetsam,")
|
|
print(" inject-daemons, inject-dylib")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|