Skip to content
jakeajamesPublic

About

No description, website, or topics provided.

Resources

Stars

58 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Troy

Troy is a rootless semi-jailbreak for iOS 27 using the TSS cryptex "bug" (allowing any cryptex to be signed for retail devices). It installs a persistent Procursus bootstrap at /var/jb and provides process launching, tweak injection, trust-cache loading, and Mach-O development tools.

DISCLAIMERS: The bug is now patched and Apple no longer signs custom Cryptex1 images, so new Troy builds cannot be personalized or installed on any device or iOS version. The code was written with AI assistance.

The cryptex build & deploy code has been redacted, to be revealed at a later time.

Features

  • Persistent Procursus environment stored on the active Preboot volume.
  • During a userspace reboot, Troy redirects launchd's setexec to the resigned /var/jb/sbin/launchd, which becomes the new PID 1 with Troy's launch hook already loaded.
  • The replacement launchd bind-mounts a copy of /usr/lib containing Troy's patched dyld and exec-hook.dylib over /usr/lib.
  • The bootstrap, replacement launchd, patched dyld, and launch daemons are kept in Preboot so they remain available if the Cryptex unmounts.
  • OpenSSH on ports 22 and 2222.
  • Sileo, ElleKit, PreferenceLoader, and OpenSSH installed through dpkg.
  • Launch hooks for posix_spawn, posix_spawnp, and execve.
  • Direct execution of trusted /var/jb binaries and a troy-execmain fallback that loads unsupported Mach-O executables into its own process and calls their entry point with the original arguments and environment.
  • Redirection of stock executable paths to matching /var/jb mirrors while preserving the original process identity exposed to user space.
  • A privileged troyd service that marks suspended children as debugged, answers executable trust queries, and lets approved setuid tools run commands as root, passing their fds to the child and returning its exit status.
  • Dylib injection into running processes.
  • A sandbox extension gives processes carrying Troy's launch hooks read access to /var/jb.
  • Troy's patched dyld allows DYLD_INSERT_LIBRARIES to work without get-task-allow and lets processes marked as debugged by troyd load unsigned executable code through its mmap and fcntl patches. It also allows main executables to be loaded as if they were libraries (otherwise, dylibify is required to convert executables to libraries)
  • troy-sign-index scan adds the entitlements required for dylib injection, resigns stock executables in memory, and records their cdhashes for the trust cache. troy-sign-index materialize writes those transformed executables as /var/jb mirrors.
  • A trust cache shipped with the Cryptex, plus creation and loading of additional personalized Cryptex1 trust caches on-device.

Build

Put a copy of your device's launchd and dyld inside Resources. Then run Scripts/build_cryptex.sh locally on a Mac with cryptexctl.research installed or use the Build Troy Cryptex GitHub Actions workflow. Both produce an unsigned Cryptex bundle, build summary, trust-cache dump, and SSH key pair.

Set TROY_AUTHORIZED_KEYS to embed an existing authorized_keys file. Without it, the build generates a key pair. TROY_DEBUG controls detailed launch-hook logging, but enabling it in the current build causes userspace reboot to stall on a black screen and eventually trigger a watchdog panic; leave it at the default value of 0. TROY_DAEMON_DEBUG separately controls troyd logging and defaults to 1.

Deploy

Place the unsigned artifact in out/ and connect the target device.

Optionally create an isolated Python environment:

python3 -m venv .venv
source .venv/bin/activate

Install the dependencies:

python3 -m pip install -r requirements.txt

Then deploy:

python3 Scripts/deploy.py

Persistent replacement:

python3 Scripts/deploy.py --persistent --replace

Use --udid DEVICE_UDID to select a device and --artifact PATH to select an artifact outside out/.

On first launch, troy-bootstrap installs the embedded Procursus tree under /private/preboot/<boot-manifest-hash>/troy/procursus, links /var/jb to it, prepares the root account for login and user lookup, installs the bundled Sileo, ElleKit, PreferenceLoader, and OpenSSH packages through dpkg, and registers troyd and OpenSSH to start from /var/jb after userspace reboots. Updates merge Troy-owned payload files without replacing mutable package and user data.

SSH accepts the generated key and initially permits the root password alpine. Change the password after installation.

Tools

troy-exec

Run an executable through Troy:

troy-exec /path/to/executable argument1 argument2

inject

Inject a dylib into a running process:

inject PID /absolute/path/to/library.dylib

Dylibs injected into launchd must already be trusted.

troy-trustcache-load

troy-trustcache-load [-v] trust PATH
troy-trustcache-load [-v] hashes FILE
troy-trustcache-load [-v] reload CACHE

-v enables verbose output, including scanned cdhashes, kernel trust-query results, the Cryptex1 nonce, ticket-cache activity, TSS requests, and trust-cache loading results.

