mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-05 17:14:28 +00:00
Add kernel patch testing scripts and targets
Introduce a set of tools for fast and batch testing of kernel JB patches: add testing_batch.sh, testing_do_patch.sh, testing_do_save.sh and testing_kernel_patch.py (plus a results _summary). Update the Makefile with new targets (testing_do_save, testing_kernel_patch, testing_do_patch, testing_batch) and PHONY entries to wire them into the build/test workflow. Modify kernel_jb.py to enable the amfi cdhash-in-trustcache patch (A1) and mark the amfi execve kill-path patch as causing PANIC (A2). These changes allow restoring a base kernel backup, applying single patches quickly, running per-patch DFU boots (with timeout/panic detection), and collecting logs for batch runs.
This commit is contained in:
@@ -321,3 +321,4 @@ TODO.md
|
||||
scripts/vphoned/vphoned
|
||||
sources/vphone-cli/VPhoneBuildInfo.swift
|
||||
setup_logs/
|
||||
/testing_results
|
||||
|
||||
@@ -73,6 +73,9 @@ help:
|
||||
@echo " make ramdisk_send Send ramdisk to device"
|
||||
@echo " make testing_ramdisk_build Build boot chain only (no SSH, no CFW)"
|
||||
@echo " make testing_ramdisk_send Send testing boot chain to device"
|
||||
@echo " make testing_do_save Full pipeline + save base kernel backup"
|
||||
@echo " make testing_do_patch PATCH=name Test single JB kernel patch (fast)"
|
||||
@echo " make testing_kernel_patch PATCH=name Restore+patch kernel only (no boot)"
|
||||
@echo ""
|
||||
@echo "CFW:"
|
||||
@echo " make cfw_install Install CFW mods via SSH"
|
||||
@@ -219,7 +222,7 @@ restore:
|
||||
# Ramdisk
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
.PHONY: ramdisk_build ramdisk_send testing_ramdisk_build testing_ramdisk_send
|
||||
.PHONY: ramdisk_build ramdisk_send testing_ramdisk_build testing_ramdisk_send testing_do testing_do_save testing_kernel_patch testing_do_patch
|
||||
|
||||
ramdisk_build:
|
||||
cd $(VM_DIR) && $(PYTHON) "$(CURDIR)/$(SCRIPTS)/ramdisk_build.py" .
|
||||
@@ -236,6 +239,18 @@ testing_ramdisk_send:
|
||||
testing_do:
|
||||
zsh "$(CURDIR)/$(SCRIPTS)/testing_do.sh"
|
||||
|
||||
testing_do_save:
|
||||
zsh "$(CURDIR)/$(SCRIPTS)/testing_do_save.sh"
|
||||
|
||||
testing_kernel_patch:
|
||||
cd $(VM_DIR) && $(PYTHON) "$(CURDIR)/$(SCRIPTS)/testing_kernel_patch.py" . $(PATCH)
|
||||
|
||||
testing_do_patch:
|
||||
zsh "$(CURDIR)/$(SCRIPTS)/testing_do_patch.sh" $(PATCH)
|
||||
|
||||
testing_batch:
|
||||
zsh "$(CURDIR)/$(SCRIPTS)/testing_batch.sh" $(PATCHES)
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
# CFW
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -57,11 +57,13 @@ class KernelJBPatcher(
|
||||
def find_all(self):
|
||||
self.patches = []
|
||||
|
||||
# Commented patches are broken to boot into panic.
|
||||
|
||||
# Group A: Existing patches
|
||||
# self.patch_amfi_cdhash_in_trustcache() # A1
|
||||
# self.patch_amfi_execve_kill_path() # A2
|
||||
# self.patch_task_conversion_eval_internal() # A3
|
||||
# self.patch_sandbox_hooks_extended() # A4
|
||||
self.patch_amfi_cdhash_in_trustcache() # A1
|
||||
# self.patch_amfi_execve_kill_path() # A2 (PANIC)
|
||||
self.patch_task_conversion_eval_internal() # A3
|
||||
self.patch_sandbox_hooks_extended() # A4
|
||||
|
||||
# Group B: Simple patches (string-anchored / pattern-matched)
|
||||
# self.patch_post_validation_additional() # B5
|
||||
|
||||
Executable
+244
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/env zsh
|
||||
set -euo pipefail
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
# testing_batch.sh — Batch-test kernel JB patches one at a time.
|
||||
#
|
||||
# Prerequisite: run `make testing_do_save` first to create base backup.
|
||||
#
|
||||
# For each patch:
|
||||
# 1. Restore base kernel + apply single patch
|
||||
# 2. Build ramdisk
|
||||
# 3. Boot DFU (vphone-cli --no-graphics --dfu)
|
||||
# 4. Send boot chain via irecovery
|
||||
# 5. Wait up to 2 minutes, watching for panic
|
||||
# 6. Save output → testing_results/<patch_name>.log
|
||||
# 7. Kill everything, move to next patch
|
||||
#
|
||||
# Usage:
|
||||
# ./testing_batch.sh # test all uncommented B/C patches
|
||||
# ./testing_batch.sh patch_mac_mount patch_dounmount # test specific patches
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${0:a:h}")" && pwd)"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
VM_DIR="$PROJECT_DIR/${VM_DIR:-vm}"
|
||||
RESULTS_DIR="$PROJECT_DIR/testing_results"
|
||||
TIMEOUT_SECS=120 # 2 minutes
|
||||
|
||||
BINARY="$PROJECT_DIR/.build/release/vphone-cli"
|
||||
IRECOVERY="$PROJECT_DIR/.limd/bin/irecovery"
|
||||
PYTHON="$PROJECT_DIR/.venv/bin/python3"
|
||||
|
||||
mkdir -p "$RESULTS_DIR"
|
||||
|
||||
# ─── Default patch list (all B + C patches) ────────────────────────
|
||||
ALL_PATCHES=(
|
||||
patch_post_validation_additional # B5
|
||||
patch_proc_security_policy # B6
|
||||
patch_proc_pidinfo # B7
|
||||
patch_convert_port_to_map # B8
|
||||
patch_vm_fault_enter_prepare # B9
|
||||
patch_vm_map_protect # B10
|
||||
patch_mac_mount # B11
|
||||
patch_dounmount # B12
|
||||
patch_bsd_init_auth # B13
|
||||
patch_spawn_validate_persona # B14
|
||||
patch_task_for_pid # B15
|
||||
patch_load_dylinker # B16
|
||||
patch_shared_region_map # B17
|
||||
patch_nvram_verify_permission # B18
|
||||
patch_io_secure_bsd_root # B19
|
||||
patch_thid_should_crash # B20
|
||||
patch_cred_label_update_execve # C21
|
||||
patch_syscallmask_apply_to_proc # C22
|
||||
patch_hook_cred_label_update_execve # C23
|
||||
patch_kcall10 # C24
|
||||
)
|
||||
|
||||
# Use args if provided, otherwise test all
|
||||
if (( $# > 0 )); then
|
||||
PATCHES=("$@")
|
||||
else
|
||||
PATCHES=("${ALL_PATCHES[@]}")
|
||||
fi
|
||||
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " Batch kernel JB patch tester"
|
||||
echo " Testing ${#PATCHES[@]} patch(es), ${TIMEOUT_SECS}s timeout each"
|
||||
echo " Results → $RESULTS_DIR/"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# ─── Verify backup exists ──────────────────────────────────────────
|
||||
RESTORE_DIR=$(find "$VM_DIR" -maxdepth 1 -type d -name '*Restore*' | head -1)
|
||||
KERNEL_BACKUP=$(find "$RESTORE_DIR" -name 'kernelcache.research.vphone600.base_backup' 2>/dev/null | head -1)
|
||||
if [[ -z "$KERNEL_BACKUP" ]]; then
|
||||
echo "[-] No kernel backup found. Run 'make testing_do_save' first."
|
||||
exit 1
|
||||
fi
|
||||
echo "[*] Kernel backup: $KERNEL_BACKUP"
|
||||
echo ""
|
||||
|
||||
# ─── Summary file ──────────────────────────────────────────────────
|
||||
SUMMARY="$RESULTS_DIR/_summary.txt"
|
||||
echo "Batch test run: $(date)" > "$SUMMARY"
|
||||
echo "Timeout: ${TIMEOUT_SECS}s" >> "$SUMMARY"
|
||||
echo "─────────────────────────────────────────" >> "$SUMMARY"
|
||||
|
||||
# ─── Test each patch ───────────────────────────────────────────────
|
||||
PASS_COUNT=0
|
||||
FAIL_COUNT=0
|
||||
ERROR_COUNT=0
|
||||
TOTAL=${#PATCHES[@]}
|
||||
|
||||
for i in {1..$TOTAL}; do
|
||||
PATCH="${PATCHES[$i]}"
|
||||
LOG="$RESULTS_DIR/${PATCH}.log"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " [$i/$TOTAL] Testing: $PATCH"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# Clean up any prior vphone-cli
|
||||
pkill -9 vphone-cli 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# Header in log
|
||||
{
|
||||
echo "Patch: $PATCH"
|
||||
echo "Date: $(date)"
|
||||
echo "Timeout: ${TIMEOUT_SECS}s"
|
||||
echo "══════════════════════════════════════════"
|
||||
} > "$LOG"
|
||||
|
||||
# Step 1: Restore kernel + apply patch
|
||||
echo " [1/4] Patching kernel..."
|
||||
{
|
||||
echo ""
|
||||
echo "── kernel patch ──"
|
||||
"$PYTHON" "$PROJECT_DIR/scripts/testing_kernel_patch.py" "$VM_DIR" "$PATCH" 2>&1
|
||||
} >> "$LOG" 2>&1
|
||||
|
||||
PATCH_EXIT=$?
|
||||
if (( PATCH_EXIT != 0 )); then
|
||||
echo " [-] Patch failed (exit $PATCH_EXIT) — skipping"
|
||||
echo "$PATCH ERROR patch_failed" >> "$SUMMARY"
|
||||
ERROR_COUNT=$(( ERROR_COUNT + 1 ))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Step 2: Build ramdisk
|
||||
echo " [2/4] Building ramdisk..."
|
||||
{
|
||||
echo ""
|
||||
echo "── ramdisk build ──"
|
||||
make -C "$PROJECT_DIR" testing_ramdisk_build VM_DIR="$VM_DIR" 2>&1
|
||||
} >> "$LOG" 2>&1
|
||||
|
||||
# Step 3: Boot DFU (capture output)
|
||||
echo " [3/4] Booting DFU..."
|
||||
{
|
||||
echo ""
|
||||
echo "── boot output ──"
|
||||
} >> "$LOG"
|
||||
|
||||
# Start vphone-cli in background, capturing output
|
||||
"$BINARY" \
|
||||
--rom "$VM_DIR/AVPBooter.vresearch1.bin" \
|
||||
--disk "$VM_DIR/Disk.img" \
|
||||
--nvram "$VM_DIR/nvram.bin" \
|
||||
--machine-id "$VM_DIR/machineIdentifier.bin" \
|
||||
--cpu 8 --memory 8192 \
|
||||
--sep-rom "$VM_DIR/AVPSEPBooter.vresearch1.bin" \
|
||||
--sep-storage "$VM_DIR/SEPStorage" \
|
||||
--no-graphics --dfu \
|
||||
>> "$LOG" 2>&1 &
|
||||
VM_PID=$!
|
||||
|
||||
# Step 4: Send boot chain
|
||||
echo " [4/4] Sending boot chain..."
|
||||
{
|
||||
echo ""
|
||||
echo "── ramdisk send ──"
|
||||
make -C "$PROJECT_DIR" testing_ramdisk_send VM_DIR="$VM_DIR" 2>&1
|
||||
} >> "$LOG" 2>&1 || true
|
||||
|
||||
# ─── Monitor for panic or timeout ──────────────────────────────
|
||||
echo " [*] Monitoring for ${TIMEOUT_SECS}s (panic or timeout)..."
|
||||
|
||||
RESULT="TIMEOUT"
|
||||
START_TIME=$SECONDS
|
||||
|
||||
while (( SECONDS - START_TIME < TIMEOUT_SECS )); do
|
||||
# Check if VM died
|
||||
if ! kill -0 "$VM_PID" 2>/dev/null; then
|
||||
RESULT="VM_DIED"
|
||||
break
|
||||
fi
|
||||
|
||||
# Check log for panic
|
||||
if grep -qi 'panic' "$LOG" 2>/dev/null; then
|
||||
# Give a few more seconds for full panic log to flush
|
||||
sleep 5
|
||||
RESULT="PANIC"
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ELAPSED=$(( SECONDS - START_TIME ))
|
||||
|
||||
# Kill VM
|
||||
kill -9 "$VM_PID" 2>/dev/null || true
|
||||
wait "$VM_PID" 2>/dev/null || true
|
||||
# Also kill any orphaned vphone-cli
|
||||
pkill -9 vphone-cli 2>/dev/null || true
|
||||
|
||||
# Append result to log
|
||||
{
|
||||
echo ""
|
||||
echo "══════════════════════════════════════════"
|
||||
echo "RESULT: $RESULT"
|
||||
echo "ELAPSED: ${ELAPSED}s"
|
||||
} >> "$LOG"
|
||||
|
||||
# Record
|
||||
case "$RESULT" in
|
||||
PANIC)
|
||||
echo " [X] PANIC after ${ELAPSED}s → $LOG"
|
||||
echo "$PATCH PANIC ${ELAPSED}s" >> "$SUMMARY"
|
||||
FAIL_COUNT=$(( FAIL_COUNT + 1 ))
|
||||
;;
|
||||
VM_DIED)
|
||||
echo " [X] VM died after ${ELAPSED}s → $LOG"
|
||||
echo "$PATCH VM_DIED ${ELAPSED}s" >> "$SUMMARY"
|
||||
FAIL_COUNT=$(( FAIL_COUNT + 1 ))
|
||||
;;
|
||||
TIMEOUT)
|
||||
echo " [+] No panic in ${TIMEOUT_SECS}s (likely OK) → $LOG"
|
||||
echo "$PATCH OK ${TIMEOUT_SECS}s" >> "$SUMMARY"
|
||||
PASS_COUNT=$(( PASS_COUNT + 1 ))
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# ─── Final summary ─────────────────────────────────────────────────
|
||||
{
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo "TOTAL: $TOTAL PASS: $PASS_COUNT FAIL: $FAIL_COUNT ERROR: $ERROR_COUNT"
|
||||
} >> "$SUMMARY"
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
echo " DONE — $TOTAL tested: $PASS_COUNT pass, $FAIL_COUNT fail, $ERROR_COUNT error"
|
||||
echo " Summary: $SUMMARY"
|
||||
echo " Logs: $RESULTS_DIR/<patch_name>.log"
|
||||
echo "═══════════════════════════════════════════════════════════════"
|
||||
cat "$SUMMARY"
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env zsh
|
||||
set -euo pipefail
|
||||
|
||||
# Fast test a single kernel JB patch.
|
||||
# Restores base kernel backup, applies one patch, rebuilds ramdisk, boots.
|
||||
#
|
||||
# Usage: ./testing_do_patch.sh <patch_name>
|
||||
# or: make testing_do_patch PATCH=patch_vm_fault_enter_prepare
|
||||
|
||||
# ─── Track child PIDs for cleanup ───────────────────────────────────
|
||||
typeset -a CHILD_PIDS=()
|
||||
|
||||
cleanup() {
|
||||
echo "\n[patch] cleaning up..."
|
||||
for pid in "${CHILD_PIDS[@]}"; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo "[patch] killing PID $pid"
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${0:a:h}")" && pwd)"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
PATCH_NAME="${1:-}"
|
||||
if [[ -z "$PATCH_NAME" ]]; then
|
||||
echo "Usage: $0 <patch_name>"
|
||||
echo " e.g. $0 patch_vm_fault_enter_prepare"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VM_DIR="${VM_DIR:-vm}"
|
||||
|
||||
# ─── Kill existing vphone-cli ──────────────────────────────────────
|
||||
echo "[patch] killing existing vphone-cli..."
|
||||
pkill -9 vphone-cli 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# ─── Restore kernel + apply single patch ───────────────────────────
|
||||
echo "[patch] restoring base kernel + applying: $PATCH_NAME"
|
||||
make testing_kernel_patch PATCH="$PATCH_NAME"
|
||||
|
||||
# ─── Rebuild ramdisk ────────────────────────────────────────────────
|
||||
echo "[patch] testing_ramdisk_build..."
|
||||
make testing_ramdisk_build
|
||||
|
||||
# ─── Send ramdisk in background ────────────────────────────────────
|
||||
echo "[patch] testing_ramdisk_send (background)..."
|
||||
make testing_ramdisk_send &
|
||||
CHILD_PIDS+=($!)
|
||||
|
||||
# ─── Boot DFU ──────────────────────────────────────────────────────
|
||||
echo "[patch] boot_dfu..."
|
||||
make boot_dfu &
|
||||
CHILD_PIDS+=($!)
|
||||
|
||||
echo "[patch] waiting for boot_dfu (PID ${CHILD_PIDS[-1]})..."
|
||||
wait "${CHILD_PIDS[-1]}" 2>/dev/null || true
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env zsh
|
||||
set -euo pipefail
|
||||
|
||||
# Save a base-patched kernel for fast per-patch testing.
|
||||
# Run once, then use testing_do_patch.sh <patch_name> to test individual patches.
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${0:a:h}")" && pwd)"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
VM_DIR="${VM_DIR:-vm}"
|
||||
|
||||
# ─── Kill existing vphone-cli ──────────────────────────────────────
|
||||
echo "[save] killing existing vphone-cli..."
|
||||
pkill -9 vphone-cli 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# ─── Full pipeline with base patches only ──────────────────────────
|
||||
echo "[save] fw_prepare..."
|
||||
make fw_prepare
|
||||
|
||||
echo "[save] fw_patch_jb..."
|
||||
make fw_patch_jb
|
||||
|
||||
# ─── Find and save kernelcache backup ──────────────────────────────
|
||||
RESTORE_DIR=$(find "$VM_DIR" -maxdepth 1 -type d -name '*Restore*' | head -1)
|
||||
KERNEL_PATH=$(find "$RESTORE_DIR" -name 'kernelcache.research.vphone600' | head -1)
|
||||
|
||||
if [[ -z "$KERNEL_PATH" ]]; then
|
||||
echo "[-] kernelcache not found in $RESTORE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_PATH="${KERNEL_PATH}.base_backup"
|
||||
cp "$KERNEL_PATH" "$BACKUP_PATH"
|
||||
echo "[save] kernel backup saved: $BACKUP_PATH ($(wc -c < "$BACKUP_PATH") bytes)"
|
||||
echo "[save] done. Now use: make testing_do_patch PATCH=<name>"
|
||||
echo ""
|
||||
echo "Available patch names:"
|
||||
echo " patch_post_validation_additional (B5)"
|
||||
echo " patch_proc_security_policy (B6)"
|
||||
echo " patch_proc_pidinfo (B7)"
|
||||
echo " patch_convert_port_to_map (B8)"
|
||||
echo " patch_vm_fault_enter_prepare (B9)"
|
||||
echo " patch_vm_map_protect (B10)"
|
||||
echo " patch_mac_mount (B11)"
|
||||
echo " patch_dounmount (B12)"
|
||||
echo " patch_bsd_init_auth (B13)"
|
||||
echo " patch_spawn_validate_persona (B14)"
|
||||
echo " patch_task_for_pid (B15)"
|
||||
echo " patch_load_dylinker (B16)"
|
||||
echo " patch_shared_region_map (B17)"
|
||||
echo " patch_nvram_verify_permission (B18)"
|
||||
echo " patch_io_secure_bsd_root (B19)"
|
||||
echo " patch_thid_should_crash (B20)"
|
||||
echo " patch_cred_label_update_execve (C21)"
|
||||
echo " patch_syscallmask_apply_to_proc (C22)"
|
||||
echo " patch_hook_cred_label_update_execve (C23)"
|
||||
echo " patch_kcall10 (C24)"
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
testing_kernel_patch.py — Restore base kernel backup and apply a single JB patch.
|
||||
|
||||
Usage:
|
||||
python3 testing_kernel_patch.py <vm_directory> <patch_name> [patch_name2 ...]
|
||||
|
||||
Example:
|
||||
python3 testing_kernel_patch.py vm patch_vm_fault_enter_prepare
|
||||
python3 testing_kernel_patch.py vm patch_mac_mount patch_dounmount
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from fw_patch import find_file, find_restore_dir, load_firmware, save_firmware
|
||||
from patchers.kernel_jb import KernelJBPatcher
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print(f"Usage: {sys.argv[0]} <vm_dir> <patch_name> [patch_name2 ...]")
|
||||
sys.exit(1)
|
||||
|
||||
vm_dir = os.path.abspath(sys.argv[1])
|
||||
patch_names = sys.argv[2:]
|
||||
|
||||
restore_dir = find_restore_dir(vm_dir)
|
||||
if not restore_dir:
|
||||
print(f"[-] No *Restore* directory found in {vm_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
kernel_path = find_file(restore_dir, ["kernelcache.research.vphone600"], "kernelcache")
|
||||
backup_path = kernel_path + ".base_backup"
|
||||
|
||||
if not os.path.exists(backup_path):
|
||||
print(f"[-] No backup found: {backup_path}")
|
||||
print(f" Run 'make testing_do_save' first.")
|
||||
sys.exit(1)
|
||||
|
||||
# Restore from backup
|
||||
shutil.copy2(backup_path, kernel_path)
|
||||
print(f"[*] Restored kernel from backup ({os.path.getsize(backup_path)} bytes)")
|
||||
|
||||
# Load the kernel
|
||||
im4p, data, was_im4p, original_raw = load_firmware(kernel_path)
|
||||
fmt = "IM4P" if was_im4p else "raw"
|
||||
print(f"[*] Loaded: {fmt}, {len(data)} bytes")
|
||||
|
||||
# Create patcher (inherits from KernelJBPatcherBase which inherits from KernelPatcher)
|
||||
kp = KernelJBPatcher(data)
|
||||
|
||||
# Apply each requested patch
|
||||
applied = 0
|
||||
for patch_name in patch_names:
|
||||
method = getattr(kp, patch_name, None)
|
||||
if method is None:
|
||||
print(f"[-] Unknown patch: {patch_name}")
|
||||
print(f" Available patches:")
|
||||
for name in sorted(dir(kp)):
|
||||
if name.startswith("patch_") and callable(getattr(kp, name)):
|
||||
print(f" {name}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n[*] Applying: {patch_name}")
|
||||
method()
|
||||
|
||||
# Apply the collected patches
|
||||
for off, patch_bytes, _ in kp.patches:
|
||||
data[off : off + len(patch_bytes)] = patch_bytes
|
||||
applied += 1
|
||||
|
||||
print(f"\n[+] {applied} patch(es) applied from {len(patch_names)} method(s)")
|
||||
|
||||
# Save
|
||||
save_firmware(kernel_path, im4p, data, was_im4p, original_raw)
|
||||
print(f"[+] Saved: {kernel_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user