mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-02 02:34:29 +00:00
KernelPatchApfsMount: Re-anchor handle_get_dev_by_role deny gates on stable strings
The patch-16 entitlement-gate matcher keyed on source line IDs
(`mov w8, #0x332D / #0x333B`); on 26.4 both the value and the register drifted,
so it found nothing and silently skipped (worked on 26.1/26.3).
Re-anchor the deny blocks on their stable panic strings ("This operation needs
entitlement" and "lookup takes place out of a volume group, but the source
volume is in one"), scoped to the routine by also requiring the
`handle_get_dev_by_role` function-name string — this excludes the adjacent
`handle_volume_class_keybag_op`, which shares the entitlement message. Yields the
same 3 gates on 26.1/26.3 (parity) and now 3 on 26.4.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
committed by
zqxwce
co-authored by
Claude Opus 4.8
parent
9808bd24b9
commit
aa0000a65b
@@ -306,6 +306,14 @@ extension KernelPatcher {
|
||||
return false
|
||||
}
|
||||
|
||||
// Scope to this routine: its deny blocks load both the message and the
|
||||
// `handle_get_dev_by_role` name; the name excludes the adjacent keybag handler.
|
||||
let msgRefs = stringRefSet(in: apfsRange, needles: [
|
||||
"%s:%d: %s This operation needs entitlement",
|
||||
"%s:%d: %s lookup takes place out of a volume group, but the source volume is in one",
|
||||
])
|
||||
let nameRefs = stringRefSet(in: apfsRange, needles: ["handle_get_dev_by_role"])
|
||||
|
||||
for ref in refs {
|
||||
guard let funcStart = findFunctionStart(ref.adrpOff) else { continue }
|
||||
let funcEnd = min(funcStart + 0x1200, buffer.count)
|
||||
@@ -339,7 +347,9 @@ extension KernelPatcher {
|
||||
scan += 4; continue
|
||||
}
|
||||
|
||||
if isEntitlementErrorBlock(at: target, funcEnd: funcEnd) {
|
||||
let span = target ..< min(target + 0x40, funcEnd)
|
||||
let inSpan = { (s: Set<Int>) in s.contains { span.contains($0) } }
|
||||
if inSpan(msgRefs), inSpan(nameRefs) {
|
||||
if !candidates.contains(where: { $0.off == scan }) {
|
||||
candidates.append((off: scan, target: target))
|
||||
}
|
||||
@@ -367,38 +377,15 @@ extension KernelPatcher {
|
||||
return false
|
||||
}
|
||||
|
||||
/// Return true if the block at `targetOff` contains `mov w8, #0x332D` or
|
||||
/// `mov w8, #0x333B` within the first 0x30 bytes (entitlement-gate line IDs).
|
||||
private func isEntitlementErrorBlock(at targetOff: Int, funcEnd: Int) -> Bool {
|
||||
let scanEnd = min(targetOff + 0x30, funcEnd)
|
||||
var off = targetOff
|
||||
while off + 4 <= scanEnd {
|
||||
guard let insn = disasm.disassembleOne(in: buffer.data, at: off),
|
||||
let detail = insn.aarch64
|
||||
else {
|
||||
off += 4; continue
|
||||
}
|
||||
|
||||
// Stop on call, unconditional branch, or return — different path.
|
||||
if insn.mnemonic == "bl" || insn.mnemonic == "b"
|
||||
|| insn.mnemonic == "ret" || insn.mnemonic == "retab"
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if insn.mnemonic == "mov", detail.operands.count >= 2 {
|
||||
let ops = detail.operands
|
||||
if ops[0].type == AARCH64_OP_REG,
|
||||
ops[0].reg == AARCH64_REG_W8,
|
||||
ops[1].type == AARCH64_OP_IMM,
|
||||
ops[1].imm == 0x332D || ops[1].imm == 0x333B
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
off += 4
|
||||
/// ADRP+ADD reference offsets to `needles`. Anchors deny-block detection on stable
|
||||
/// panic strings instead of the per-version line IDs the old matcher pinned.
|
||||
private func stringRefSet(in range: (start: Int, end: Int), needles: [String]) -> Set<Int> {
|
||||
var refs = Set<Int>()
|
||||
for needle in needles {
|
||||
guard let strOff = buffer.findString(needle) else { continue }
|
||||
for ref in findStringRefs(strOff, in: range) { refs.insert(ref.adrpOff) }
|
||||
}
|
||||
return false
|
||||
return refs
|
||||
}
|
||||
|
||||
// MARK: - Aggregate entry point
|
||||
|
||||
Reference in New Issue
Block a user