Scan a file or directory and load a personalized trust cache for every signed Mach-O that is not already trusted:

troy-trustcache-load trust /var/jb/path

Load cdhashes from a text file:

troy-trustcache-load hashes /path/to/cdhashes.txt

Reload a cached signed response without contacting TSS:

troy-trustcache-load reload /var/jb/var/cache/troy/trustcache/CACHE

The default ticket cache is /var/jb/var/cache/troy/trustcache. Binaries used with dynamic trust caches must carry a valid ad-hoc signature, including a CodeDirectory with CS_ADHOC set.

troy-sign-index

troy-sign-index prepares stock executables for launch redirection and dylib injection. Its scan mode calculates resigned hashes and cdhashes for inclusion in Troy's trust cache without keeping modified copies:

troy-sign-index scan \
  --manifest /var/tmp/troy-system-machos.json \
  --cdhashes /var/tmp/troy-system-cdhashes.txt

With no roots specified, scan uses /Applications, /System/Applications, /System/Library/CoreServices, /System/Library/PrivateFrameworks, /usr/bin, /usr/libexec, and /usr/sbin. To scan specific roots, append each path after the --cdhashes output path:

troy-sign-index scan \
  --manifest /var/tmp/troy-system-machos.json \
  --cdhashes /var/tmp/troy-system-cdhashes.txt \
  /usr/libexec /usr/sbin

Its materialize mode writes a matching resigned mirror under /var/jb:

troy-sign-index materialize /usr/libexec/exampled

The default destination is /var/jb/<absolute source path>. Add generated system cdhashes to TrustCache/system-cdhashes.txt before building the Cryptex that will use the materialized files.

Launching

exec-hook.dylib propagates to eligible descendant processes and intercepts spawn and exec operations. For binaries under /var/jb, it asks troyd to check every cdhash against the kernel trust cache. Trusted binaries execute normally; other supported binaries are routed through troy-execmain. troyd attaches to suspended children, marks them as debugged, detaches, and resumes them.

The final build I personalized before signing stopped has a troyd that cannot open the AMFI user client. Because I can no longer personalize a new build, I did not bother to fix it. That existing installation checks /var/jb/etc/troy/trusted-cdhashes.bin instead of querying the kernel trust cache.

The lsd hook remains in the source tree but is not injected automatically. It was introduced when embedded app registration appeared to require an lsd entitlement bypass, disabled when that bypass proved unnecessary, re-enabled when an unidentified bug broke direct registration, and disabled again after the bug was found to be signing mistakenly stripping uicache entitlements and was fixed.

Limitations

Current Availability

  • New builds cannot be installed because Apple no longer personalizes custom Cryptex1 images.

Unfixed In My Final Build

  • TROY_DEBUG=1 can stall userspace reboot on a black screen and trigger a watchdog panic.
  • My existing installation uses /var/jb/etc/troy/trusted-cdhashes.bin because its troyd cannot query the kernel trust cache.
  • Dylibs injected into launchd must already be trusted.
  • LaunchServices database rebuilds do not automatically re-register apps from /var/jb; run uicache -a again afterward.

Restrictions

  • Troy operates entirely in userland and has no kernel read/write capability.
  • Mach-O files loaded in processes without CS_DEBUGGED or executables ran directly must carry a valid ad-hoc signature with the CS_ADHOC flag.
  • All non-Apple code must be authorized by a trust cache. Troy has no amfid patch because the kernel since iOS 15 (and now TXM) verifies provisioning profiles too instead of trusting amfid's result. Troy can run unsigned code through troy-exec or by injecting to a debugged process, but cannot grant that code arbitrary entitlements.

Repository Layout

  • Scripts/build_cryptex.sh: builds the unsigned Cryptex and bundled payload.
  • Scripts/deploy.py: personalizes and installs the Cryptex.
  • Sources/LaunchRedirect: launch hooks, troyd, IPC, and path translation.
  • Sources/ExecMainBinary: executable loader and dyld validation support.
  • Sources/troy-trustcache-load.m: on-device trust-cache personalization and loading.
  • Sources/troy-sign-index.mm: scanning, signing, and materialization.
  • Sources/troy-bootstrap.c: persistent bootstrap installation.
  • Sources/Injector: the modified opainject-derived injector core.
  • Tools/update-cdhash-index.c: merges cached trust-cache entries into the fallback cdhash index.
  • Scripts/attach_troyd.py and Scripts/lldb_remote_exports.py: helper functions to attach a debugger to troyd and use it to run code as root. I needed this because I messed up the bootstrap right before the bug was patched.

Credits

About

No description, website, or topics provided.

Resources

Stars

58 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages