mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-10-01 23:54:35 +08:00
Name every patch {component}-{effect}-{name}
The 117 bundled patch identifiers had grown five naming schemes
(kernel.x, jb.x, kernelcache_jb.x, txm_dev.x, bare names). Each one is now
{component}-{effect}-{name}:
- component: avpbooter, ibss, ibec, llb, txm, kernel, devicetree, dyld,
preboot, or system-<binary> for a guest binary or file.
- effect: boot when the patch is boot-essential, exp when the standard
preset leaves it off, cfw otherwise. A catalog test enforces this.
- name: snake_case, no hyphen, so the identifier splits from the right.
Record sites are now always <identifier>.<site>. The underscore-prefix
rule in covers(recordIdentifier:) and in the gate is gone: the new names
contain underscores, so kernel-boot-post_validation would otherwise have
covered kernel-boot-post_validation_unsigned. The 25 records that relied
on it (amfi_trustcache_1, launch_constraints_mov, sandbox_ext_N, ...) now
use a dot.
Old identifiers are not migrated. A VM whose PatchPlan or PatchSelection
names one must be patched again. The bundle becomes 2.2.0 and Launchpad
requires 2.2.0, so it never meets an old identifier from a bundle.
Launchpad's patch table shows Component, Effect and Name columns in place
of Identifier and Patch Set; the set moves to the detail line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ Use the VM window's **Keys → Home** action. The current JB workflow does not i
|
||||
|
||||
## App exits with `EXC_GUARD` / `GUARD_TYPE_MACH_PORT`
|
||||
|
||||
The kernel patch `kernel.thread_guard_violation` stops fatal Mach port guard delivery. It applies only on an iOS 18 base, where it is needed to boot, and every preset turns it on there. Other bases cannot select it, so an app that trips this guard on a 26.x base still exits. See [issue #291](https://github.com/Lakr233/vphone-cli/issues/291).
|
||||
The kernel patch `kernel-boot-thread_guard_violation` stops fatal Mach port guard delivery. It applies only on an iOS 18 base, where it is needed to boot, and every preset turns it on there. Other bases cannot select it, so an app that trips this guard on a 26.x base still exits. See [issue #291](https://github.com/Lakr233/vphone-cli/issues/291).
|
||||
|
||||
## Restore or first boot fails
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ linked call, no options -> 0x0 (0xE8008014 without the hook)
|
||||
|
||||
## What was built
|
||||
|
||||
`installd.adhoc_signature` — `VPhoneGuestComponents/MISFix/MISFix-vphone.c`,
|
||||
`system-installd-cfw-adhoc_signature` — `VPhoneGuestComponents/MISFix/MISFix-vphone.c`,
|
||||
built as `/usr/lib/libmisfix.dylib`, attached to `/usr/libexec/installd` by a
|
||||
`LC_LOAD_WEAK_DYLIB` that `cfw install` inserts. It interposes
|
||||
`MISValidateSignatureAndCopyInfo` and
|
||||
@@ -251,7 +251,7 @@ again.
|
||||
|
||||
## What was built
|
||||
|
||||
`misagent.device_identity` — the same `libmisfix.dylib`, attached to
|
||||
`system-misagent-cfw-device_identity` — the same `libmisfix.dylib`, attached to
|
||||
`/usr/libexec/misagent`, interposing `MGCopyAnswer` and `MGCopyAnswerWithError`
|
||||
and answering `UniqueDeviceID` with the value in `libmisfix.plist`. Set it to a
|
||||
device the team has already registered and that team's profiles install here,
|
||||
|
||||
@@ -34,11 +34,12 @@ nine in-tree sets and the two shipped presets live in
|
||||
`emit`. That is what ties the patch to its declaration.
|
||||
|
||||
3. **Declare it** in the right set, with the identifier being the record
|
||||
identifier, or their common prefix when the patch writes several sites:
|
||||
identifier, or the part before `.<site>` when the patch writes several
|
||||
sites. Name it by the scheme in [Naming](#naming):
|
||||
|
||||
```swift
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.my_patch",
|
||||
identifier: "kernel-boot-my_patch",
|
||||
title: "What it is, in three or four words",
|
||||
summary: "What it does and why the guest needs it. One or two sentences.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -51,29 +52,44 @@ nine in-tree sets and the two shipped presets live in
|
||||
`[!] <component>: <id> is declared by no patch set; applying it anyway`. Grep
|
||||
the logs for `declared by no patch set` — it must be absent.
|
||||
|
||||
### Naming
|
||||
|
||||
A patch identifier is `{component}-{effect}-{name}`, hyphen-separated:
|
||||
|
||||
- **component** — where the bytes land: `avpbooter`, `ibss`, `ibec`, `llb`,
|
||||
`txm`, `kernel`, `devicetree`, `dyld` (the shared cache), `preboot`, or
|
||||
`system-<binary>` for a guest system binary or file
|
||||
(`system-seputil-boot-gigalocker_uuid`, `system-vphoned-boot-install`).
|
||||
- **effect** — derived, never chosen: `boot` if `bootEssential`, else `exp` if
|
||||
`standard` leaves it off, else `cfw`. A patch that changes either property is
|
||||
renamed with it.
|
||||
- **name** — snake_case, `[a-z0-9_]`, no dots or hyphens.
|
||||
|
||||
`Every patch identifier names its component, effect and patch` in
|
||||
`FirmwarePatchSetCatalogTests` checks the shape, the effect and uniqueness for
|
||||
every bundled declaration.
|
||||
|
||||
### Identifiers Are the Contract
|
||||
|
||||
A declaration covers its own record and any record under it, with either
|
||||
separator:
|
||||
A declaration covers its own record and any record `<identifier>.<site>` —
|
||||
only a dot starts a site:
|
||||
|
||||
- `jb.kcall10` covers `jb.kcall10.sy_call`, `jb.kcall10.sy_munge`, …
|
||||
- `llb.rootfs` covers `llb.rootfs_cbz_0x3b7`, `llb.rootfs_bhs_0x400`, …
|
||||
- `sandbox_ext` covers `sandbox_ext_267` and every other index
|
||||
- `kernel.debugger` does **not** cover `kernel.debuggerless`
|
||||
- `kernel-boot-kcall10` covers `kernel-boot-kcall10.sy_call`, `kernel-boot-kcall10.sy_munge`, …
|
||||
- `kernel-boot-sandbox_ext` covers `kernel-boot-sandbox_ext.3` and every other index
|
||||
- `kernel-boot-post_validation` does **not** cover `kernel-boot-post_validation_unsigned`
|
||||
- `kernel-cfw-debugger` does **not** cover `kernel-cfw-debuggerless`
|
||||
|
||||
Both separators are supported because record identifiers predate declarations and
|
||||
spell their per-site suffix both ways. Do not rename an existing record
|
||||
identifier to tidy this up: they appear in logs, in research notes and in test
|
||||
expectations.
|
||||
An underscore continues a snake_case name, so it never separates a site: emit
|
||||
`.1`, not `_1`.
|
||||
|
||||
Pick the granularity a user would want to tick. One declaration per patch method
|
||||
is usually right — a patch writing four sites that only work together is one
|
||||
checkbox, because half of it would not boot. Where sites are genuinely
|
||||
independent, declare them separately: `kernel.sandbox.*` is five declarations,
|
||||
independent, declare them separately: `kernel-*-sandbox_*` is five declarations,
|
||||
one per MACF hook, because turning one hook off is a sensible thing to want.
|
||||
|
||||
**Never let one declaration read as a site of another.**
|
||||
`FirmwarePatchSetCatalogTests.noAmbiguousPrefixes` fails if you do.
|
||||
`No patch identifier is a record-site prefix of another` fails if you do.
|
||||
|
||||
## Version Gates
|
||||
|
||||
@@ -184,7 +200,7 @@ selection:
|
||||
<string>Block</string>
|
||||
<key>Patches</key>
|
||||
<array>
|
||||
<string>kernelcache_frida.thread_set_state_entitlement_flag</string>
|
||||
<string>kernel-exp-frida_thread_set_state_entitlement_flag</string>
|
||||
</array>
|
||||
</dict>
|
||||
```
|
||||
@@ -196,14 +212,15 @@ patch added later will not be in it.
|
||||
|
||||
When you add or change a preset plist, mirror it in
|
||||
`FirmwarePatchSetCatalog` — that Swift copy is what a dev build with no staged
|
||||
bundle falls back to, and `shippedPresetsMatchBuiltIns` fails if they drift.
|
||||
bundle falls back to, and `The shipped preset plists match the built-in copies`
|
||||
fails if they drift.
|
||||
|
||||
### What a VM Records
|
||||
|
||||
`fw set-patches` writes `<vm>/PatchSelection.plist`, and is the only writer:
|
||||
|
||||
```zsh
|
||||
vphone-cli fw set-patches lab --preset extended --block kernel.debugger
|
||||
vphone-cli fw set-patches lab --preset extended --block kernel-cfw-debugger
|
||||
vphone-cli fw set-patches lab # back to the preset alone
|
||||
```
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ public final class AVPBooterPatcher: BufferedPatcher {
|
||||
throw PatcherError.patchSiteNotFound("AVPBooter DGST: x0 setter not found before RET")
|
||||
}
|
||||
|
||||
guard gateAllows("avpbooter.dgst_bypass") else { return }
|
||||
guard gateAllows("avpbooter-boot-dgst_bypass") else { return }
|
||||
|
||||
let target = insns[targetIdx]
|
||||
let fileOff = Int(target.address) // base address is 0, so VA == file offset
|
||||
@@ -140,7 +140,7 @@ public final class AVPBooterPatcher: BufferedPatcher {
|
||||
let afterStr = afterInsn.map { "\($0.mnemonic) \($0.operandString)" } ?? "mov x0, #0"
|
||||
|
||||
let record = PatchRecord(
|
||||
patchID: "avpbooter.dgst_bypass",
|
||||
patchID: "avpbooter-boot-dgst_bypass",
|
||||
component: component,
|
||||
fileOffset: fileOff,
|
||||
virtualAddress: nil,
|
||||
@@ -154,7 +154,7 @@ public final class AVPBooterPatcher: BufferedPatcher {
|
||||
|
||||
if verbose {
|
||||
print(String(
|
||||
format: " 0x%06X: %@ → %@ [avpbooter.dgst_bypass]",
|
||||
format: " 0x%06X: %@ → %@ [avpbooter-boot-dgst_bypass]",
|
||||
fileOff,
|
||||
beforeStr,
|
||||
afterStr,
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public enum CustomFirmwareCacheLoaderPatcher {
|
||||
|
||||
/// Record identity, matching the Python's `records.site` label so a captured
|
||||
/// reference and this port sort together.
|
||||
public static let patchID = "launchd_cache_loader.unsecure_cache_gate"
|
||||
public static let patchID = "system-launchd_cache_loader-boot-unsecure_cache_gate"
|
||||
|
||||
/// Substrings that name the gate's boot-arg, most specific first. The same
|
||||
/// list the Python carries: the later three are there for a firmware that
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public enum CustomFirmwareDiskImage {
|
||||
|
||||
/// Record identity, matching the Python's `records.site` label so a captured
|
||||
/// reference and this port sort together.
|
||||
public static let patchID = "diskimagesiod.is_mount_complete"
|
||||
public static let patchID = "system-diskimagesiod-cfw-is_mount_complete"
|
||||
|
||||
/// `mov x0, #1 ; ret`.
|
||||
///
|
||||
|
||||
+1
-1
@@ -254,7 +254,7 @@ public enum CustomFirmwareJetsamPatcher {
|
||||
|
||||
let original = Data(data[site.gateOffset ..< site.gateOffset + 4])
|
||||
let record = PatchRecord(
|
||||
patchID: "launchd_jetsam.panic_guard_bypass",
|
||||
patchID: "system-launchd-boot-jetsam_panic_guard_bypass",
|
||||
component: "launchd_jetsam",
|
||||
fileOffset: site.gateOffset,
|
||||
virtualAddress: gateVMA,
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ public enum CustomFirmwareMobileActivation {
|
||||
|
||||
/// Record identity, matching the Python's `records.site` label so a captured
|
||||
/// reference and this port sort together.
|
||||
public static let patchID = "mobileactivationd.should_hactivate"
|
||||
public static let patchID = "system-mobileactivationd-boot-should_hactivate"
|
||||
|
||||
/// Where progress goes when the caller does not say. The Python prints to
|
||||
/// stdout and `cfw_install*.sh` captures that, so this does too.
|
||||
|
||||
+1
-1
@@ -473,7 +473,7 @@ public enum CustomFirmwareSeputil {
|
||||
/// field.
|
||||
private static func record(for site: Site, original: Data, replacement: Data) -> PatchRecord {
|
||||
PatchRecord(
|
||||
patchID: "seputil.gigalocker_uuid",
|
||||
patchID: "system-seputil-boot-gigalocker_uuid",
|
||||
component: "seputil",
|
||||
fileOffset: site.fieldOffset,
|
||||
virtualAddress: site.fieldVMA,
|
||||
|
||||
+2
-2
@@ -281,7 +281,7 @@ public enum CustomFirmwareWatchDog {
|
||||
at: site.gateFileOffset,
|
||||
virtualAddress: site.gateVMA,
|
||||
patched: gate,
|
||||
id: "\(component).hv_vmm_cache.cbnz@0x\(hex(site.gateVMA))",
|
||||
id: "system-\(component)-exp-hv_vmm_cache.cbnz@0x\(hex(site.gateVMA))",
|
||||
description: "NOP the cbnz w0 that skips the cached hv_vmm_present store",
|
||||
disassembler: disassembler,
|
||||
))
|
||||
@@ -290,7 +290,7 @@ public enum CustomFirmwareWatchDog {
|
||||
at: site.valueFileOffset,
|
||||
virtualAddress: site.valueVMA,
|
||||
patched: value,
|
||||
id: "\(component).hv_vmm_cache.cset@0x\(hex(site.valueVMA))",
|
||||
id: "system-\(component)-exp-hv_vmm_cache.cset@0x\(hex(site.valueVMA))",
|
||||
description: "cset \(site.valueRegister) -> mov \(site.valueRegister), #1 "
|
||||
+ "(cached 'am I a VM?' byte forced to 1)",
|
||||
disassembler: disassembler,
|
||||
|
||||
+9
-9
@@ -109,7 +109,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "video-cap", length: 4, flags: 0, value: .integer(2)),
|
||||
.init(name: "video-stills", length: 4, flags: 0, value: .integer(1)),
|
||||
],
|
||||
patchID: "devicetree.product.camera_node",
|
||||
patchID: "devicetree-cfw-product_camera_node",
|
||||
description: "Add /product/camera node with full iPhone17,3 D47AP property set (62 props)",
|
||||
),
|
||||
|
||||
@@ -148,7 +148,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "tnr-mode-back", length: 4, flags: 0, value: .integer(10)),
|
||||
.init(name: "tnr-mode-front", length: 4, flags: 0, value: .integer(10)),
|
||||
],
|
||||
patchID: "devicetree.product.facetime_node",
|
||||
patchID: "devicetree-cfw-product_facetime_node",
|
||||
description: "Add /product/facetime node with full iPhone17,3 D47AP property set (9 props)",
|
||||
),
|
||||
|
||||
@@ -219,7 +219,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "voiceTriggerChannels", length: 4, flags: 0, value: .integer(1)),
|
||||
.init(name: "wireless-splitter", length: 4, flags: 0, value: .integer(1)),
|
||||
],
|
||||
patchID: "devicetree.product.audio_node",
|
||||
patchID: "devicetree-cfw-product_audio_node",
|
||||
description: "Add /product/audio node with full iPhone17,3 D47AP property set (31 props)",
|
||||
),
|
||||
|
||||
@@ -239,7 +239,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "aot-linger-time-ms", length: 4, flags: 0, value: .integer(0)),
|
||||
.init(name: "aot-mode", length: 4, flags: 0, value: .integer(13)),
|
||||
],
|
||||
patchID: "devicetree.product.iopm_node",
|
||||
patchID: "devicetree-cfw-product_iopm_node",
|
||||
description: "Add /product/iopm node with aot-mode=13 + aot-linger-time-ms=0 (2 props)",
|
||||
),
|
||||
|
||||
@@ -282,7 +282,7 @@ extension DeviceTreePatcher {
|
||||
parentPath: ["device-tree", "arm-io"],
|
||||
nodeName: "smc",
|
||||
properties: [],
|
||||
patchID: "devicetree.arm_io.smc_stub",
|
||||
patchID: "devicetree-cfw-arm_io_smc_stub",
|
||||
description: "Add /arm-io/smc empty stub (parent for smc-ext-charger chain)",
|
||||
),
|
||||
|
||||
@@ -291,7 +291,7 @@ extension DeviceTreePatcher {
|
||||
parentPath: ["device-tree", "arm-io", "smc"],
|
||||
nodeName: "iop-smc-nub",
|
||||
properties: [],
|
||||
patchID: "devicetree.arm_io.smc.iop_smc_nub_stub",
|
||||
patchID: "devicetree-cfw-arm_io_smc_iop_smc_nub_stub",
|
||||
description: "Add /arm-io/smc/iop-smc-nub empty stub (parent for smc-ext-charger)",
|
||||
),
|
||||
|
||||
@@ -302,7 +302,7 @@ extension DeviceTreePatcher {
|
||||
properties: [
|
||||
.init(name: "camera-driver", length: 14, flags: 0, value: .string("AppleH16CamIn")),
|
||||
],
|
||||
patchID: "devicetree.arm_io.smc.smc_ext_charger_camera_driver",
|
||||
patchID: "devicetree-cfw-arm_io_smc_ext_charger_camera_driver",
|
||||
description: "Add /arm-io/smc/iop-smc-nub/smc-ext-charger with camera-driver='AppleH16CamIn'",
|
||||
),
|
||||
|
||||
@@ -314,7 +314,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "camera-front", length: 4, flags: 0, value: .integer(1)),
|
||||
.init(name: "camera-rear", length: 4, flags: 0, value: .integer(1)),
|
||||
],
|
||||
patchID: "devicetree.arm_io.isp_camera_flags",
|
||||
patchID: "devicetree-cfw-arm_io_isp_camera_flags",
|
||||
description: "Add /arm-io/isp stub with camera-front=1 + camera-rear=1",
|
||||
),
|
||||
|
||||
@@ -326,7 +326,7 @@ extension DeviceTreePatcher {
|
||||
.init(name: "camera-front", length: 4, flags: 0, value: .integer(1)),
|
||||
.init(name: "camera-rear", length: 4, flags: 0, value: .integer(1)),
|
||||
],
|
||||
patchID: "devicetree.arm_io.ispRtb_camera_flags",
|
||||
patchID: "devicetree-cfw-arm_io_isp_rtb_camera_flags",
|
||||
description: "Add /arm-io/ispRtb stub with camera-front=1 + camera-rear=1",
|
||||
),
|
||||
]
|
||||
|
||||
+14
-14
@@ -51,7 +51,7 @@ extension DeviceTreePatcher {
|
||||
length: 12,
|
||||
flags: 0,
|
||||
value: .string("vphone-1337"),
|
||||
patchID: "devicetree.serial_number",
|
||||
patchID: "devicetree-cfw-serial_number",
|
||||
description: "Set serial number to vphone-1337",
|
||||
),
|
||||
PropertyPatch(
|
||||
@@ -60,7 +60,7 @@ extension DeviceTreePatcher {
|
||||
length: 4,
|
||||
flags: 0,
|
||||
value: .integer(2),
|
||||
patchID: "devicetree.home_button_type",
|
||||
patchID: "devicetree-cfw-home_button_type",
|
||||
description: "Set home button type to 2",
|
||||
),
|
||||
PropertyPatch(
|
||||
@@ -69,7 +69,7 @@ extension DeviceTreePatcher {
|
||||
length: 4,
|
||||
flags: 0,
|
||||
value: .integer(2556),
|
||||
patchID: "devicetree.artwork_device_subtype",
|
||||
patchID: "devicetree-cfw-artwork_device_subtype",
|
||||
description: "Set artwork device subtype to 2556",
|
||||
),
|
||||
PropertyPatch(
|
||||
@@ -78,7 +78,7 @@ extension DeviceTreePatcher {
|
||||
length: 4,
|
||||
flags: 0,
|
||||
value: .integer(144),
|
||||
patchID: "devicetree.island_notch_location",
|
||||
patchID: "devicetree-cfw-island_notch_location",
|
||||
description: "Set island notch location to 144",
|
||||
),
|
||||
]
|
||||
@@ -118,7 +118,7 @@ extension DeviceTreePatcher {
|
||||
length: 12,
|
||||
flags: 0,
|
||||
value: .string("D47AP"),
|
||||
patchID: "devicetree.target_sub_type",
|
||||
patchID: "devicetree-exp-target_sub_type",
|
||||
description: "Set target-sub-type to D47AP (was VPHONE600AP)",
|
||||
),
|
||||
|
||||
@@ -135,7 +135,7 @@ extension DeviceTreePatcher {
|
||||
length: 48,
|
||||
flags: 0,
|
||||
value: .bytes(compatibleRewrite),
|
||||
patchID: "devicetree.compatible_secondary",
|
||||
patchID: "devicetree-exp-compatible_secondary",
|
||||
description: "Surgical rewrite of compatible[1]: iPhone99,11 -> iPhone17,3",
|
||||
),
|
||||
|
||||
@@ -148,7 +148,7 @@ extension DeviceTreePatcher {
|
||||
length: 12,
|
||||
flags: 0,
|
||||
value: .string("iPhone17,3"),
|
||||
patchID: "devicetree.product.fdr_product_type",
|
||||
patchID: "devicetree-exp-product_fdr_product_type",
|
||||
description: "Set product/fdr-product-type to iPhone17,3 (was iPhone99,11)",
|
||||
),
|
||||
|
||||
@@ -161,7 +161,7 @@ extension DeviceTreePatcher {
|
||||
length: 12,
|
||||
flags: 0,
|
||||
value: .string("iPhone17,3"),
|
||||
patchID: "devicetree.product.sub_product_type",
|
||||
patchID: "devicetree-exp-product_sub_product_type",
|
||||
description: "Set product/sub-product-type to iPhone17,3 (was iPhone99,11)",
|
||||
),
|
||||
|
||||
@@ -174,7 +174,7 @@ extension DeviceTreePatcher {
|
||||
length: 12,
|
||||
flags: 0,
|
||||
value: .string("D47AP"),
|
||||
patchID: "devicetree.product.unique_model",
|
||||
patchID: "devicetree-exp-product_unique_model",
|
||||
description: "Set product/unique-model to D47AP (was VPHONE600AP)",
|
||||
),
|
||||
|
||||
@@ -194,7 +194,7 @@ extension DeviceTreePatcher {
|
||||
length: 14,
|
||||
flags: 0,
|
||||
value: .string("t8140-io"),
|
||||
patchID: "devicetree.arm_io.device_type",
|
||||
patchID: "devicetree-exp-arm_io_device_type",
|
||||
description: "Set arm-io/device_type to t8140-io (was vresearch1-io)",
|
||||
),
|
||||
|
||||
@@ -208,7 +208,7 @@ extension DeviceTreePatcher {
|
||||
length: 11,
|
||||
flags: 0,
|
||||
value: .string("H17"),
|
||||
patchID: "devicetree.arm_io.soc_generation",
|
||||
patchID: "devicetree-exp-arm_io_soc_generation",
|
||||
description: "Set arm-io/soc-generation to H17 (was VResearch1)",
|
||||
),
|
||||
|
||||
@@ -229,7 +229,7 @@ extension DeviceTreePatcher {
|
||||
length: 27,
|
||||
flags: 0,
|
||||
value: .string("d47-gestalt-variants"),
|
||||
patchID: "devicetree.product.gestalt_variants_rename",
|
||||
patchID: "devicetree-exp-product_gestalt_variants_rename",
|
||||
description: "Rename node vphone600-gestalt-variants -> d47-gestalt-variants",
|
||||
),
|
||||
|
||||
@@ -252,7 +252,7 @@ extension DeviceTreePatcher {
|
||||
0xD8, 0x13, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
])),
|
||||
patchID: "devicetree.product.front_cam_offset",
|
||||
patchID: "devicetree-cfw-product_front_cam_offset",
|
||||
description: "Set product/front-cam-offset-from-center to d47ap geometry (was syscfg/fcof)",
|
||||
),
|
||||
PropertyPatch(
|
||||
@@ -265,7 +265,7 @@ extension DeviceTreePatcher {
|
||||
0x59, 0x08, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
])),
|
||||
patchID: "devicetree.product.rear_cam_offset",
|
||||
patchID: "devicetree-cfw-product_rear_cam_offset",
|
||||
description: "Set product/rear-cam-offset-from-center to d47ap geometry (was syscfg/rcof)",
|
||||
),
|
||||
]
|
||||
|
||||
+2
-2
@@ -139,7 +139,7 @@ public enum DyldSharedCacheCameraPatcher {
|
||||
public struct Site: Sendable {
|
||||
public let family: Family
|
||||
public let symbol: String
|
||||
/// `camera_dsc.<family>.<slug>` — the id `cfw_records.next_site` gives
|
||||
/// `dyld-cfw-camera.<family>.<slug>` — the id `cfw_records.next_site` gives
|
||||
/// the same write, so a capture taken either side of this port lines up.
|
||||
public let patchID: String
|
||||
public let vma: UInt64
|
||||
@@ -313,7 +313,7 @@ public enum DyldSharedCacheCameraPatcher {
|
||||
Site(
|
||||
family: family,
|
||||
symbol: symbol,
|
||||
patchID: "camera_dsc.\(family.rawValue).\(symbolSlug(symbol))",
|
||||
patchID: "dyld-cfw-camera.\(family.rawValue).\(symbolSlug(symbol))",
|
||||
vma: vma,
|
||||
originalBytes: original,
|
||||
patchedBytes: replacement,
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public enum DyldSharedCacheIOMFBForceKernPatcher {
|
||||
public static let requiredSuffixes: [String] = ["SwapBegin", "SwapEnd", "SwapSetLayer"]
|
||||
|
||||
/// Record group name, matching `records.set_group("iomfb_force_kern")`.
|
||||
public static let recordGroup = "iomfb_force_kern"
|
||||
public static let recordGroup = "dyld-boot-iomfb_force_kern"
|
||||
|
||||
/// Where diagnostics go when the caller does not say. Mirrors the
|
||||
/// reference's `print`, so the two runs can be diffed line by line.
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public enum DyldSharedCacheLSDEmbeddedRegPatcher {
|
||||
|
||||
/// Record identity, matching the Python's `records.next_site` label so a
|
||||
/// captured reference and this port sort together.
|
||||
public static let patchID = "lsd_embedded_reg.entitlement_gate"
|
||||
public static let patchID = "dyld-boot-lsd_embedded_reg"
|
||||
|
||||
/// How far into the method to look. The gate sits within the first handful
|
||||
/// of basic blocks; 96 instructions is the Python's window and is ample.
|
||||
|
||||
+1
-1
@@ -323,7 +323,7 @@ public enum DyldSharedCacheLockdownModePatcher {
|
||||
let span = DyldSharedCacheWriteSpan(vma: gate.address, length: replacement.count)
|
||||
let (chunkURL, range) = try chunks.fileRange(of: span)
|
||||
return PatchRecord(
|
||||
patchID: "lockdown_mode.sysctl_error_gate",
|
||||
patchID: "dyld-boot-lockdown_mode",
|
||||
component: chunkURL.lastPathComponent,
|
||||
fileOffset: range.lowerBound,
|
||||
virtualAddress: gate.address,
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// A guest restored by this project is *hacktivated*: `mobileactivationd`'s
|
||||
// `-[DeviceType should_hactivate]` is forced to YES (see the
|
||||
// `mobileactivationd.should_hactivate` declaration), so the device never talks
|
||||
// `system-mobileactivationd-boot-should_hactivate` declaration), so the device never talks
|
||||
// to Apple's activation service and never receives an activation record. That
|
||||
// is what makes the VM boot without an Apple ID, and it is also why a profile
|
||||
// that wants online authorization can never get it:
|
||||
@@ -108,8 +108,8 @@ public enum DyldSharedCacheMISTrustAuthPatcher {
|
||||
/// own log strings rather than from any symbol table.
|
||||
public static let function = "checkTrustAndAuthorization"
|
||||
|
||||
/// Record identity. `mis_trust_auth` is the declaration prefix.
|
||||
public static let patchID = "mis_trust_auth.force_success"
|
||||
/// Record identity. `dyld-cfw-mis_trust_auth` is the declaration prefix.
|
||||
public static let patchID = "dyld-cfw-mis_trust_auth.force_success"
|
||||
|
||||
/// The literal that names the function. Matched with its NUL so the tail of
|
||||
/// a longer string cannot stand in for it.
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ public enum DyldSharedCacheMaxSlidePatcher {
|
||||
static let magicPrefix = Data("dyld_v1".utf8)
|
||||
|
||||
/// The patch identifier the reference capture records under.
|
||||
public static let patchID = "dsc_maxslide.zero"
|
||||
public static let patchID = "dyld-boot-maxslide"
|
||||
|
||||
// MARK: - Result
|
||||
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ public enum DyldSharedCacheXPCLWCRPatcher {
|
||||
static let maxInstructions = 160
|
||||
|
||||
/// The record group this patcher writes under, matching `cfw_records`.
|
||||
public static let recordGroup = "xpc_lwcr"
|
||||
public static let recordGroup = "dyld-boot-xpc_lwcr"
|
||||
|
||||
// MARK: - Outcome
|
||||
|
||||
|
||||
+3
-3
@@ -43,7 +43,7 @@ extension IBootPatcher {
|
||||
}
|
||||
|
||||
// Write the string itself
|
||||
emitString(newOff, newArgsData, id: "\(component).boot_args_string", description: "boot-args string")
|
||||
emitString(newOff, newArgsData, id: "\(component)-boot-boot_args.string", description: "boot-args string")
|
||||
|
||||
// Re-encode ADRP x2 → new page
|
||||
guard let newAdrp = ARM64Encoder.encodeADRP(rd: 2, pc: UInt64(adrpOff), target: UInt64(newOff)) else {
|
||||
@@ -52,7 +52,7 @@ extension IBootPatcher {
|
||||
}
|
||||
return
|
||||
}
|
||||
emit(adrpOff, newAdrp, id: "\(component).boot_args_adrp", description: "boot-args: adrp x2 → new string page")
|
||||
emit(adrpOff, newAdrp, id: "\(component)-boot-boot_args.adrp", description: "boot-args: adrp x2 → new string page")
|
||||
|
||||
// Re-encode ADD x2, x2, #offset
|
||||
let imm12 = UInt32(newOff & 0xFFF)
|
||||
@@ -62,7 +62,7 @@ extension IBootPatcher {
|
||||
}
|
||||
return
|
||||
}
|
||||
emit(addOff, newAdd, id: "\(component).boot_args_add", description: "boot-args: add x2 → new string offset")
|
||||
emit(addOff, newAdd, id: "\(component)-boot-boot_args.add", description: "boot-args: add x2 → new string offset")
|
||||
}
|
||||
|
||||
/// Find the standalone "%s" format string near "rd=md0" or "BootArgs".
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ extension IBootPatcher {
|
||||
emit(
|
||||
gate,
|
||||
ARM64.nop,
|
||||
id: "\(component).bootx_precondition",
|
||||
id: "\(component)-boot-bootx_precondition",
|
||||
description: "bootx precondition: NOP gate TBZ",
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -64,11 +64,11 @@ extension IBootPatcher {
|
||||
candidates.last!.addr
|
||||
}
|
||||
|
||||
emit(off, ARM64.nop, id: "\(component).image4_callback_bne", description: "image4 callback: b.ne → nop")
|
||||
emit(off, ARM64.nop, id: "\(component)-boot-image4_callback.bne", description: "image4 callback: b.ne → nop")
|
||||
emit(
|
||||
off + 4,
|
||||
ARM64.movX0_0,
|
||||
id: "\(component).image4_callback_mov",
|
||||
id: "\(component)-boot-image4_callback.mov",
|
||||
description: "image4 callback: mov x0,x22 → mov x0,#0",
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ extension IBootPatcher {
|
||||
emit(
|
||||
step + 4,
|
||||
ARM64.nop,
|
||||
id: "\(component).panic_bypass",
|
||||
id: "\(component)-boot-panic_bypass",
|
||||
description: "panic bypass: NOP cbnz w0",
|
||||
)
|
||||
return
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@ extension IBootPatcher {
|
||||
return
|
||||
}
|
||||
|
||||
emit(cbzOff, bInsn, id: "\(component).rootfs_cbz_0x\(String(errorCode, radix: 16))", description: description)
|
||||
emit(cbzOff, bInsn, id: "\(component)-boot-rootfs.cbz_0x\(String(errorCode, radix: 16))", description: description)
|
||||
}
|
||||
|
||||
/// NOP the `b.hs` of the unique `cmp x8,#0x400 ; b.hs` rootfs size gate.
|
||||
@@ -94,7 +94,7 @@ extension IBootPatcher {
|
||||
emit(
|
||||
bhsSites[0],
|
||||
ARM64.nop,
|
||||
id: "\(component).rootfs_bhs_0x400",
|
||||
id: "\(component)-boot-rootfs.bhs_0x400",
|
||||
description: "rootfs: NOP b.hs size check (0x400)",
|
||||
)
|
||||
}
|
||||
@@ -134,7 +134,7 @@ extension IBootPatcher {
|
||||
emit(
|
||||
scan + 4,
|
||||
ARM64.nop,
|
||||
id: "\(component).rootfs_null_check_0x78",
|
||||
id: "\(component)-boot-rootfs.null_check_0x78",
|
||||
description: "rootfs: NOP cbz x8 null check (#0x78)",
|
||||
)
|
||||
return
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ extension IBootPatcher {
|
||||
|
||||
for runStart in eqRuns.prefix(2) {
|
||||
let writeOff = runStart + 1 // Python: run_start + 1
|
||||
emitString(writeOff, labelBytes, id: "\(component).serial_label", description: "serial label")
|
||||
emitString(writeOff, labelBytes, id: "\(component)-cfw-serial_label", description: "serial label")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public final class IBootJailbreakPatcher: IBootPatcher {
|
||||
let afterStr = afterInsn.map { "\($0.mnemonic) \($0.operandString)" } ?? "b"
|
||||
|
||||
let record = PatchRecord(
|
||||
patchID: "ibss_jb.skip_generate_nonce",
|
||||
patchID: "ibss-boot-skip_generate_nonce",
|
||||
component: component,
|
||||
fileOffset: scan,
|
||||
virtualAddress: nil,
|
||||
@@ -130,7 +130,7 @@ public final class IBootJailbreakPatcher: IBootPatcher {
|
||||
|
||||
if verbose {
|
||||
print(String(
|
||||
format: " 0x%06X: %@ → %@ [ibss_jb.skip_generate_nonce]",
|
||||
format: " 0x%06X: %@ → %@ [ibss-boot-skip_generate_nonce]",
|
||||
scan,
|
||||
beforeStr,
|
||||
afterStr,
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
scan,
|
||||
ARM64.movW0_0,
|
||||
patchID: "apfs_graft",
|
||||
patchID: "kernel-boot-apfs_graft",
|
||||
virtualAddress: va,
|
||||
description: "mov w0,#0 [_apfs_graft]",
|
||||
)
|
||||
|
||||
+4
-4
@@ -113,7 +113,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
scan,
|
||||
ARM64.cmpX0X0,
|
||||
patchID: "kernel.apfs_vfsop_mount.cmp_x0_x0",
|
||||
patchID: "kernel-boot-apfs_vfsop_mount.cmp_x0_x0",
|
||||
virtualAddress: va,
|
||||
description: "cmp x0,x0 (was \(insn.mnemonic) \(insn.operandString)) [_apfs_vfsop_mount]",
|
||||
)
|
||||
@@ -186,7 +186,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
nextOff,
|
||||
ARM64.movW0_0,
|
||||
patchID: "kernel.apfs_mount_upgrade_checks.mov_w0_0",
|
||||
patchID: "kernel-boot-apfs_mount_upgrade_checks.mov_w0_0",
|
||||
virtualAddress: va,
|
||||
description: "mov w0,#0 [_apfs_mount_upgrade_checks]",
|
||||
)
|
||||
@@ -259,7 +259,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
scan,
|
||||
ARM64.movW0_0,
|
||||
patchID: "kernel.handle_fsioc_graft.mov_w0_0",
|
||||
patchID: "kernel-boot-handle_fsioc_graft.mov_w0_0",
|
||||
virtualAddress: va,
|
||||
description: "mov w0,#0 [_handle_fsioc_graft]",
|
||||
)
|
||||
@@ -354,7 +354,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
cand.off,
|
||||
ARM64.nop,
|
||||
patchID: "kernel.handle_get_dev_by_role.gate_\(String(format: "%X", cand.off))",
|
||||
patchID: "kernel-boot-handle_get_dev_by_role.gate_\(String(format: "%X", cand.off))",
|
||||
virtualAddress: va,
|
||||
description: "NOP [handle_get_dev_by_role entitlement gate -> 0x\(String(format: "%X", cand.target))]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ extension KernelPatcher {
|
||||
if let branchTarget = conditionalBranchTarget(insn: insn) {
|
||||
if branchTarget >= errLo, branchTarget <= errHi {
|
||||
let desc = "NOP \(insn.mnemonic) (seal broken) [_authapfs_seal_is_broken]"
|
||||
emit(back, ARM64.nop, patchID: "kernel.apfs_seal_broken", description: desc)
|
||||
emit(back, ARM64.nop, patchID: "kernel-boot-apfs_seal_broken", description: desc)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ extension KernelPatcher {
|
||||
}
|
||||
|
||||
let desc = "NOP \(insn.mnemonic) \(insn.operandString) (sealed vol check) [_apfs_vfsop_mount]"
|
||||
emit(scan, ARM64.nop, patchID: "kernel.apfs_root_snapshot", description: desc)
|
||||
emit(scan, ARM64.nop, patchID: "kernel-boot-apfs_root_snapshot", description: desc)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,14 +62,14 @@ extension KernelPatcher {
|
||||
emit(
|
||||
offset,
|
||||
ARM64.movX0_1,
|
||||
patchID: "kernel.debugger.mov_x0_1",
|
||||
patchID: "kernel-cfw-debugger.mov_x0_1",
|
||||
virtualAddress: va,
|
||||
description: "mov x0,#1 [_PE_i_can_has_debugger]",
|
||||
)
|
||||
emit(
|
||||
offset + 4,
|
||||
ARM64.ret,
|
||||
patchID: "kernel.debugger.ret",
|
||||
patchID: "kernel-cfw-debugger.ret",
|
||||
virtualAddress: va.map { $0 + 4 },
|
||||
description: "ret [_PE_i_can_has_debugger]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -66,14 +66,14 @@ extension KernelPatcher {
|
||||
emit(
|
||||
bl1.blOff,
|
||||
ARM64.movW0_1,
|
||||
patchID: "dyld_policy_1",
|
||||
patchID: "kernel-boot-dyld_policy.1",
|
||||
virtualAddress: va1,
|
||||
description: "mov w0,#1 (was BL) [_check_dyld_policy_internal @1]",
|
||||
)
|
||||
emit(
|
||||
bl2.blOff,
|
||||
ARM64.movW0_1,
|
||||
patchID: "dyld_policy_2",
|
||||
patchID: "kernel-boot-dyld_policy.2",
|
||||
virtualAddress: va2,
|
||||
description: "mov w0,#1 (was BL) [_check_dyld_policy_internal @2]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
inner,
|
||||
ARM64.ret,
|
||||
patchID: "kernel.thread_guard_violation",
|
||||
patchID: "kernel-boot-thread_guard_violation",
|
||||
virtualAddress: va,
|
||||
description: "PACIBSP→RET (disable guard violation delivery)",
|
||||
)
|
||||
|
||||
+2
-2
@@ -53,14 +53,14 @@ extension KernelPatcher {
|
||||
emit(
|
||||
funcStart,
|
||||
ARM64.movW0_0,
|
||||
patchID: "launch_constraints_mov",
|
||||
patchID: "kernel-boot-launch_constraints.mov",
|
||||
virtualAddress: va0,
|
||||
description: "mov w0,#0 [_proc_check_launch_constraints]",
|
||||
)
|
||||
emit(
|
||||
funcStart + 4,
|
||||
ARM64.ret,
|
||||
patchID: "launch_constraints_ret",
|
||||
patchID: "kernel-boot-launch_constraints.ret",
|
||||
virtualAddress: va1,
|
||||
description: "ret [_proc_check_launch_constraints]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
scan,
|
||||
ARM64.nop,
|
||||
patchID: "kernel.post_validation.nop_tbnz",
|
||||
patchID: "kernel-boot-post_validation.nop_tbnz",
|
||||
virtualAddress: va,
|
||||
description: "NOP \(insn.mnemonic) \(insn.operandString) [txm post-validation]",
|
||||
)
|
||||
@@ -153,7 +153,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.cmpW0W0,
|
||||
patchID: "kernel.post_validation.cmp_w0_w0",
|
||||
patchID: "kernel-boot-post_validation.cmp_w0_w0",
|
||||
virtualAddress: fileOffsetToVA(patchOff),
|
||||
description: "cmp w0,w0 (was cmp w0,#imm) [postValidation]",
|
||||
)
|
||||
|
||||
+10
-8
@@ -37,12 +37,14 @@ extension KernelPatcher {
|
||||
|
||||
let sandboxRange = discoverSandboxTextRange()
|
||||
|
||||
let hooks: [(name: String, index: Int)] = [
|
||||
("file_check_mmap", 36),
|
||||
("mount_check_mount", 87),
|
||||
("mount_check_remount", 88),
|
||||
("mount_check_umount", 91),
|
||||
("vnode_check_rename", 120),
|
||||
// Each hook carries its own patch-set declaration id: the five hooks
|
||||
// belong to different effects (boot vs cfw), so there is no single prefix.
|
||||
let hooks: [(name: String, index: Int, decl: String)] = [
|
||||
("file_check_mmap", 36, "kernel-cfw-sandbox_file_check_mmap"),
|
||||
("mount_check_mount", 87, "kernel-boot-sandbox_mount_check_mount"),
|
||||
("mount_check_remount", 88, "kernel-boot-sandbox_mount_check_remount"),
|
||||
("mount_check_umount", 91, "kernel-cfw-sandbox_mount_check_umount"),
|
||||
("vnode_check_rename", 120, "kernel-cfw-sandbox_vnode_check_rename"),
|
||||
]
|
||||
|
||||
var patchedCount = 0
|
||||
@@ -73,14 +75,14 @@ extension KernelPatcher {
|
||||
emit(
|
||||
funcOff,
|
||||
ARM64.movX0_0,
|
||||
patchID: "kernel.sandbox.\(hook.name).mov_x0_0",
|
||||
patchID: "\(hook.decl).mov_x0_0",
|
||||
virtualAddress: va,
|
||||
description: "mov x0,#0 [_hook_\(hook.name)]",
|
||||
)
|
||||
emit(
|
||||
funcOff + 4,
|
||||
ARM64.ret,
|
||||
patchID: "kernel.sandbox.\(hook.name).ret",
|
||||
patchID: "\(hook.decl).ret",
|
||||
virtualAddress: va.map { $0 + 4 },
|
||||
description: "ret [_hook_\(hook.name)]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ extension KernelPatcher {
|
||||
emit(
|
||||
back,
|
||||
ARM64.nop,
|
||||
patchID: "kernel.bsd_init_rootvp",
|
||||
patchID: "kernel-boot-bsd_init_rootvp",
|
||||
virtualAddress: va,
|
||||
description: "NOP \(insn.mnemonic) (rootvp auth) [_bsd_init]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -146,7 +146,7 @@ extension KernelExperimentalPatcher {
|
||||
let va = fileOffsetToVA(cstringStart)
|
||||
emit(cstringStart,
|
||||
Data([0x58]),
|
||||
patchID: "kernelcache_exp.hv_vmm_oid_rename",
|
||||
patchID: "kernel-exp-hv_vmm.oid_rename",
|
||||
virtualAddress: va,
|
||||
description: "Part A: rename OID name 'h' -> 'X' "
|
||||
+ "('hv_vmm_present' -> 'Xv_vmm_present')")
|
||||
@@ -244,7 +244,7 @@ extension KernelExperimentalPatcher {
|
||||
let va = fileOffsetToVA(mangleOffset)
|
||||
emit(mangleOffset,
|
||||
Data([0x58]),
|
||||
patchID: "kernelcache_exp.hv_vmm_internal_caller_mangle",
|
||||
patchID: "kernel-exp-hv_vmm.internal_caller_mangle",
|
||||
virtualAddress: va,
|
||||
description: "Part B (\(site.label)): byte-5 mangle "
|
||||
+ "'h' -> 'X' at foff 0x"
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
targetOff,
|
||||
ARM64.movW0_0,
|
||||
patchID: "jb.amfi_execve.kill_return",
|
||||
patchID: "kernel-boot-amfi_execve.kill_return",
|
||||
description: "mov w0,#0 [AMFI kill return → allow]",
|
||||
)
|
||||
|
||||
|
||||
+4
-4
@@ -134,28 +134,28 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
funcStart,
|
||||
ARM64.movX0_1,
|
||||
patchID: "amfi_trustcache_1",
|
||||
patchID: "kernel-boot-amfi_trustcache.1",
|
||||
virtualAddress: va0,
|
||||
description: "mov x0,#1 [AMFIIsCDHashInTrustCache]",
|
||||
)
|
||||
emit(
|
||||
funcStart + 4,
|
||||
ARM64.cbzX2_8,
|
||||
patchID: "amfi_trustcache_2",
|
||||
patchID: "kernel-boot-amfi_trustcache.2",
|
||||
virtualAddress: va1,
|
||||
description: "cbz x2,+8 [AMFIIsCDHashInTrustCache]",
|
||||
)
|
||||
emit(
|
||||
funcStart + 8,
|
||||
ARM64.strX0X2,
|
||||
patchID: "amfi_trustcache_3",
|
||||
patchID: "kernel-boot-amfi_trustcache.3",
|
||||
virtualAddress: va2,
|
||||
description: "str x0,[x2] [AMFIIsCDHashInTrustCache]",
|
||||
)
|
||||
emit(
|
||||
funcStart + 12,
|
||||
ARM64.ret,
|
||||
patchID: "amfi_trustcache_4",
|
||||
patchID: "kernel-boot-amfi_trustcache.4",
|
||||
virtualAddress: va3,
|
||||
description: "ret [AMFIIsCDHashInTrustCache]",
|
||||
)
|
||||
|
||||
+4
-4
@@ -108,7 +108,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
dCaveOff + i,
|
||||
Data(chunk),
|
||||
patchID: "jb.cred_label_update_execve.deny_cave",
|
||||
patchID: "kernel-boot-cred_label_update_execve.deny_cave",
|
||||
description: "deny_trampoline+\(i) [_cred_label_update_execve C21-v3]",
|
||||
)
|
||||
}
|
||||
@@ -121,7 +121,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
dOff,
|
||||
branchToCave,
|
||||
patchID: "jb.cred_label_update_execve.deny_redirect",
|
||||
patchID: "kernel-boot-cred_label_update_execve.deny_redirect",
|
||||
description: "b deny cave [_cred_label_update_execve C21-v3 exit @ 0x\(String(format: "%X", dOff))]",
|
||||
)
|
||||
}
|
||||
@@ -161,7 +161,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
successCaveOff + i,
|
||||
Data(chunk),
|
||||
patchID: "jb.cred_label_update_execve.success_cave",
|
||||
patchID: "kernel-boot-cred_label_update_execve.success_cave",
|
||||
description: "success_trampoline+\(i) [_cred_label_update_execve C21-v3]",
|
||||
)
|
||||
}
|
||||
@@ -175,7 +175,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
exitOff,
|
||||
branchToCave,
|
||||
patchID: "jb.cred_label_update_execve.success_redirect",
|
||||
patchID: "kernel-boot-cred_label_update_execve.success_redirect",
|
||||
description: "b success cave [_cred_label_update_execve C21-v3 exit @ 0x\(String(format: "%X", exitOff))]",
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -89,14 +89,14 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
entryOff,
|
||||
newEntry,
|
||||
patchID: "jb.hook_cred_label.ops_retarget",
|
||||
patchID: "kernel-boot-hook_cred_label.ops_retarget",
|
||||
description: "retarget ops[\(Self.hookCredLabelIndex)] to faithful C23 cave [_hook_cred_label_update_execve]",
|
||||
)
|
||||
|
||||
emit(
|
||||
caveOff,
|
||||
caveBytes,
|
||||
patchID: "jb.hook_cred_label.c23_cave",
|
||||
patchID: "kernel-boot-hook_cred_label.c23_cave",
|
||||
description: "faithful upstream C23 cave (vnode getattr -> uid/gid/P_SUGID fixup -> wrapper)",
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
blOff,
|
||||
bBytes,
|
||||
patchID: "jb.load_dylinker.policy_bypass",
|
||||
patchID: "kernel-boot-load_dylinker.policy_bypass",
|
||||
virtualAddress: fileOffsetToVA(blOff),
|
||||
description: "b #0x\(String(format: "%X", allowTarget - blOff)) [_load_dylinker policy bypass]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.cmpW0W0,
|
||||
patchID: "jb.post_validation.cmp_w0_w0",
|
||||
patchID: "kernel-boot-post_validation_unsigned.cmp_w0_w0",
|
||||
virtualAddress: fileOffsetToVA(patchOff),
|
||||
description: "cmp w0,w0 [postValidation additional]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
cmpOff,
|
||||
newBytes,
|
||||
patchID: "iomfb_swapend_handler_size",
|
||||
patchID: "kernel-boot-iomfb_swapend.handler_size",
|
||||
virtualAddress: va,
|
||||
description: "swap_submit cmp w2,#0x588 -> #0x6e0 [accept iOS 27 native SwapEnd struct]",
|
||||
)
|
||||
@@ -136,7 +136,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
sizeFieldOff,
|
||||
newBytes,
|
||||
patchID: "iomfb_swapend_variable_size",
|
||||
patchID: "kernel-boot-iomfb_swapend.variable_size",
|
||||
virtualAddress: va,
|
||||
description: "SwapEnd checkStructureInputSize 0x588 -> variable [accept iOS 27 native IOMFBSwapRec]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.nvram_verify_permission",
|
||||
patchID: "kernel-cfw-nvram_verify_permission",
|
||||
virtualAddress: va,
|
||||
description: "NOP [verifyPermission NVRAM]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// KernelJailbreakPatchThreadSetState.swift — optional Frida Stalker support.
|
||||
//
|
||||
// Declared as `kernelcache_frida.thread_set_state_entitlement_flag`, off in
|
||||
// Declared as `kernel-exp-frida_thread_set_state_entitlement_flag`, off in
|
||||
// `standard`.
|
||||
//
|
||||
// Frida follows an existing thread via thread_set_state_from_user, whose flags
|
||||
@@ -80,7 +80,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
setterOff,
|
||||
bytes,
|
||||
patchID: "kernelcache_frida.thread_set_state_entitlement_flag",
|
||||
patchID: "kernel-exp-frida_thread_set_state_entitlement_flag",
|
||||
virtualAddress: fileOffsetToVA(setterOff),
|
||||
description: "clear TSSF_CHECK_ENTITLEMENT (0x201 -> 0x1) [thread_set_state user setter, --frida]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// KernelJailbreakPatchVmMapDelete.swift — optional Frida Stalker support.
|
||||
//
|
||||
// Declared as `kernelcache_frida.vm_map_delete_immutable_code`, off in `standard`.
|
||||
// Declared as `kernel-exp-frida_vm_map_delete_immutable_code`, off in `standard`.
|
||||
//
|
||||
// Frida's write-then-flip leaves a permanent CSM mapping at current RW / max RWX;
|
||||
// vm_map_delete's immutable-code exception tests current-protection EXECUTE, which
|
||||
@@ -67,7 +67,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
gate.offset,
|
||||
bytes,
|
||||
patchID: "kernelcache_frida.vm_map_delete_immutable_code",
|
||||
patchID: "kernel-exp-frida_vm_map_delete_immutable_code",
|
||||
virtualAddress: fileOffsetToVA(gate.offset),
|
||||
description: "\(gate.nonzero ? "tbnz" : "tbz") entry max_protection.X [vm_map_delete immutable-code \(gate.shape), frida]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
back + 4,
|
||||
bBytes,
|
||||
patchID: "jb.port_to_map.skip_panic",
|
||||
patchID: "kernel-boot-port_to_map.skip_panic",
|
||||
virtualAddress: fileOffsetToVA(back + 4),
|
||||
description: "b 0x\(String(format: "%X", branchTarget)) [_convert_port_to_map skip panic]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.cmpX0X0,
|
||||
patchID: "kernelcache_jb.shared_region_map",
|
||||
patchID: "kernel-boot-shared_region_map",
|
||||
virtualAddress: va,
|
||||
description: "cmp x0,x0 [_shared_region_map_and_slide_setup]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.vm_fault_enter_prepare",
|
||||
patchID: "kernel-boot-vm_fault_enter_prepare",
|
||||
virtualAddress: va,
|
||||
description: "NOP [_vm_fault_enter_prepare]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
brOff,
|
||||
bBytes,
|
||||
patchID: "kernelcache_jb.vm_map_protect",
|
||||
patchID: "kernel-boot-vm_map_protect",
|
||||
virtualAddress: fileOffsetToVA(brOff),
|
||||
description: "b #0x\(String(format: "%X", delta)) "
|
||||
+ "[_vm_map_protect skip W^X downgrade, shape \(shape)]",
|
||||
|
||||
+4
-4
@@ -83,7 +83,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
caveOff,
|
||||
caveBytes,
|
||||
patchID: "jb.kcall10.cave",
|
||||
patchID: "kernel-boot-kcall10.cave",
|
||||
description: "kcall10 ABI-correct cave (target + 7 args -> uint64 x0)",
|
||||
)
|
||||
|
||||
@@ -96,7 +96,7 @@ extension KernelJailbreakPatcher {
|
||||
key: 0,
|
||||
addrDiv: 0,
|
||||
),
|
||||
patchID: "jb.kcall10.sy_call",
|
||||
patchID: "kernel-boot-kcall10.sy_call",
|
||||
description: "sysent[439].sy_call = cave 0x\(String(format: "%X", caveOff)) (auth rebase, div=0xBCAD, next=\(callNext)) [kcall10]",
|
||||
)
|
||||
|
||||
@@ -109,7 +109,7 @@ extension KernelJailbreakPatcher {
|
||||
key: mungeKey,
|
||||
addrDiv: mungeAddrDiv,
|
||||
),
|
||||
patchID: "jb.kcall10.sy_munge",
|
||||
patchID: "kernel-boot-kcall10.sy_munge",
|
||||
description: "sysent[439].sy_arg_munge32 = 8-arg helper 0x\(String(format: "%X", mungerTarget)) [kcall10]",
|
||||
)
|
||||
|
||||
@@ -123,7 +123,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
entry439 + 16,
|
||||
metadata,
|
||||
patchID: "jb.kcall10.sysent_meta",
|
||||
patchID: "kernel-boot-kcall10.sysent_meta",
|
||||
description: "sysent[439].sy_return_type=7,sy_narg=8,sy_arg_bytes=0x20 [kcall10]",
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -74,14 +74,14 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
guardA,
|
||||
ARM64.nop,
|
||||
patchID: "jb.proc_pidinfo.nop_guard_a",
|
||||
patchID: "kernel-cfw-proc_pidinfo.nop_guard_a",
|
||||
virtualAddress: fileOffsetToVA(guardA),
|
||||
description: "NOP [_proc_pidinfo pid-0 guard A]",
|
||||
)
|
||||
emit(
|
||||
guardB,
|
||||
ARM64.nop,
|
||||
patchID: "jb.proc_pidinfo.nop_guard_b",
|
||||
patchID: "kernel-cfw-proc_pidinfo.nop_guard_b",
|
||||
virtualAddress: fileOffsetToVA(guardB),
|
||||
description: "NOP [_proc_pidinfo pid-0 guard B]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -40,14 +40,14 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
firstCbz,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.spawn_validate_persona.cbz1",
|
||||
patchID: "kernel-boot-spawn_validate_persona.cbz1",
|
||||
virtualAddress: va1,
|
||||
description: "NOP [_spawn_validate_persona pid-slot guard]",
|
||||
)
|
||||
emit(
|
||||
secondCbz,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.spawn_validate_persona.cbz2",
|
||||
patchID: "kernel-boot-spawn_validate_persona.cbz2",
|
||||
virtualAddress: va2,
|
||||
description: "NOP [_spawn_validate_persona persona-slot guard]",
|
||||
)
|
||||
|
||||
+3
-3
@@ -83,21 +83,21 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
callOff,
|
||||
ARM64.encodeU32(movX17X0),
|
||||
patchID: "jb.syscallmask.save_selector",
|
||||
patchID: "kernel-boot-syscallmask.save_selector",
|
||||
description: "mov x17,x0 [syscallmask C22 save RO selector]",
|
||||
)
|
||||
|
||||
emit(
|
||||
branchOff,
|
||||
branchToCave,
|
||||
patchID: "jb.syscallmask.tail_redirect",
|
||||
patchID: "kernel-boot-syscallmask.tail_redirect",
|
||||
description: "b cave [syscallmask C22 mutate mask then setter]",
|
||||
)
|
||||
|
||||
emit(
|
||||
caveOff,
|
||||
caveBytes,
|
||||
patchID: "jb.syscallmask.c22_cave",
|
||||
patchID: "kernel-boot-syscallmask.c22_cave",
|
||||
description: "syscallmask C22 cave (ff blob 0x\(String(format: "%X", Self.syscallmaskFFBlobSize)) + structural mutator + setter tail)",
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
site,
|
||||
ARM64.cmpXzrXzr,
|
||||
patchID: "task_conversion_eval",
|
||||
patchID: "kernel-boot-task_conversion_eval",
|
||||
virtualAddress: va,
|
||||
description: "cmp xzr,xzr [_task_conversion_eval_internal]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.task_for_pid",
|
||||
patchID: "kernel-cfw-task_for_pid",
|
||||
virtualAddress: va,
|
||||
description: "NOP [_task_for_pid pid==0 gate]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
low32,
|
||||
Data([0, 0, 0, 0]),
|
||||
patchID: "kernelcache_jb.thid_should_crash",
|
||||
patchID: "kernel-boot-thid_should_crash",
|
||||
virtualAddress: va,
|
||||
description: "zero [_thid_should_crash]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
cbzOff,
|
||||
bBytes,
|
||||
patchID: "container_manager_upcall_force_success",
|
||||
patchID: "kernel-boot-container_manager_upcall_force_success",
|
||||
virtualAddress: va,
|
||||
description: "cbz w0 -> b [force container-manager exec upcall success; skip autobox/temporary-sandbox]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
cbzOff,
|
||||
bBytes,
|
||||
patchID: "exec_security_policy_kill",
|
||||
patchID: "kernel-boot-exec_security_policy_kill",
|
||||
virtualAddress: va,
|
||||
description: "cbz -> b [exec ip_mac_return SECURITY_POLICY kill bypass]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -38,13 +38,13 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
entryOff,
|
||||
newEntry,
|
||||
patchID: "jb.fpfs_scoped_open.ops_retarget",
|
||||
patchID: "kernel-boot-fpfs_scoped_open.ops_retarget",
|
||||
description: "ops[267] -> FileProvider-scoped vnode_check_open trampoline",
|
||||
)
|
||||
emit(
|
||||
caveOff,
|
||||
caveBytes,
|
||||
patchID: "jb.fpfs_scoped_open.cave",
|
||||
patchID: "kernel-boot-fpfs_scoped_open.cave",
|
||||
description: "trampoline: FileProvider daemons -> real check, else allow",
|
||||
)
|
||||
return true
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
off + 4,
|
||||
patchBytes,
|
||||
patchID: "iouc_macf_gate",
|
||||
patchID: "kernel-boot-iouc_macf_gate",
|
||||
virtualAddress: va,
|
||||
description: "b #0x\(String(format: "%X", delta)) [IOUC MACF deny → allow]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
denyEntry,
|
||||
patchBytes,
|
||||
patchID: "iouc_sandbox_gate",
|
||||
patchID: "kernel-boot-iouc_sandbox_gate",
|
||||
virtualAddress: va,
|
||||
description: "b #\(delta >= 0 ? "" : "-")0x\(String(format: "%X", abs(delta))) [IOUC sandbox deny → allow]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -68,14 +68,14 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
branchOff,
|
||||
ARM64.nop,
|
||||
patchID: "kernelcache_jb.mac_mount.flag_gate",
|
||||
patchID: "kernel-boot-mac_mount.flag_gate",
|
||||
virtualAddress: va1,
|
||||
description: "NOP [___mac_mount upstream flag gate]",
|
||||
)
|
||||
emit(
|
||||
movOff,
|
||||
clearBytes,
|
||||
patchID: "kernelcache_jb.mac_mount.state_clear",
|
||||
patchID: "kernel-boot-mac_mount.state_clear",
|
||||
virtualAddress: va2,
|
||||
description: "mov x,xzr [___mac_mount upstream state clear]",
|
||||
)
|
||||
|
||||
+2
-2
@@ -27,14 +27,14 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
policy,
|
||||
ARM64.movX0_0,
|
||||
patchID: "jb.proc_security_policy.mov_x0_0",
|
||||
patchID: "kernel-boot-proc_security_policy.mov_x0_0",
|
||||
virtualAddress: fileOffsetToVA(policy),
|
||||
description: "mov x0,#0 [_proc_security_policy]",
|
||||
)
|
||||
emit(
|
||||
policy + 4,
|
||||
ARM64.ret,
|
||||
patchID: "jb.proc_security_policy.ret",
|
||||
patchID: "kernel-boot-proc_security_policy.ret",
|
||||
virtualAddress: fileOffsetToVA(policy + 4),
|
||||
description: "ret [_proc_security_policy]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
entryOff,
|
||||
newBytes,
|
||||
patchID: "sandbox_ext_\(idx)",
|
||||
patchID: "kernel-boot-sandbox_ext.\(idx)",
|
||||
virtualAddress: nil,
|
||||
description: "ops[\(idx)] -> allow stub [_hook_\(hookName)]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
branchOff,
|
||||
ARM64.nop,
|
||||
patchID: "jb.bsd_init_auth.nop_cbnz",
|
||||
patchID: "kernel-boot-bsd_init_auth.nop_cbnz",
|
||||
virtualAddress: fileOffsetToVA(branchOff),
|
||||
description: "NOP cbnz (rootvp auth) [_bsd_init]",
|
||||
)
|
||||
|
||||
+5
-5
@@ -56,7 +56,7 @@ extension KernelJailbreakPatcher {
|
||||
log("\n[JB] DiskImages2 GATE1: CreateDevice controller-ABI b.ne -> nop")
|
||||
return nopAbiVersionGate(
|
||||
funcSig: "static IOReturn DIDeviceCreatorUserClient::CreateDevice(OSObject *, void *, IOExternalMethodArguments *)",
|
||||
patchID: "di2_createdevice_abi",
|
||||
patchID: "kernel-boot-di2.createdevice_abi",
|
||||
desc: "nop [DI2 CreateDevice controller-ABI cmp#9/b.ne gate]",
|
||||
)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ extension KernelJailbreakPatcher {
|
||||
log("\n[JB] DiskImages2 GATE2b: Connect daemon-ABI b.ne -> nop")
|
||||
return nopAbiVersionGate(
|
||||
funcSig: "static IOReturn DIDeviceIOUserClient::Connect(OSObject *, void *, IOExternalMethodArguments *)",
|
||||
patchID: "di2_connect_abi",
|
||||
patchID: "kernel-boot-di2.connect_abi",
|
||||
desc: "nop [DI2 Connect daemon-ABI cmp#9/b.ne gate]",
|
||||
)
|
||||
}
|
||||
@@ -156,12 +156,12 @@ extension KernelJailbreakPatcher {
|
||||
var ok = applyDI2AllocPortsSize(at: allocSite)
|
||||
ok = applyFieldLoadMov800(
|
||||
at: f1,
|
||||
patchID: "di2_notif_boundcheck_d8",
|
||||
patchID: "kernel-boot-di2.notif_boundcheck_d8",
|
||||
desc: "mov wD,#0x800 [DI2 RegisterNotificationPort bound-check field1 @+0xd8]",
|
||||
) && ok
|
||||
ok = applyFieldLoadMov800(
|
||||
at: f2,
|
||||
patchID: "di2_notif_boundcheck_e8",
|
||||
patchID: "kernel-boot-di2.notif_boundcheck_e8",
|
||||
desc: "mov wD,#0x800 [DI2 RegisterNotificationPort bound-check field2 @+0xe8]",
|
||||
) && ok
|
||||
return ok
|
||||
@@ -236,7 +236,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
lslOff,
|
||||
bytes,
|
||||
patchID: "di2_allocports_size",
|
||||
patchID: "kernel-boot-di2.allocports_size",
|
||||
virtualAddress: fileOffsetToVA(lslOff),
|
||||
description: "mov x1,#0x4000 [DI2 AllocPortsArray widen notif-ports alloc to 0x800 entries]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
patchOff,
|
||||
ARM64.nop,
|
||||
patchID: "jb.dounmount.nop_cleanup_bl",
|
||||
patchID: "kernel-boot-dounmount.nop_cleanup_bl",
|
||||
virtualAddress: fileOffsetToVA(patchOff),
|
||||
description: "NOP [_dounmount upstream cleanup call]",
|
||||
)
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ extension KernelJailbreakPatcher {
|
||||
emit(
|
||||
off,
|
||||
patchBytes,
|
||||
patchID: "jb.io_secure_bsd_root.zero_return",
|
||||
patchID: "kernel-boot-io_secure_bsd_root.zero_return",
|
||||
virtualAddress: fileOffsetToVA(off),
|
||||
description: "mov \(destReg), #0 [_IOSecureBSDRoot SecureRootName allow]",
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class KernelPatcher: KernelPatcherBase, BufferedPatcher {
|
||||
/// non-dev variants. Always required on iOS 18 bases: their older
|
||||
/// userland (runningboardd/SpringBoard) trips a Mach port guard
|
||||
/// "flavor 10" that crash-loops the UI. On other bases it is off: the
|
||||
/// `kernel.thread_guard_violation` declaration is pinned to iOS 18, and no
|
||||
/// `kernel-boot-thread_guard_violation` declaration is pinned to iOS 18, and no
|
||||
/// preset or checkmark can widen a version gate, so a 26.x or 27.x base cannot
|
||||
/// ask for it any more. What it used to be for: some
|
||||
/// third-party apps calling task_swap_exception_ports() (crash-reporting/
|
||||
|
||||
+19
-19
@@ -22,7 +22,7 @@ public enum FirmwareBootChainPatchSet {
|
||||
// MARK: AVPBooter
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "avpbooter.dgst_bypass",
|
||||
identifier: "avpbooter-boot-dgst_bypass",
|
||||
title: "AVPBooter digest bypass",
|
||||
summary: "Accepts the resealed boot images instead of the stock digests.",
|
||||
target: .firmware(.avpBooter),
|
||||
@@ -32,20 +32,20 @@ public enum FirmwareBootChainPatchSet {
|
||||
// MARK: iBSS
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibss.serial_label",
|
||||
identifier: "ibss-cfw-serial_label",
|
||||
title: "iBSS serial label",
|
||||
summary: "Tags iBSS serial output so the boot log names its stage.",
|
||||
target: .firmware(.iBSS),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibss.image4_callback",
|
||||
identifier: "ibss-boot-image4_callback",
|
||||
title: "iBSS image-4 callback",
|
||||
summary: "Lets iBSS load the resealed next stage.",
|
||||
target: .firmware(.iBSS),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibss_jb.skip_generate_nonce",
|
||||
identifier: "ibss-boot-skip_generate_nonce",
|
||||
title: "iBSS nonce generation skip",
|
||||
summary: "Keeps the boot nonce stable so a personalised image stays valid.",
|
||||
target: .firmware(.iBSS),
|
||||
@@ -55,27 +55,27 @@ public enum FirmwareBootChainPatchSet {
|
||||
// MARK: iBEC
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibec.serial_label",
|
||||
identifier: "ibec-cfw-serial_label",
|
||||
title: "iBEC serial label",
|
||||
summary: "Tags iBEC serial output so the boot log names its stage.",
|
||||
target: .firmware(.iBEC),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibec.image4_callback",
|
||||
identifier: "ibec-boot-image4_callback",
|
||||
title: "iBEC image-4 callback",
|
||||
summary: "Lets iBEC load the resealed kernelcache.",
|
||||
target: .firmware(.iBEC),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibec.boot_args",
|
||||
identifier: "ibec-boot-boot_args",
|
||||
title: "iBEC boot arguments",
|
||||
summary: "Installs the research boot-args string iBEC hands the kernel.",
|
||||
target: .firmware(.iBEC),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "ibec.bootx_precondition",
|
||||
identifier: "ibec-boot-bootx_precondition",
|
||||
title: "iBEC bootx precondition",
|
||||
summary: "Drops the precondition that would refuse a patched chain.",
|
||||
target: .firmware(.iBEC),
|
||||
@@ -85,34 +85,34 @@ public enum FirmwareBootChainPatchSet {
|
||||
// MARK: LLB
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "llb.serial_label",
|
||||
identifier: "llb-cfw-serial_label",
|
||||
title: "LLB serial label",
|
||||
summary: "Tags LLB serial output so the boot log names its stage.",
|
||||
target: .firmware(.llb),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "llb.image4_callback",
|
||||
identifier: "llb-boot-image4_callback",
|
||||
title: "LLB image-4 callback",
|
||||
summary: "Lets LLB load the resealed next stage.",
|
||||
target: .firmware(.llb),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "llb.boot_args",
|
||||
identifier: "llb-boot-boot_args",
|
||||
title: "LLB boot arguments",
|
||||
summary: "Installs the research boot-args string LLB passes along.",
|
||||
target: .firmware(.llb),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "llb.rootfs",
|
||||
identifier: "llb-boot-rootfs",
|
||||
title: "LLB root filesystem checks",
|
||||
summary: "Skips the signature, size and null checks on the patched root image.",
|
||||
target: .firmware(.llb),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "llb.panic_bypass",
|
||||
identifier: "llb-boot-panic_bypass",
|
||||
title: "LLB panic bypass",
|
||||
summary: "Turns LLB's image-policy panic into a continue.",
|
||||
target: .firmware(.llb),
|
||||
@@ -122,40 +122,40 @@ public enum FirmwareBootChainPatchSet {
|
||||
// MARK: TXM
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm.trustcache_bypass",
|
||||
identifier: "txm-boot-trustcache_bypass",
|
||||
title: "TXM trust cache bypass",
|
||||
summary: "Lets TXM admit the guest's own trust cache entries.",
|
||||
target: .firmware(.txm),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm_dev.get_task_allow",
|
||||
identifier: "txm-cfw-get_task_allow",
|
||||
title: "TXM get-task-allow",
|
||||
summary: "Grants get-task-allow so a debugger can attach in the guest.",
|
||||
target: .firmware(.txm),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm_dev.debugger_entitlement",
|
||||
identifier: "txm-cfw-debugger_entitlement",
|
||||
title: "TXM debugger entitlement",
|
||||
summary: "Grants the task_for_pid debugger entitlement.",
|
||||
target: .firmware(.txm),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm_dev.developer_mode_bypass",
|
||||
identifier: "txm-boot-developer_mode_bypass",
|
||||
title: "TXM developer mode",
|
||||
summary: "Reports developer mode on without the enrolment dance.",
|
||||
target: .firmware(.txm),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm_dev.selector24_bypass",
|
||||
identifier: "txm-boot-selector24_bypass",
|
||||
title: "TXM selector 24 bypass",
|
||||
summary: "Lets the selector-24 code-signing query succeed.",
|
||||
target: .firmware(.txm),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "txm_dev.sel42_29",
|
||||
identifier: "txm-boot-sel42_29",
|
||||
title: "TXM selector 42/29 shellcode",
|
||||
summary: "Installs the selector-42/29 stub that admits guest signatures.",
|
||||
target: .firmware(.txm),
|
||||
|
||||
+23
-23
@@ -39,22 +39,22 @@ public enum FirmwareDeviceTreePatchSet {
|
||||
// MARK: Board Presentation
|
||||
|
||||
property(
|
||||
"devicetree.serial_number",
|
||||
"devicetree-cfw-serial_number",
|
||||
"Serial number",
|
||||
"Gives the board a well-formed serial number.",
|
||||
),
|
||||
property(
|
||||
"devicetree.home_button_type",
|
||||
"devicetree-cfw-home_button_type",
|
||||
"Home button type",
|
||||
"Declares a gesture-driven device with no home button.",
|
||||
),
|
||||
property(
|
||||
"devicetree.artwork_device_subtype",
|
||||
"devicetree-cfw-artwork_device_subtype",
|
||||
"Artwork device subtype",
|
||||
"Picks the artwork subtype the guest UI lays out against.",
|
||||
),
|
||||
property(
|
||||
"devicetree.island_notch_location",
|
||||
"devicetree-cfw-island_notch_location",
|
||||
"Island notch location",
|
||||
"Places the sensor cutout so status bar layout matches the display.",
|
||||
),
|
||||
@@ -62,42 +62,42 @@ public enum FirmwareDeviceTreePatchSet {
|
||||
// MARK: Device Identity
|
||||
|
||||
property(
|
||||
"devicetree.target_sub_type",
|
||||
"devicetree-exp-target_sub_type",
|
||||
"Target sub type",
|
||||
"Reports the iPhone17,3 target sub type.",
|
||||
),
|
||||
property(
|
||||
"devicetree.compatible_secondary",
|
||||
"devicetree-exp-compatible_secondary",
|
||||
"Compatible list",
|
||||
"Adds the iPhone17,3 entry to the board's compatible list.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.fdr_product_type",
|
||||
"devicetree-exp-product_fdr_product_type",
|
||||
"FDR product type",
|
||||
"Reports the iPhone17,3 product type to FDR.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.sub_product_type",
|
||||
"devicetree-exp-product_sub_product_type",
|
||||
"Sub product type",
|
||||
"Reports the iPhone17,3 sub product type.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.unique_model",
|
||||
"devicetree-exp-product_unique_model",
|
||||
"Unique model code",
|
||||
"Reports the model code a stock app reads for the device name.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.gestalt_variants_rename",
|
||||
"devicetree-exp-product_gestalt_variants_rename",
|
||||
"Gestalt variants",
|
||||
"Renames the gestalt variants node so the identity is consistent.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.device_type",
|
||||
"devicetree-exp-arm_io_device_type",
|
||||
"SoC device type",
|
||||
"Reports the SoC device type the identity implies.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.soc_generation",
|
||||
"devicetree-exp-arm_io_soc_generation",
|
||||
"SoC generation",
|
||||
"Reports the SoC generation the identity implies.",
|
||||
),
|
||||
@@ -105,12 +105,12 @@ public enum FirmwareDeviceTreePatchSet {
|
||||
// MARK: Camera Geometry
|
||||
|
||||
property(
|
||||
"devicetree.product.front_cam_offset",
|
||||
"devicetree-cfw-product_front_cam_offset",
|
||||
"Front camera offset",
|
||||
"Places the front camera where the identity's hardware has it.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.rear_cam_offset",
|
||||
"devicetree-cfw-product_rear_cam_offset",
|
||||
"Rear camera offset",
|
||||
"Places the rear camera where the identity's hardware has it.",
|
||||
),
|
||||
@@ -118,47 +118,47 @@ public enum FirmwareDeviceTreePatchSet {
|
||||
// MARK: Added Nodes
|
||||
|
||||
property(
|
||||
"devicetree.product.camera_node",
|
||||
"devicetree-cfw-product_camera_node",
|
||||
"Camera node",
|
||||
"Adds the camera node the virtual camera is published under.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.facetime_node",
|
||||
"devicetree-cfw-product_facetime_node",
|
||||
"FaceTime node",
|
||||
"Adds the FaceTime camera node.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.audio_node",
|
||||
"devicetree-cfw-product_audio_node",
|
||||
"Audio node",
|
||||
"Adds the audio topology node so the guest has speakers.",
|
||||
),
|
||||
property(
|
||||
"devicetree.product.iopm_node",
|
||||
"devicetree-cfw-product_iopm_node",
|
||||
"Power management node",
|
||||
"Adds the IOPM node the power stack expects.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.smc_stub",
|
||||
"devicetree-cfw-arm_io_smc_stub",
|
||||
"SMC stub",
|
||||
"Adds a stub SMC so the power and thermal clients attach.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.smc.iop_smc_nub_stub",
|
||||
"devicetree-cfw-arm_io_smc_iop_smc_nub_stub",
|
||||
"SMC nub stub",
|
||||
"Adds the SMC nub the IOP driver binds to.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.smc.smc_ext_charger_camera_driver",
|
||||
"devicetree-cfw-arm_io_smc_ext_charger_camera_driver",
|
||||
"SMC charger and camera driver",
|
||||
"Publishes the charger and camera driver under the stub SMC.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.isp_camera_flags",
|
||||
"devicetree-cfw-arm_io_isp_camera_flags",
|
||||
"ISP camera flags",
|
||||
"Sets the ISP flags the virtual camera pipeline needs.",
|
||||
),
|
||||
property(
|
||||
"devicetree.arm_io.ispRtb_camera_flags",
|
||||
"devicetree-cfw-arm_io_isp_rtb_camera_flags",
|
||||
"ISP RTB camera flags",
|
||||
"Sets the ISP round-trip buffer flags for the camera pipeline.",
|
||||
),
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ public enum FirmwareGuestDisplayPatchSet {
|
||||
summary: "IOMFB patches that let the guest present a frame on the virtual display",
|
||||
patches: [
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "iomfb_force_kern",
|
||||
identifier: "dyld-boot-iomfb_force_kern",
|
||||
title: "IOMFB force kernel swap",
|
||||
summary: "Routes the 27 display swap through the kernel, where the virtual framebuffer lives.",
|
||||
target: .dyldSharedCache,
|
||||
@@ -25,7 +25,7 @@ public enum FirmwareGuestDisplayPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "dsc.iomfb_swapend",
|
||||
identifier: "dyld-boot-iomfb_swapend",
|
||||
title: "IOMFB swap-end size",
|
||||
summary: "Resizes the swap-end structure a 26.0 or 18.x userland submits.",
|
||||
target: .dyldSharedCache,
|
||||
|
||||
+8
-8
@@ -6,8 +6,8 @@
|
||||
// `com.vphone.patchset.kernel.hypervisor` and the device tree's identity and camera
|
||||
// nodes: on their own, each half leaves the guest inconsistent with itself.
|
||||
//
|
||||
// Everything here came from the former EXP variant. Only `camera_dsc` is on in
|
||||
// `standard`. `hv_vmm_dsc` is off for exactly the reason its kernel half is — see
|
||||
// Everything here came from the former EXP variant. Only `dyld-cfw-camera` is on in
|
||||
// `standard`. `dyld-exp-hv_vmm` is off for exactly the reason its kernel half is — see
|
||||
// `FirmwareKernelHypervisorPatchSet` for what a 26.4 guest does when the OID is
|
||||
// renamed. The watchdogd patch only matters once the hypervisor is hidden, so it
|
||||
// moves with that pair (`FirmwarePatchSetCatalog.hypervisorConcealmentPatches`).
|
||||
@@ -22,7 +22,7 @@ public enum FirmwareGuestIdentityPatchSet {
|
||||
|
||||
/// The root `model`, `target-type` and `compatible` rewrite in the restored
|
||||
/// Preboot device tree, run by `cfw install`.
|
||||
public static let prebootDeviceTreeIdentity = "preboot_devicetree.identity"
|
||||
public static let prebootDeviceTreeIdentity = "preboot-exp-devicetree_identity"
|
||||
|
||||
public static let manifest = VPhonePatchSetManifest(
|
||||
identifier: identifier,
|
||||
@@ -30,21 +30,21 @@ public enum FirmwareGuestIdentityPatchSet {
|
||||
summary: "Hypervisor concealment in the shared cache and watchdog, the Preboot identity, and the virtual camera symbols",
|
||||
patches: [
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "hv_vmm_dsc",
|
||||
identifier: "dyld-exp-hv_vmm",
|
||||
title: "Shared cache hypervisor strings",
|
||||
summary: """
|
||||
Mangles the hv_vmm_present references in the shared cache, so a userland check \
|
||||
finds nothing where the kernel set renamed the sysctl. Off by default, and \
|
||||
pointless without kernelcache_exp.hv_vmm: enable the two together or neither.
|
||||
pointless without kernel-exp-hv_vmm: enable the two together or neither.
|
||||
""",
|
||||
target: .dyldSharedCache,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "watchdogd.hv_vmm_cache",
|
||||
identifier: "system-watchdogd-exp-hv_vmm_cache",
|
||||
title: "watchdogd hypervisor cache",
|
||||
summary: """
|
||||
Forces watchdogd's cached hypervisor answer to true. Without it, watchdogd \
|
||||
panics the guest once kernelcache_exp.hv_vmm renames the sysctl, so it is \
|
||||
panics the guest once kernel-exp-hv_vmm renames the sysctl, so it is \
|
||||
off by default with the concealment and must be enabled with it.
|
||||
""",
|
||||
target: .guestExecutable(path: "/usr/libexec/watchdogd"),
|
||||
@@ -59,7 +59,7 @@ public enum FirmwareGuestIdentityPatchSet {
|
||||
target: .prebootDeviceTree,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "camera_dsc",
|
||||
identifier: "dyld-cfw-camera",
|
||||
title: "Camera shared cache symbols",
|
||||
summary: "Redirects the camera symbols the virtual camera publishes frames through.",
|
||||
target: .dyldSharedCache,
|
||||
|
||||
+20
-20
@@ -25,7 +25,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
// MARK: Shared Cache Policy
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "dsc_maxslide.zero",
|
||||
identifier: "dyld-boot-maxslide",
|
||||
title: "Shared cache max slide",
|
||||
summary: """
|
||||
Zeroes the shared cache's maximum slide. A 27 userland otherwise computes a slide \
|
||||
@@ -36,7 +36,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "lsd_embedded_reg.entitlement_gate",
|
||||
identifier: "dyld-boot-lsd_embedded_reg",
|
||||
title: "lsd registration entitlement",
|
||||
summary: "Lets lsd register the guest's embedded app bundles.",
|
||||
target: .dyldSharedCache,
|
||||
@@ -44,7 +44,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "xpc_lwcr",
|
||||
identifier: "dyld-boot-xpc_lwcr",
|
||||
title: "XPC lightweight code requirements",
|
||||
summary: "Stops XPC refusing a peer whose lightweight code requirement no longer matches.",
|
||||
target: .dyldSharedCache,
|
||||
@@ -52,7 +52,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "lockdown_mode.sysctl_error_gate",
|
||||
identifier: "dyld-boot-lockdown_mode",
|
||||
title: "Lockdown mode sysctl gate",
|
||||
summary: "Stops a failed lockdown-mode sysctl read being treated as an error.",
|
||||
target: .dyldSharedCache,
|
||||
@@ -60,7 +60,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "mis_trust_auth",
|
||||
identifier: "dyld-cfw-mis_trust_auth",
|
||||
title: "MIS online authorization",
|
||||
summary: """
|
||||
Accepts a provisioning profile that wants online authorization. The guest is \
|
||||
@@ -74,42 +74,42 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
// MARK: System Daemons
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "seputil.gigalocker_uuid",
|
||||
identifier: "system-seputil-boot-gigalocker_uuid",
|
||||
title: "seputil Gigalocker UUID",
|
||||
summary: "Points seputil at the renamed Gigalocker so key material resolves.",
|
||||
target: .guestExecutable(path: "/usr/libexec/seputil"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "diskimagesiod.is_mount_complete",
|
||||
identifier: "system-diskimagesiod-cfw-is_mount_complete",
|
||||
title: "diskimagesiod mount completion",
|
||||
summary: "Reports the personalised developer image as mounted on a 27 userland.",
|
||||
target: .guestExecutable(path: "/usr/libexec/diskimagesiod"),
|
||||
applicability: ios27,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "launchd_cache_loader.unsecure_cache_gate",
|
||||
identifier: "system-launchd_cache_loader-boot-unsecure_cache_gate",
|
||||
title: "launchd cache loader gate",
|
||||
summary: "Lets the launchd cache loader accept the patched, unsealed cache.",
|
||||
target: .guestExecutable(path: "/usr/libexec/launchd_cache_loader"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "mobileactivationd.should_hactivate",
|
||||
identifier: "system-mobileactivationd-boot-should_hactivate",
|
||||
title: "mobileactivationd activation",
|
||||
summary: "Reports the device activated, so the guest reaches the home screen.",
|
||||
target: .guestExecutable(path: "/usr/libexec/mobileactivationd"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "launchd_jetsam.panic_guard_bypass",
|
||||
identifier: "system-launchd-boot-jetsam_panic_guard_bypass",
|
||||
title: "launchd jetsam panic guard",
|
||||
summary: "Stops launchd panicking when jetsam reaps a process the VM needs.",
|
||||
target: .guestExecutable(path: "/sbin/launchd"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "installd.adhoc_signature",
|
||||
identifier: "system-installd-cfw-adhoc_signature",
|
||||
title: "installd ad-hoc signatures",
|
||||
summary: """
|
||||
Lets Xcode install an app the guest would otherwise refuse. installd asks \
|
||||
@@ -122,7 +122,7 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
target: .guestExecutable(path: "/usr/libexec/installd"),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "misagent.device_identity",
|
||||
identifier: "system-misagent-cfw-device_identity",
|
||||
title: "misagent device identity",
|
||||
summary: """
|
||||
Lets a provisioning profile written for a device you already own install on \
|
||||
@@ -136,13 +136,13 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
target: .guestExecutable(path: "/usr/libexec/misagent"),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.debugserver",
|
||||
identifier: "system-debugserver-cfw-install",
|
||||
title: "debugserver",
|
||||
summary: "Installs a debugserver that can attach in the guest.",
|
||||
target: .guestFile(path: "/usr/bin/debugserver"),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "campo.entitlements",
|
||||
identifier: "system-campo-cfw-entitlements",
|
||||
title: "Campo entitlements",
|
||||
summary: "Widens Campo's entitlements so the 27 setup assistant completes.",
|
||||
target: .guestEntitlements(path: "/System/Library/PrivateFrameworks/Campo.framework/Campo"),
|
||||
@@ -152,35 +152,35 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
// MARK: Guest Payload
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.gigalocker_rename",
|
||||
identifier: "system-gigalocker-boot-rename",
|
||||
title: "Gigalocker rename",
|
||||
summary: "Renames the data volume's Gigalocker so the guest recreates it.",
|
||||
target: .guestFile(path: "/private/var/Gigalocker"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.gpu_bundle",
|
||||
identifier: "system-extensions-boot-gpu_bundle",
|
||||
title: "GPU driver bundle",
|
||||
summary: "Installs the GPU bundle the virtual display needs.",
|
||||
target: .guestFile(path: "/System/Library/Extensions"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.vphoned",
|
||||
identifier: "system-vphoned-boot-install",
|
||||
title: "vphoned",
|
||||
summary: "Installs the guest daemon the host talks to over VSOCK.",
|
||||
target: .guestFile(path: "/usr/local/bin/vphoned"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.environment",
|
||||
identifier: "system-launchdaemons-boot-environment",
|
||||
title: "Guest environment",
|
||||
summary: "Installs the launchd environment and plists the guest tools read.",
|
||||
target: .guestFile(path: "/Library/LaunchDaemons"),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "guest.build_version",
|
||||
identifier: "system-systemversion-cfw-build_version",
|
||||
title: "Reported build version",
|
||||
summary: """
|
||||
Rewrites the guest's SystemVersion build string. Needs a build to write: the \
|
||||
@@ -194,6 +194,6 @@ public enum FirmwareGuestSystemPatchSet {
|
||||
provides: ["vphone.guest.system"],
|
||||
)
|
||||
|
||||
/// The preset parameter `guest.build_version` reads.
|
||||
/// The preset parameter `system-systemversion-cfw-build_version` reads.
|
||||
public static let buildVersionParameter = "BuildVersion"
|
||||
}
|
||||
|
||||
+18
-18
@@ -23,49 +23,49 @@ public enum FirmwareKernelBasePatchSet {
|
||||
// MARK: APFS
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.apfs_root_snapshot",
|
||||
identifier: "kernel-boot-apfs_root_snapshot",
|
||||
title: "APFS root snapshot",
|
||||
summary: "Boots the live root volume instead of its sealed snapshot.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.apfs_seal_broken",
|
||||
identifier: "kernel-boot-apfs_seal_broken",
|
||||
title: "APFS broken seal",
|
||||
summary: "Accepts a root volume whose seal the patches broke.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "apfs_graft",
|
||||
identifier: "kernel-boot-apfs_graft",
|
||||
title: "APFS graft",
|
||||
summary: "Allows grafting so the cryptex payload mounts.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.apfs_vfsop_mount",
|
||||
identifier: "kernel-boot-apfs_vfsop_mount",
|
||||
title: "APFS mount entry check",
|
||||
summary: "Drops the vfsop_mount refusal for an unsealed volume.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.apfs_mount_upgrade_checks",
|
||||
identifier: "kernel-boot-apfs_mount_upgrade_checks",
|
||||
title: "APFS mount upgrade checks",
|
||||
summary: "Lets a read-only root be remounted writable.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.handle_fsioc_graft",
|
||||
identifier: "kernel-boot-handle_fsioc_graft",
|
||||
title: "APFS graft ioctl",
|
||||
summary: "Lets the graft ioctl succeed from the guest.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.handle_get_dev_by_role",
|
||||
identifier: "kernel-boot-handle_get_dev_by_role",
|
||||
title: "APFS device-by-role gates",
|
||||
summary: "Resolves volume roles for the patched container layout.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -75,7 +75,7 @@ public enum FirmwareKernelBasePatchSet {
|
||||
// MARK: Startup
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.bsd_init_rootvp",
|
||||
identifier: "kernel-boot-bsd_init_rootvp",
|
||||
title: "bsd_init root vnode",
|
||||
summary: "Keeps bsd_init going when the root vnode is the patched image.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -85,28 +85,28 @@ public enum FirmwareKernelBasePatchSet {
|
||||
// MARK: Code Signing
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.post_validation",
|
||||
identifier: "kernel-boot-post_validation",
|
||||
title: "Post-validation checks",
|
||||
summary: "Accepts signatures the patched trust cache vouches for.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "launch_constraints",
|
||||
identifier: "kernel-boot-launch_constraints",
|
||||
title: "Launch constraints",
|
||||
summary: "Stops launch constraints refusing a relocated system binary.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "dyld_policy",
|
||||
identifier: "kernel-boot-dyld_policy",
|
||||
title: "dyld loading policy",
|
||||
summary: "Lets dyld load a library from outside the sealed image.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.debugger",
|
||||
identifier: "kernel-cfw-debugger",
|
||||
title: "Debugger check",
|
||||
summary: "Reports the kernel as debuggable so task_for_pid works.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -115,33 +115,33 @@ public enum FirmwareKernelBasePatchSet {
|
||||
// MARK: Sandbox MACF Hooks
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.sandbox.file_check_mmap",
|
||||
identifier: "kernel-cfw-sandbox_file_check_mmap",
|
||||
title: "Sandbox: file_check_mmap",
|
||||
summary: "Stubs the mmap sandbox check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.sandbox.mount_check_mount",
|
||||
identifier: "kernel-boot-sandbox_mount_check_mount",
|
||||
title: "Sandbox: mount_check_mount",
|
||||
summary: "Stubs the mount sandbox check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.sandbox.mount_check_remount",
|
||||
identifier: "kernel-boot-sandbox_mount_check_remount",
|
||||
title: "Sandbox: mount_check_remount",
|
||||
summary: "Stubs the remount sandbox check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.sandbox.mount_check_umount",
|
||||
identifier: "kernel-cfw-sandbox_mount_check_umount",
|
||||
title: "Sandbox: mount_check_umount",
|
||||
summary: "Stubs the umount sandbox check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.sandbox.vnode_check_rename",
|
||||
identifier: "kernel-cfw-sandbox_vnode_check_rename",
|
||||
title: "Sandbox: vnode_check_rename",
|
||||
summary: "Stubs the rename sandbox check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -150,7 +150,7 @@ public enum FirmwareKernelBasePatchSet {
|
||||
// MARK: Mach Port Guard
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernel.thread_guard_violation",
|
||||
identifier: "kernel-boot-thread_guard_violation",
|
||||
title: "Mach port guard violation",
|
||||
summary: """
|
||||
Turns a fatal EXC_GUARD port violation into a continue. Required on an iOS 18 \
|
||||
|
||||
+2
-2
@@ -22,14 +22,14 @@ public enum FirmwareKernelFridaPatchSet {
|
||||
summary: "Kernel relaxations Frida's Stalker needs to trace and rewrite code pages",
|
||||
patches: [
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_frida.thread_set_state_entitlement_flag",
|
||||
identifier: "kernel-exp-frida_thread_set_state_entitlement_flag",
|
||||
title: "thread_set_state entitlement",
|
||||
summary: "Drops the entitlement flag thread_set_state checks, so Stalker can set thread state.",
|
||||
target: .firmware(.kernelcache),
|
||||
applicability: fridaCapable,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_frida.vm_map_delete_immutable_code",
|
||||
identifier: "kernel-exp-frida_vm_map_delete_immutable_code",
|
||||
title: "Immutable code deletion",
|
||||
summary: "Lets vm_map_delete remove an immutable code mapping, which Stalker rewrites over.",
|
||||
target: .firmware(.kernelcache),
|
||||
|
||||
+5
-5
@@ -13,8 +13,8 @@
|
||||
// blocks on a synchronous call to the throttled Bluetooth XPC service, the
|
||||
// `com.apple.locationd.migrator` data-migrator plugin hangs for over an hour, and
|
||||
// SpringBoard waits on migration — black screen, no panic. `--preset extended` or a
|
||||
// per-VM checkmark turns it back on, together with `hv_vmm_dsc` and
|
||||
// `watchdogd.hv_vmm_cache`.
|
||||
// per-VM checkmark turns it back on, together with `dyld-exp-hv_vmm` and
|
||||
// `system-watchdogd-exp-hv_vmm_cache`.
|
||||
//
|
||||
// Its own set because it is the one kernel change that is about hiding the
|
||||
// hypervisor rather than about jailbreaking, so a preset can take it or leave it
|
||||
@@ -32,13 +32,13 @@ public enum FirmwareKernelHypervisorPatchSet {
|
||||
summary: "Renames the hv_vmm_present sysctl so userland does not see the hypervisor",
|
||||
patches: [
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_exp.hv_vmm",
|
||||
identifier: "kernel-exp-hv_vmm",
|
||||
title: "hv_vmm_present sysctl",
|
||||
summary: """
|
||||
Renames the hv_vmm_present OID and mangles its internal caller, so a userland \
|
||||
check for the hypervisor finds nothing. Off by default: it leaves a freshly \
|
||||
restored 26.4 guest on a black screen. Enable it together with hv_vmm_dsc \
|
||||
and watchdogd.hv_vmm_cache, never alone.
|
||||
restored 26.4 guest on a black screen. Enable it together with dyld-exp-hv_vmm \
|
||||
and system-watchdogd-exp-hv_vmm_cache, never alone.
|
||||
""",
|
||||
target: .firmware(.kernelcache),
|
||||
),
|
||||
|
||||
+31
-31
@@ -26,42 +26,42 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Trust Cache and Code Signing
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "amfi_trustcache",
|
||||
identifier: "kernel-boot-amfi_trustcache",
|
||||
title: "AMFI trust cache",
|
||||
summary: "Admits the guest's own trust cache so unsigned binaries run.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.post_validation",
|
||||
identifier: "kernel-boot-post_validation_unsigned",
|
||||
title: "Jailbreak post-validation",
|
||||
summary: "Completes the base post-validation patch for unsigned pages.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.cred_label_update_execve",
|
||||
identifier: "kernel-boot-cred_label_update_execve",
|
||||
title: "Credential label on execve",
|
||||
summary: "Grants the platform label to every binary the guest executes.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.hook_cred_label",
|
||||
identifier: "kernel-boot-hook_cred_label",
|
||||
title: "Credential label hook",
|
||||
summary: "Retargets the MACF credential hook to the patched handler.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.amfi_execve",
|
||||
identifier: "kernel-boot-amfi_execve",
|
||||
title: "AMFI execve kill",
|
||||
summary: "Stops AMFI killing a process whose signature it dislikes.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.load_dylinker",
|
||||
identifier: "kernel-boot-load_dylinker",
|
||||
title: "Dynamic linker policy",
|
||||
summary: "Lets a binary name a dynamic linker outside the sealed image.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -71,47 +71,47 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Task and Process
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "task_conversion_eval",
|
||||
identifier: "kernel-boot-task_conversion_eval",
|
||||
title: "Task conversion evaluation",
|
||||
summary: "Allows converting a task port the caller would not normally get.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.task_for_pid",
|
||||
identifier: "kernel-cfw-task_for_pid",
|
||||
title: "task_for_pid",
|
||||
summary: "Lets task_for_pid return a port for any process.",
|
||||
target: .firmware(.kernelcache),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.port_to_map",
|
||||
identifier: "kernel-boot-port_to_map",
|
||||
title: "Port to map conversion",
|
||||
summary: "Skips the panic when a port is converted to a vm_map.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.proc_pidinfo",
|
||||
identifier: "kernel-cfw-proc_pidinfo",
|
||||
title: "proc_pidinfo guards",
|
||||
summary: "Lets proc_pidinfo report on processes the caller does not own.",
|
||||
target: .firmware(.kernelcache),
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.proc_security_policy",
|
||||
identifier: "kernel-boot-proc_security_policy",
|
||||
title: "Process security policy",
|
||||
summary: "Stubs the per-process security policy check to allow.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.spawn_validate_persona",
|
||||
identifier: "kernel-boot-spawn_validate_persona",
|
||||
title: "Spawn persona validation",
|
||||
summary: "Lets a process spawn under a persona it did not inherit.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.thid_should_crash",
|
||||
identifier: "kernel-boot-thid_should_crash",
|
||||
title: "Thread identity crash",
|
||||
summary: "Stops a thread-identity mismatch killing the process.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -121,21 +121,21 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Memory
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.vm_map_protect",
|
||||
identifier: "kernel-boot-vm_map_protect",
|
||||
title: "vm_map_protect",
|
||||
summary: "Allows making an executable mapping writable.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.vm_fault_enter_prepare",
|
||||
identifier: "kernel-boot-vm_fault_enter_prepare",
|
||||
title: "vm_fault_enter_prepare",
|
||||
summary: "Lets a fault install an unsigned executable page.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.shared_region_map",
|
||||
identifier: "kernel-boot-shared_region_map",
|
||||
title: "Shared region mapping",
|
||||
summary: "Lets the patched dyld shared cache be mapped.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -145,35 +145,35 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Filesystem
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.bsd_init_auth",
|
||||
identifier: "kernel-boot-bsd_init_auth",
|
||||
title: "bsd_init imageboot gate",
|
||||
summary: "Skips the imageboot authentication branch during startup.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.io_secure_bsd_root",
|
||||
identifier: "kernel-boot-io_secure_bsd_root",
|
||||
title: "Secure BSD root",
|
||||
summary: "Reports the root device as not security-locked.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.mac_mount",
|
||||
identifier: "kernel-boot-mac_mount",
|
||||
title: "MACF mount flags",
|
||||
summary: "Lets the guest mount writable over a sealed path.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.dounmount",
|
||||
identifier: "kernel-boot-dounmount",
|
||||
title: "dounmount cleanup",
|
||||
summary: "Skips the unmount cleanup call that would undo the bind mounts.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "kernelcache_jb.nvram_verify_permission",
|
||||
identifier: "kernel-cfw-nvram_verify_permission",
|
||||
title: "NVRAM permission check",
|
||||
summary: "Lets the guest write the NVRAM variables the jailbreak reads.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -182,21 +182,21 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Sandbox and IOUserClient
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "sandbox_ext",
|
||||
identifier: "kernel-boot-sandbox_ext",
|
||||
title: "Extended sandbox hooks",
|
||||
summary: "Retargets the remaining vnode and mount sandbox hooks to an allow stub.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "iouc_macf_gate",
|
||||
identifier: "kernel-boot-iouc_macf_gate",
|
||||
title: "IOUserClient MACF gate",
|
||||
summary: "Lets the guest open user clients MACF would refuse.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "iouc_sandbox_gate",
|
||||
identifier: "kernel-boot-iouc_sandbox_gate",
|
||||
title: "IOUserClient sandbox gate",
|
||||
summary: "Lets a sandboxed process open a user client, as a 27 userland expects.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -207,14 +207,14 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: Syscall Surface
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.kcall10",
|
||||
identifier: "kernel-boot-kcall10",
|
||||
title: "Kernel call syscall",
|
||||
summary: "Installs the syscall the jailbreak uses to call into the kernel.",
|
||||
target: .firmware(.kernelcache),
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.syscallmask",
|
||||
identifier: "kernel-boot-syscallmask",
|
||||
title: "Per-process syscall mask",
|
||||
summary: "Widens the syscall mask a process inherits.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -224,7 +224,7 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
// MARK: iOS 27 Userland
|
||||
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "di2",
|
||||
identifier: "kernel-boot-di2",
|
||||
title: "DiskImages2 client ABI",
|
||||
summary: "Matches the DiskImages2 client ABI a 27 userland calls with.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -232,7 +232,7 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "exec_security_policy_kill",
|
||||
identifier: "kernel-boot-exec_security_policy_kill",
|
||||
title: "Exec security policy kill",
|
||||
summary: "Stops the 27 exec security policy killing the process.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -240,7 +240,7 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "container_manager_upcall_force_success",
|
||||
identifier: "kernel-boot-container_manager_upcall_force_success",
|
||||
title: "Container manager upcall",
|
||||
summary: "Forces the container-manager upcall to succeed.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -248,7 +248,7 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "iomfb_swapend",
|
||||
identifier: "kernel-boot-iomfb_swapend",
|
||||
title: "IOMFB swap-end sizes",
|
||||
summary: "Accepts the 27 display driver's swap-end structure sizes.",
|
||||
target: .firmware(.kernelcache),
|
||||
@@ -256,7 +256,7 @@ public enum FirmwareKernelJailbreakPatchSet {
|
||||
bootEssential: true,
|
||||
),
|
||||
VPhonePatchDeclaration(
|
||||
identifier: "jb.fpfs_scoped_open",
|
||||
identifier: "kernel-boot-fpfs_scoped_open",
|
||||
title: "FileProvider scoped open",
|
||||
summary: "Scopes the vnode-open check to FileProvider so respring does not loop.",
|
||||
target: .firmware(.kernelcache),
|
||||
|
||||
+12
-12
@@ -59,20 +59,20 @@ public enum FirmwarePatchSetCatalog {
|
||||
/// The former EXP patches that make the guest claim to be an iPhone17,3.
|
||||
///
|
||||
/// `standard` is the JB baseline plus the camera. The camera needs the device
|
||||
/// tree's `/product/camera`, ISP and SMC nodes and `camera_dsc`, which stay on;
|
||||
/// tree's `/product/camera`, ISP and SMC nodes and `dyld-cfw-camera`, which stay on;
|
||||
/// it does not need the identity rewrites. They shipped on with the hypervisor
|
||||
/// concealment when EXP joined the JB flow, and guests from that build lost
|
||||
/// location (issue #438), so they go back to opt-in with it. `extended` or a
|
||||
/// per-VM checkmark turns them back on.
|
||||
public static let experimentalIdentityPatches: Set<String> = [
|
||||
"devicetree.target_sub_type",
|
||||
"devicetree.compatible_secondary",
|
||||
"devicetree.product.fdr_product_type",
|
||||
"devicetree.product.sub_product_type",
|
||||
"devicetree.product.unique_model",
|
||||
"devicetree.product.gestalt_variants_rename",
|
||||
"devicetree.arm_io.device_type",
|
||||
"devicetree.arm_io.soc_generation",
|
||||
"devicetree-exp-target_sub_type",
|
||||
"devicetree-exp-compatible_secondary",
|
||||
"devicetree-exp-product_fdr_product_type",
|
||||
"devicetree-exp-product_sub_product_type",
|
||||
"devicetree-exp-product_unique_model",
|
||||
"devicetree-exp-product_gestalt_variants_rename",
|
||||
"devicetree-exp-arm_io_device_type",
|
||||
"devicetree-exp-arm_io_soc_generation",
|
||||
FirmwareGuestIdentityPatchSet.prebootDeviceTreeIdentity,
|
||||
]
|
||||
|
||||
@@ -92,9 +92,9 @@ public enum FirmwarePatchSetCatalog {
|
||||
/// waits on migration forever — a black screen with no panic. See
|
||||
/// `Research/Patches/hv_vmm_present_usermode_xrefs.md`.
|
||||
public static let hypervisorConcealmentPatches: Set<String> = [
|
||||
"kernelcache_exp.hv_vmm",
|
||||
"hv_vmm_dsc",
|
||||
"watchdogd.hv_vmm_cache",
|
||||
"kernel-exp-hv_vmm",
|
||||
"dyld-exp-hv_vmm",
|
||||
"system-watchdogd-exp-hv_vmm_cache",
|
||||
]
|
||||
|
||||
/// The preset a VM gets when nothing else is named.
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ extension FirmwarePipeline {
|
||||
// patcher built to write nothing is a patcher whose log lines lie.
|
||||
// `standard` blocks it: see FirmwareKernelHypervisorPatchSet.
|
||||
let includeHypervisor = includesSet(FirmwareKernelHypervisorPatchSet.identifier)
|
||||
&& isEnabled("kernelcache_exp.hv_vmm", fallback: false)
|
||||
&& isEnabled("kernel-exp-hv_vmm", fallback: false)
|
||||
|
||||
let baseIs18 = iOSBase?.major == 18
|
||||
let baseIs27 = iOSBase?.major == 27
|
||||
@@ -68,7 +68,7 @@ extension FirmwarePipeline {
|
||||
// SpringBoard trip GUARD_TYPE_MACH_PORT flavor 10 and crash-loop the UI —
|
||||
// the VM does not boot there without it. On 26.x and 27.x it only hides
|
||||
// violations, so it is off unless a VM checks it on.
|
||||
let applyExcGuard = isEnabled("kernel.thread_guard_violation", fallback: baseIs18)
|
||||
let applyExcGuard = isEnabled("kernel-boot-thread_guard_violation", fallback: baseIs18)
|
||||
|
||||
// Not a selection: `applyIOS27` changes which shapes the JB patch methods
|
||||
// look for, and which sandbox hook is left real for the fpfs trampoline.
|
||||
|
||||
@@ -297,7 +297,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
body,
|
||||
ARM64.movW0_0xA1,
|
||||
patchID: "txm_dev.selector24_bypass_mov",
|
||||
patchID: "txm-boot-selector24_bypass.mov",
|
||||
description: "selector24 bypass: mov w0, #0xa1 (PASS)",
|
||||
)
|
||||
|
||||
@@ -308,7 +308,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
body + 4,
|
||||
bInsn,
|
||||
patchID: "txm_dev.selector24_bypass_b",
|
||||
patchID: "txm-boot-selector24_bypass.b",
|
||||
description: "selector24 bypass: b epilogue",
|
||||
)
|
||||
return
|
||||
@@ -353,7 +353,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
cands[0],
|
||||
ARM64.movX0_1,
|
||||
patchID: "txm_dev.get_task_allow",
|
||||
patchID: "txm-cfw-get_task_allow",
|
||||
description: "get-task-allow: bl -> mov x0,#1",
|
||||
)
|
||||
}
|
||||
@@ -425,7 +425,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
stubOff,
|
||||
branchToShellcode,
|
||||
patchID: "txm_dev.sel42_29_branch",
|
||||
patchID: "txm-boot-sel42_29.branch",
|
||||
description: "selector42|29: branch to shellcode",
|
||||
)
|
||||
|
||||
@@ -433,25 +433,25 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
cave,
|
||||
ARM64.nop,
|
||||
patchID: "txm_dev.sel42_29_shell_nop",
|
||||
patchID: "txm-boot-sel42_29.shell_nop",
|
||||
description: "selector42|29 shellcode pad: udf -> nop",
|
||||
)
|
||||
emit(
|
||||
cave + 4,
|
||||
ARM64.movX0_1,
|
||||
patchID: "txm_dev.sel42_29_shell_mov1",
|
||||
patchID: "txm-boot-sel42_29.shell_mov1",
|
||||
description: "selector42|29 shellcode: mov x0,#1",
|
||||
)
|
||||
emit(
|
||||
cave + 8,
|
||||
ARM64.strbW0X20_30,
|
||||
patchID: "txm_dev.sel42_29_shell_strb",
|
||||
patchID: "txm-boot-sel42_29.shell_strb",
|
||||
description: "selector42|29 shellcode: strb w0,[x20,#0x30]",
|
||||
)
|
||||
emit(
|
||||
cave + 12,
|
||||
ARM64.movX0X20,
|
||||
patchID: "txm_dev.sel42_29_shell_mov20",
|
||||
patchID: "txm-boot-sel42_29.shell_mov20",
|
||||
description: "selector42|29 shellcode: mov x0,x20",
|
||||
)
|
||||
|
||||
@@ -463,7 +463,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
cave + 16,
|
||||
branchBack,
|
||||
patchID: "txm_dev.sel42_29_shell_ret",
|
||||
patchID: "txm-boot-sel42_29.shell_ret",
|
||||
description: "selector42|29 shellcode: branch back",
|
||||
)
|
||||
}
|
||||
@@ -515,7 +515,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
cands[0],
|
||||
ARM64.movW0_1,
|
||||
patchID: "txm_dev.debugger_entitlement",
|
||||
patchID: "txm-cfw-debugger_entitlement",
|
||||
description: "debugger entitlement: bl -> mov w0,#1",
|
||||
)
|
||||
}
|
||||
@@ -557,7 +557,7 @@ public final class TXMDevPatcher: TXMPatcher {
|
||||
emit(
|
||||
cands[0],
|
||||
ARM64.nop,
|
||||
patchID: "txm_dev.developer_mode_bypass",
|
||||
patchID: "txm-boot-developer_mode_bypass",
|
||||
description: "developer mode bypass",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ extension TXMPatcher {
|
||||
emit(
|
||||
legacyBL,
|
||||
ARM64.movX0_0,
|
||||
patchID: "txm.trustcache_bypass",
|
||||
patchID: "txm-boot-trustcache_bypass",
|
||||
description: "trustcache bypass: legacy binary-search call → mov x0, #0",
|
||||
)
|
||||
return
|
||||
@@ -124,7 +124,7 @@ extension TXMPatcher {
|
||||
emit(
|
||||
selector24BL,
|
||||
ARM64.movX0_0,
|
||||
patchID: "txm.trustcache_bypass",
|
||||
patchID: "txm-boot-trustcache_bypass",
|
||||
description: "trustcache bypass: selector24 hash-flags call → mov x0, #0",
|
||||
)
|
||||
return
|
||||
|
||||
+1
-1
@@ -409,7 +409,7 @@ struct CustomFirmwareCacheLoaderParityTests {
|
||||
let report = try CustomFirmwareCacheLoaderPatcher.patch(fileAt: clone, log: nil)
|
||||
let record = try #require(report.record)
|
||||
|
||||
#expect(record.patchID == "launchd_cache_loader.unsecure_cache_gate")
|
||||
#expect(record.patchID == "system-launchd_cache_loader-boot-unsecure_cache_gate")
|
||||
#expect(record.component == "launchd_cache_loader")
|
||||
#expect(record.fileOffset == report.gate.fileOffset)
|
||||
#expect(record.virtualAddress == report.gate.vma)
|
||||
|
||||
+1
-1
@@ -492,7 +492,7 @@ struct CustomFirmwareDiskImageParityTests {
|
||||
let report = try CustomFirmwareDiskImage.patch(fileAt: clone, log: nil)
|
||||
let record = try #require(report.record)
|
||||
|
||||
#expect(record.patchID == "diskimagesiod.is_mount_complete")
|
||||
#expect(record.patchID == "system-diskimagesiod-cfw-is_mount_complete")
|
||||
#expect(record.component == "diskimagesiod")
|
||||
#expect(record.fileOffset == report.site.fileOffset)
|
||||
#expect(record.virtualAddress == report.site.virtualAddress)
|
||||
|
||||
+1
-1
@@ -339,7 +339,7 @@ struct CustomFirmwareMobileActivationParityTests {
|
||||
#expect(!differing.isEmpty)
|
||||
#expect(differing.allSatisfy { record.fileOffset ..< record.fileOffset + 8 ~= $0 })
|
||||
#expect(record.fileOffset == MobileactivationdGolden.impFileOffset)
|
||||
#expect(record.patchID == "mobileactivationd.should_hactivate")
|
||||
#expect(record.patchID == "system-mobileactivationd-boot-should_hactivate")
|
||||
#expect(record.component == "mobileactivationd")
|
||||
#expect(record.patchedBytes == ARM64.movX0_1 + ARM64.ret)
|
||||
#expect(record.beforeDisasm.hasSuffix("ret"))
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ struct CustomFirmwareSeputilParityTests {
|
||||
|
||||
let outcome = try CustomFirmwareSeputil.patch(fileAt: file, dryRun: true, log: nil)
|
||||
let record = try #require(outcome.record)
|
||||
#expect(record.patchID == "seputil.gigalocker_uuid")
|
||||
#expect(record.patchID == "system-seputil-boot-gigalocker_uuid")
|
||||
#expect(record.component == "seputil")
|
||||
#expect(record.fileOffset == outcome.site.fieldOffset)
|
||||
#expect(record.virtualAddress == outcome.site.fieldVMA)
|
||||
|
||||
+1
-1
@@ -379,7 +379,7 @@ struct DyldSharedCacheCameraPatcherParityTests {
|
||||
+ [DyldSharedCacheCameraPatcher.authorizationStatusSymbol]
|
||||
let mine = symbols.map(DyldSharedCacheCameraPatcher.symbolSlug)
|
||||
#expect(mine == FrozenReference.symbolSlugs)
|
||||
print("[camera slugs] \(mine.count) ids agreed, e.g. camera_dsc.nu_styletransfer.\(mine[0])")
|
||||
print("[camera slugs] \(mine.count) ids agreed, e.g. dyld-cfw-camera.nu_styletransfer.\(mine[0])")
|
||||
}
|
||||
|
||||
/// Both replacements come out of the Keystone-checked encoders, and both
|
||||
|
||||
+32
-4
@@ -31,12 +31,40 @@ struct FirmwarePatchSetCatalogTests {
|
||||
// Two declarations where one is a site of the other would make record
|
||||
// attribution depend on the order they happen to be checked in. The
|
||||
// resolver picks the longest, but a catalogue that needs that rule to
|
||||
// disambiguate its own patches is a catalogue with a naming mistake.
|
||||
// disambiguate its own patches is a catalogue with a naming mistake. Only
|
||||
// a dot starts a site: an underscore continues a snake_case name.
|
||||
let identifiers = FirmwarePatchSetCatalog.allDeclarations.map(\.identifier)
|
||||
for outer in identifiers {
|
||||
for inner in identifiers where inner != outer {
|
||||
let isSite = inner.hasPrefix(outer + ".") || inner.hasPrefix(outer + "_")
|
||||
#expect(!isSite, "\(inner) reads as a site of \(outer)")
|
||||
#expect(!inner.hasPrefix(outer + "."), "\(inner) reads as a site of \(outer)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func `Every patch identifier names its component, effect and patch`() throws {
|
||||
// `{component}-{effect}-{name}`. The effect is derived, not chosen:
|
||||
// `boot` for a boot-essential patch, `exp` for one standard leaves off,
|
||||
// `cfw` for the rest. A patch that changes either property has to be
|
||||
// renamed with it, so the identifier never lies about what it is.
|
||||
let shape = try Regex("^[a-z0-9_]+(-[a-z0-9_]+)*-(boot|cfw|exp)-[a-z0-9_]+$")
|
||||
let standard = FirmwarePatchSetCatalog.standardPreset
|
||||
let standardSets = Set(standard.patchSets.map(\.identifier))
|
||||
var seen: Set<String> = []
|
||||
for set in FirmwarePatchSetCatalog.bundled {
|
||||
// The same rule `fw patches --json` reports as `inPreset`.
|
||||
let setInStandard = standardSets.contains(set.identifier)
|
||||
for patch in set.patches {
|
||||
let identifier = patch.identifier
|
||||
#expect(seen.insert(identifier).inserted, "\(identifier) is declared twice")
|
||||
#expect(identifier.wholeMatch(of: shape) != nil, "\(identifier) does not match the naming scheme")
|
||||
|
||||
let segments = identifier.split(separator: "-", omittingEmptySubsequences: false)
|
||||
guard segments.count >= 3 else { continue }
|
||||
let effect = segments[segments.count - 2]
|
||||
let inStandard = setInStandard && standard.selection.includes(identifier)
|
||||
let expected = patch.bootEssential ? "boot" : (inStandard ? "cfw" : "exp")
|
||||
#expect(effect == expected, "\(identifier) should use effect \(expected)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +156,7 @@ struct FirmwarePatchSetCatalogTests {
|
||||
// These two were flags once (`--force-exc-guard`, `--force-dsc-maxslide`).
|
||||
// They are now pinned to the release that needs them, so a base that does
|
||||
// not need them never gets them from a preset.
|
||||
let pinned = ["kernel.thread_guard_violation": 18, "dsc_maxslide.zero": 27]
|
||||
let pinned = ["kernel-boot-thread_guard_violation": 18, "dyld-boot-maxslide": 27]
|
||||
for (identifier, requiredMajor) in pinned {
|
||||
for base in [18, 26, 27] {
|
||||
let plan = try VPhonePatchPlan.resolve(
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import VPhonePatchKit
|
||||
/// Where the example set is, and how to get sealed and tampered copies of it.
|
||||
private enum ExamplePatchSet {
|
||||
static let identifier = "com.vphone.patchset.example"
|
||||
static let patchIdentifier = "example.string_rewrite"
|
||||
static let patchIdentifier = "ibec-exp-string_rewrite"
|
||||
|
||||
/// The built product, beside the running `.xctest`.
|
||||
static func url() throws -> URL {
|
||||
|
||||
+36
-24
@@ -159,22 +159,31 @@ struct VPhonePatchDeclarationTests {
|
||||
|
||||
@Test
|
||||
func `A declaration covers its own record and its per-site records`() {
|
||||
let kcall = declaration("jb.kcall10")
|
||||
#expect(kcall.covers(recordIdentifier: "jb.kcall10"))
|
||||
#expect(kcall.covers(recordIdentifier: "jb.kcall10.sy_call"))
|
||||
let kcall = declaration("kernel-boot-kcall10")
|
||||
#expect(kcall.covers(recordIdentifier: "kernel-boot-kcall10"))
|
||||
#expect(kcall.covers(recordIdentifier: "kernel-boot-kcall10.sy_call"))
|
||||
|
||||
// Record identifiers predate declarations and use both separators.
|
||||
let rootfs = declaration("llb.rootfs")
|
||||
#expect(rootfs.covers(recordIdentifier: "llb.rootfs_cbz_0x3b7"))
|
||||
let sandbox = declaration("sandbox_ext")
|
||||
#expect(sandbox.covers(recordIdentifier: "sandbox_ext_267"))
|
||||
let rootfs = declaration("llb-boot-rootfs")
|
||||
#expect(rootfs.covers(recordIdentifier: "llb-boot-rootfs.cbz_0x3b7"))
|
||||
let sandbox = declaration("kernel-boot-sandbox_ext")
|
||||
#expect(sandbox.covers(recordIdentifier: "kernel-boot-sandbox_ext.267"))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `Only a dot starts a site`() {
|
||||
// Names are snake_case, so an underscore continues the name: covering
|
||||
// `_` suffixes would let `sandbox_ext` claim a sibling `sandbox_ext_2`.
|
||||
let sandbox = declaration("kernel-boot-sandbox_ext")
|
||||
#expect(!sandbox.covers(recordIdentifier: "kernel-boot-sandbox_ext_267"))
|
||||
#expect(!sandbox.covers(recordIdentifier: "kernel-boot-sandbox_ext_2"))
|
||||
#expect(sandbox.covers(recordIdentifier: "kernel-boot-sandbox_ext.2"))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `A bare textual prefix is not a site`() {
|
||||
let debugger = declaration("kernel.debugger")
|
||||
#expect(!debugger.covers(recordIdentifier: "kernel.debuggerless"))
|
||||
#expect(!debugger.covers(recordIdentifier: "kernel.debug"))
|
||||
let debugger = declaration("kernel-cfw-debugger")
|
||||
#expect(!debugger.covers(recordIdentifier: "kernel-cfw-debuggerless"))
|
||||
#expect(!debugger.covers(recordIdentifier: "kernel-cfw-debug"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -322,9 +331,9 @@ struct VPhonePatchPlanTests {
|
||||
|
||||
@Test
|
||||
func `A record maps back to the declaration that owns it`() throws {
|
||||
let sets = [set("a", patches: [patch("kernel.sandbox"), patch("kernel.sandbox.mount_check_mount")])]
|
||||
let sets = [set("a", patches: [patch("kernel-cfw-sandbox"), patch("kernel-cfw-sandbox.mount_check_mount")])]
|
||||
let plan = try VPhonePatchPlan.resolve(
|
||||
preset: preset(["a"], selection: .allow(["kernel.sandbox"])),
|
||||
preset: preset(["a"], selection: .allow(["kernel-cfw-sandbox"])),
|
||||
patchSets: sets,
|
||||
iOSBase: nil,
|
||||
cloudOS: nil,
|
||||
@@ -332,11 +341,11 @@ struct VPhonePatchPlanTests {
|
||||
// The longest matching declaration wins, so a record is attributed to the
|
||||
// most specific patch that claims it.
|
||||
#expect(
|
||||
plan.declaration(coveringRecord: "kernel.sandbox.mount_check_mount")?.identifier
|
||||
== "kernel.sandbox.mount_check_mount",
|
||||
plan.declaration(coveringRecord: "kernel-cfw-sandbox.mount_check_mount")?.identifier
|
||||
== "kernel-cfw-sandbox.mount_check_mount",
|
||||
)
|
||||
#expect(plan.isRecordEnabled("kernel.sandbox.file_check_mmap"))
|
||||
#expect(!plan.isRecordEnabled("kernel.sandbox.mount_check_mount"))
|
||||
#expect(plan.isRecordEnabled("kernel-cfw-sandbox.file_check_mmap"))
|
||||
#expect(!plan.isRecordEnabled("kernel-cfw-sandbox.mount_check_mount"))
|
||||
// A record no declaration covers is not enabled by this plan; the gate,
|
||||
// not the plan, decides that it applies anyway.
|
||||
#expect(!plan.isRecordEnabled("something.else"))
|
||||
@@ -518,9 +527,12 @@ struct VPhonePatchGateTests {
|
||||
|
||||
@Test
|
||||
func `A gate answers about record identifiers, not just declarations`() {
|
||||
let gate = VPhonePatchGate(declared: ["jb.kcall10", "sandbox_ext"], enabled: ["jb.kcall10"])
|
||||
#expect(gate.allows(record: "jb.kcall10.sy_call"))
|
||||
#expect(!gate.allows(record: "sandbox_ext_267"))
|
||||
let gate = VPhonePatchGate(
|
||||
declared: ["kernel-boot-kcall10", "kernel-boot-sandbox_ext"],
|
||||
enabled: ["kernel-boot-kcall10"],
|
||||
)
|
||||
#expect(gate.allows(record: "kernel-boot-kcall10.sy_call"))
|
||||
#expect(!gate.allows(record: "kernel-boot-sandbox_ext.267"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -537,10 +549,10 @@ struct VPhonePatchGateTests {
|
||||
@Test
|
||||
func `The longest declaration owns a record`() {
|
||||
let gate = VPhonePatchGate(
|
||||
declared: ["kernel.sandbox", "kernel.sandbox.mount_check_mount"],
|
||||
enabled: ["kernel.sandbox"],
|
||||
declared: ["kernel-cfw-sandbox", "kernel-cfw-sandbox.mount_check_mount"],
|
||||
enabled: ["kernel-cfw-sandbox"],
|
||||
)
|
||||
#expect(!gate.allows(record: "kernel.sandbox.mount_check_mount"))
|
||||
#expect(gate.allows(record: "kernel.sandbox.file_check_mmap"))
|
||||
#expect(!gate.allows(record: "kernel-cfw-sandbox.mount_check_mount"))
|
||||
#expect(gate.allows(record: "kernel-cfw-sandbox.file_check_mmap"))
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -418,43 +418,43 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
// The version branches stay: they and the declarations' applicability say
|
||||
// the same thing, and this is what a VM with no plan still follows.
|
||||
if version.hasPrefix("27.") {
|
||||
if on("iomfb_force_kern") {
|
||||
if on("dyld-boot-iomfb_force_kern") {
|
||||
try patch("patch-iomfb-force-kern", [dsc])
|
||||
}
|
||||
if on("dsc_maxslide.zero") {
|
||||
if on("dyld-boot-maxslide") {
|
||||
try patch("patch-dsc-maxslide", [dsc])
|
||||
}
|
||||
if on("lsd_embedded_reg.entitlement_gate") {
|
||||
if on("dyld-boot-lsd_embedded_reg") {
|
||||
try patch("patch-lsd-embedded-reg", [dsc])
|
||||
}
|
||||
if on("xpc_lwcr") {
|
||||
if on("dyld-boot-xpc_lwcr") {
|
||||
try patch("patch-xpc-lwcr", [dsc])
|
||||
}
|
||||
if on("lockdown_mode.sysctl_error_gate") {
|
||||
if on("dyld-boot-lockdown_mode") {
|
||||
try patch("patch-lockdown-mode", [dsc])
|
||||
}
|
||||
} else if version.hasPrefix("26.0") || version.hasPrefix("18.") {
|
||||
if on("dsc.iomfb_swapend") {
|
||||
if on("dyld-boot-iomfb_swapend") {
|
||||
try patch("patch-iomfb-swapend", [dsc, "--target-size", "0x560"])
|
||||
}
|
||||
}
|
||||
// Version-agnostic: the guest is hacktivated on every base, so the
|
||||
// profile check this opens fails on every base too.
|
||||
if on("mis_trust_auth") {
|
||||
if on("dyld-cfw-mis_trust_auth") {
|
||||
try patch("patch-mis-trust-auth", [dsc])
|
||||
}
|
||||
// These former EXP patches pair with the kernel OID rename and the
|
||||
// camera DeviceTree additions in the public JB firmware pipeline.
|
||||
if on("hv_vmm_dsc") {
|
||||
if on("dyld-exp-hv_vmm") {
|
||||
try patch("patch-hv-vmm-dsc", [dsc])
|
||||
}
|
||||
if on("camera_dsc") {
|
||||
if on("dyld-cfw-camera") {
|
||||
try patch("patch-camera-dsc", [dsc, (dsc as NSString).appendingPathComponent("dyld_shared_cache_arm64e")])
|
||||
}
|
||||
// The preset's own parameter first; `SPOOF_BUILD` still works for a VM
|
||||
// whose preset does not set one.
|
||||
let buildVersion = plan?.parameters[FirmwareGuestSystemPatchSet.buildVersionParameter] ?? spoofBuild
|
||||
if let build = buildVersion, !build.isEmpty, on("guest.build_version") {
|
||||
if let build = buildVersion, !build.isEmpty, on("system-systemversion-cfw-build_version") {
|
||||
for path in [
|
||||
"System/Library/CoreServices/SystemVersion.plist",
|
||||
"System/Cryptexes/OS/System/Library/CoreServices/SystemVersion.plist",
|
||||
@@ -462,7 +462,7 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
try patchCopy(of: path, in: system, work: work, verb: "patch-build-version", arguments: [build])
|
||||
}
|
||||
}
|
||||
if on("seputil.gigalocker_uuid") {
|
||||
if on("system-seputil-boot-gigalocker_uuid") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -471,7 +471,7 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
identifier: "com.apple.seputil",
|
||||
)
|
||||
}
|
||||
if version.hasPrefix("27."), on("diskimagesiod.is_mount_complete") {
|
||||
if version.hasPrefix("27."), on("system-diskimagesiod-cfw-is_mount_complete") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -480,13 +480,13 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
preserveEntitlements: true,
|
||||
)
|
||||
}
|
||||
if on("guest.gigalocker_rename") {
|
||||
if on("system-gigalocker-boot-rename") {
|
||||
try renameGigalocker(data: data)
|
||||
}
|
||||
if on("guest.gpu_bundle") {
|
||||
if on("system-extensions-boot-gpu_bundle") {
|
||||
try installGPUBundle(restore: restore, system: system, owner: owner)
|
||||
}
|
||||
if on("launchd_cache_loader.unsecure_cache_gate") {
|
||||
if on("system-launchd_cache_loader-boot-unsecure_cache_gate") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -495,7 +495,7 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
identifier: "com.apple.launchd_cache_loader",
|
||||
)
|
||||
}
|
||||
if on("mobileactivationd.should_hactivate") {
|
||||
if on("system-mobileactivationd-boot-should_hactivate") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -503,16 +503,16 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
verb: "patch-mobileactivationd",
|
||||
)
|
||||
}
|
||||
if on("watchdogd.hv_vmm_cache") {
|
||||
if on("system-watchdogd-exp-hv_vmm_cache") {
|
||||
try patchWatchdog(system: system, work: work)
|
||||
}
|
||||
if on("guest.vphoned") {
|
||||
if on("system-vphoned-boot-install") {
|
||||
try installVphoned(system: system, work: work)
|
||||
}
|
||||
if on("guest.environment") {
|
||||
if on("system-launchdaemons-boot-environment") {
|
||||
try installEnvironment(system: system)
|
||||
}
|
||||
if on("launchd_jetsam.panic_guard_bypass") {
|
||||
if on("system-launchd-boot-jetsam_panic_guard_bypass") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -522,7 +522,7 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
injectedDylibPath: "/vh",
|
||||
)
|
||||
}
|
||||
if on("installd.adhoc_signature") {
|
||||
if on("system-installd-cfw-adhoc_signature") {
|
||||
// No bytes of installd's own change: the hook rides in on a weak
|
||||
// load command and does its work through dyld interposition.
|
||||
try patchMachO(
|
||||
@@ -534,7 +534,7 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
injectedDylibPath: "/usr/lib/libmisfix.dylib",
|
||||
)
|
||||
}
|
||||
if on("misagent.device_identity") {
|
||||
if on("system-misagent-cfw-device_identity") {
|
||||
try patchMachO(
|
||||
system: system,
|
||||
work: work,
|
||||
@@ -544,10 +544,10 @@ struct VPhoneCustomFirmwareInstaller {
|
||||
injectedDylibPath: "/usr/lib/libmisfix.dylib",
|
||||
)
|
||||
}
|
||||
if on("guest.debugserver") {
|
||||
if on("system-debugserver-cfw-install") {
|
||||
try patchDebugserver(system: system, work: work)
|
||||
}
|
||||
if version.hasPrefix("27."), on("campo.entitlements") {
|
||||
if version.hasPrefix("27."), on("system-campo-cfw-entitlements") {
|
||||
try patchCampo(system: system, work: work)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import Foundation
|
||||
|
||||
/// A single patch application record, used to compare Python vs Swift output.
|
||||
public struct PatchRecord: Codable, Equatable, Sendable {
|
||||
/// Unique patch identifier (e.g., "kernel.bsd_init_rootvp").
|
||||
/// Unique patch identifier (e.g., "kernel-boot-bsd_init_rootvp").
|
||||
public let patchID: String
|
||||
|
||||
/// Component being patched (e.g., "kernelcache", "ibss", "txm").
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// The identifier is the contract. It is the prefix of the ``PatchRecord``
|
||||
// identifiers the patch emits, so a patch writing four records under
|
||||
// `jb.cred_label_update_execve.*` declares one identifier and is selected or
|
||||
// `kernel-boot-cred_label_update_execve.*` declares one identifier and is selected or
|
||||
// blocked as a unit — a half-applied patch of that shape would not boot.
|
||||
|
||||
import Foundation
|
||||
@@ -95,14 +95,14 @@ public extension VPhonePatchDeclaration {
|
||||
/// Whether `recordIdentifier` came from this patch.
|
||||
///
|
||||
/// A record either is the declaration itself or sits under it as
|
||||
/// `<identifier><separator><site>`. Both separators count: record
|
||||
/// identifiers predate declarations and spell their per-site suffix either
|
||||
/// way — `jb.kcall10.sy_call` with a dot, `llb.rootfs_cbz_0x3b7` and
|
||||
/// `sandbox_ext_267` with an underscore. A bare textual prefix does not
|
||||
/// match, so `kernel.debuggerless` is not a site of `kernel.debugger`.
|
||||
/// `<identifier>.<site>` — `kernel-boot-kcall10.sy_call`,
|
||||
/// `llb-boot-rootfs.cbz_0x3b7`. Only a dot separates a site: identifiers
|
||||
/// are snake_case and contain underscores, so an underscore suffix would
|
||||
/// let `kernel-boot-sandbox_mount_check_mount` cover a different patch
|
||||
/// that happens to extend its name. A bare textual prefix does not match
|
||||
/// either, so `kernel-cfw-debuggerless` is not a site of `kernel-cfw-debugger`.
|
||||
func covers(recordIdentifier record: String) -> Bool {
|
||||
record == identifier
|
||||
|| record.hasPrefix(identifier + ".")
|
||||
|| record.hasPrefix(identifier + "_")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
// Gates answer about *record* identifiers, because that is what a patch site has
|
||||
// in hand, and record identifiers are finer than declarations: one declaration
|
||||
// covers `jb.kcall10.sy_call` and its three siblings. A record no declaration
|
||||
// covers `kernel-boot-kcall10.sy_call` and its three siblings. A record no declaration
|
||||
// covers is a gap in a manifest, not a patch the user turned off, so the gate
|
||||
// applies it and says so. Failing open keeps a missed declaration from silently
|
||||
// changing the firmware; the warning is what makes the gap findable.
|
||||
@@ -33,7 +33,7 @@ public struct VPhonePatchGate: Sendable, Hashable {
|
||||
/// Only the plan's enabled patches apply.
|
||||
public init(plan: VPhonePatchPlan) {
|
||||
policy = .plan(
|
||||
// Longest first, so `kernel.sandbox.mount_check_mount` is consulted
|
||||
// Longest first, so `kernel-boot-sandbox_mount_check_mount` is consulted
|
||||
// before a shorter declaration that also happens to cover the record.
|
||||
declared: plan.declarations.map(\.identifier).sorted { $0.count > $1.count },
|
||||
enabled: plan.enabled,
|
||||
@@ -97,7 +97,7 @@ public struct VPhonePatchGate: Sendable, Hashable {
|
||||
/// over a list already ordered longest first.
|
||||
private static func declaration(covering record: String, in declared: [String]) -> String? {
|
||||
declared.first {
|
||||
record == $0 || record.hasPrefix($0 + ".") || record.hasPrefix($0 + "_")
|
||||
record == $0 || record.hasPrefix($0 + ".")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ public struct VPhonePatchPlan: Sendable, Hashable {
|
||||
|
||||
/// Whether the patch that emits `recordIdentifier` runs.
|
||||
///
|
||||
/// Record identifiers are sometimes built at runtime (`sandbox_ext_3`,
|
||||
/// `camera_dsc.<family>.<symbol>`), so this maps a record back to the
|
||||
/// Record identifiers are sometimes built at runtime (`kernel-boot-sandbox_ext.3`,
|
||||
/// `dyld-cfw-camera.<family>.<symbol>`), so this maps a record back to the
|
||||
/// declaration that owns it instead of matching the full string.
|
||||
public func isRecordEnabled(_ recordIdentifier: String) -> Bool {
|
||||
guard let declaration = declaration(coveringRecord: recordIdentifier) else { return false }
|
||||
|
||||
@@ -66,8 +66,8 @@ public struct VPhonePatchSetManifest: Sendable, Hashable, Codable, Identifiable
|
||||
|
||||
/// The declaration owning `recordIdentifier`, if this set emits it.
|
||||
public func declaration(coveringRecord recordIdentifier: String) -> VPhonePatchDeclaration? {
|
||||
// Longest identifier first, so `kernel.debugger.ret` is attributed to
|
||||
// `kernel.debugger` rather than to a shorter `kernel` umbrella.
|
||||
// Longest identifier first, so `kernel-cfw-debugger.ret` is attributed to
|
||||
// `kernel-cfw-debugger` rather than to a shorter umbrella.
|
||||
patches
|
||||
.filter { $0.covers(recordIdentifier: recordIdentifier) }
|
||||
.max { $0.identifier.count < $1.identifier.count }
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<array>
|
||||
<dict>
|
||||
<key>Identifier</key>
|
||||
<string>example.string_rewrite</string>
|
||||
<string>ibec-exp-string_rewrite</string>
|
||||
<key>Title</key>
|
||||
<string>Example string rewrite</string>
|
||||
<key>Summary</key>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user