mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-02 02:34:29 +00:00
Fix dropbear host keys on writable Data
This commit is contained in:
+13
-1
@@ -411,6 +411,12 @@ ssh_cmd "/usr/bin/tar --preserve-permissions --no-overwrite-dir \
|
||||
-xf /mnt1/iosbinpack64.tar -C /mnt1"
|
||||
ssh_cmd "/bin/rm -f /mnt1/iosbinpack64.tar"
|
||||
|
||||
echo " Preparing dropbear host keys on Data volume..."
|
||||
ssh_cmd "/bin/mkdir -p /mnt3/dropbear"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_rsa_host_key ]; then /mnt1/iosbinpack64/usr/local/bin/dropbearkey -t rsa -f /mnt3/dropbear/dropbear_rsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_ecdsa_host_key ]; then /mnt1/iosbinpack64/usr/local/bin/dropbearkey -t ecdsa -f /mnt3/dropbear/dropbear_ecdsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "/bin/chmod 600 /mnt3/dropbear/dropbear_rsa_host_key /mnt3/dropbear/dropbear_ecdsa_host_key"
|
||||
|
||||
echo " [+] iosbinpack64 installed"
|
||||
|
||||
# ═══════════ 5/7 PATCH LAUNCHD_CACHE_LOADER ══════════════════
|
||||
@@ -493,7 +499,13 @@ echo " [+] vphoned installed (signed copy at .vphoned.signed)"
|
||||
|
||||
# Send daemon plists (overwrite on re-run)
|
||||
for plist in bash.plist dropbear.plist trollvnc.plist rpcserver_ios.plist; do
|
||||
scp_to "$INPUT_DIR/jb/LaunchDaemons/$plist" "/mnt1/System/Library/LaunchDaemons/"
|
||||
plist_src="$INPUT_DIR/jb/LaunchDaemons/$plist"
|
||||
if [[ "$plist" == "dropbear.plist" ]]; then
|
||||
plist_src="$TEMP_DIR/dropbear.plist"
|
||||
cp "$INPUT_DIR/jb/LaunchDaemons/dropbear.plist" "$plist_src"
|
||||
"$PYTHON3" "$SCRIPT_DIR/patchers/cfw.py" patch-dropbear-plist "$plist_src"
|
||||
fi
|
||||
scp_to "$plist_src" "/mnt1/System/Library/LaunchDaemons/"
|
||||
ssh_cmd "/bin/chmod 0644 /mnt1/System/Library/LaunchDaemons/$plist"
|
||||
done
|
||||
scp_to "$VPHONED_SRC/vphoned.plist" "/mnt1/System/Library/LaunchDaemons/"
|
||||
|
||||
@@ -408,6 +408,12 @@ ssh_cmd "/usr/bin/tar --preserve-permissions --no-overwrite-dir \
|
||||
-xf /mnt1/iosbinpack64.tar -C /mnt1"
|
||||
ssh_cmd "/bin/rm -f /mnt1/iosbinpack64.tar"
|
||||
|
||||
echo " Preparing dropbear host keys on Data volume..."
|
||||
ssh_cmd "/bin/mkdir -p /mnt3/dropbear"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_rsa_host_key ]; then /mnt1/iosbinpack64/usr/local/bin/dropbearkey -t rsa -f /mnt3/dropbear/dropbear_rsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_ecdsa_host_key ]; then /mnt1/iosbinpack64/usr/local/bin/dropbearkey -t ecdsa -f /mnt3/dropbear/dropbear_ecdsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "/bin/chmod 600 /mnt3/dropbear/dropbear_rsa_host_key /mnt3/dropbear/dropbear_ecdsa_host_key"
|
||||
|
||||
echo " [+] iosbinpack64 installed"
|
||||
|
||||
# ═══════════ 5/7 PATCH LAUNCHD_CACHE_LOADER ══════════════════
|
||||
@@ -487,7 +493,13 @@ echo " [+] vphoned installed (signed copy at .vphoned.signed)"
|
||||
|
||||
# Send daemon plists (overwrite on re-run)
|
||||
for plist in bash.plist dropbear.plist trollvnc.plist rpcserver_ios.plist; do
|
||||
scp_to "$INPUT_DIR/jb/LaunchDaemons/$plist" "/mnt1/System/Library/LaunchDaemons/"
|
||||
plist_src="$INPUT_DIR/jb/LaunchDaemons/$plist"
|
||||
if [[ "$plist" == "dropbear.plist" ]]; then
|
||||
plist_src="$TEMP_DIR/dropbear.plist"
|
||||
cp "$INPUT_DIR/jb/LaunchDaemons/dropbear.plist" "$plist_src"
|
||||
"$PYTHON3" "$SCRIPT_DIR/patchers/cfw.py" patch-dropbear-plist "$plist_src"
|
||||
fi
|
||||
scp_to "$plist_src" "/mnt1/System/Library/LaunchDaemons/"
|
||||
ssh_cmd "/bin/chmod 0644 /mnt1/System/Library/LaunchDaemons/$plist"
|
||||
done
|
||||
scp_to "$VPHONED_SRC/vphoned.plist" "/mnt1/System/Library/LaunchDaemons/"
|
||||
|
||||
+12
-3
@@ -52,6 +52,9 @@ Commands:
|
||||
inject-daemons <launchd.plist> <daemon_dir>
|
||||
Inject bash/dropbear/trollvnc into launchd.plist.
|
||||
|
||||
patch-dropbear-plist <dropbear.plist>
|
||||
Rewrite dropbear ProgramArguments to use /var/dropbear host keys.
|
||||
|
||||
inject-dylib <binary> <dylib_path>
|
||||
Inject LC_LOAD_DYLIB into Mach-O binary (thin or universal).
|
||||
Equivalent to: optool install -c load -p <dylib_path> -t <binary>
|
||||
@@ -76,7 +79,7 @@ if __name__ == "__main__":
|
||||
from patchers.cfw_patch_hv_vmm_dsc import patch_hv_vmm_in_dsc
|
||||
from patchers.cfw_patch_camera_dsc import apply_all_camera_patches
|
||||
from patchers.cfw_patch_watchdogd import patch_watchdogd
|
||||
from patchers.cfw_daemons import parse_cryptex_paths, inject_daemons
|
||||
from patchers.cfw_daemons import parse_cryptex_paths, inject_daemons, patch_dropbear_plist
|
||||
else:
|
||||
from .cfw_patch_seputil import patch_seputil
|
||||
from .cfw_patch_cache_loader import patch_launchd_cache_loader
|
||||
@@ -85,7 +88,7 @@ else:
|
||||
from .cfw_patch_hv_vmm_dsc import patch_hv_vmm_in_dsc
|
||||
from .cfw_patch_camera_dsc import apply_all_camera_patches
|
||||
from .cfw_patch_watchdogd import patch_watchdogd
|
||||
from .cfw_daemons import parse_cryptex_paths, inject_daemons
|
||||
from .cfw_daemons import parse_cryptex_paths, inject_daemons, patch_dropbear_plist
|
||||
|
||||
|
||||
def main():
|
||||
@@ -169,6 +172,12 @@ def main():
|
||||
sys.exit(1)
|
||||
inject_daemons(sys.argv[2], sys.argv[3])
|
||||
|
||||
elif cmd == "patch-dropbear-plist":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: patch_cfw.py patch-dropbear-plist <dropbear.plist>")
|
||||
sys.exit(1)
|
||||
patch_dropbear_plist(sys.argv[2])
|
||||
|
||||
elif cmd == "inject-dylib":
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: patch_cfw.py inject-dylib <binary> <dylib_path>")
|
||||
@@ -194,7 +203,7 @@ def main():
|
||||
print(f"Unknown command: {cmd}")
|
||||
print("Commands: cryptex-paths, patch-seputil, patch-launchd-cache-loader, patch-camera-dsc,")
|
||||
print(" patch-mobileactivationd, patch-launchd-jetsam,")
|
||||
print(" patch-hv-vmm-dsc, patch-watchdogd, inject-daemons, inject-dylib")
|
||||
print(" patch-hv-vmm-dsc, patch-watchdogd, inject-daemons, patch-dropbear-plist, inject-dylib")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,14 @@ from .cfw_asm import *
|
||||
import os
|
||||
import plistlib
|
||||
|
||||
|
||||
DROPBEAR_KEY_ARGS = [
|
||||
"-r",
|
||||
"/var/dropbear/dropbear_rsa_host_key",
|
||||
"-r",
|
||||
"/var/dropbear/dropbear_ecdsa_host_key",
|
||||
]
|
||||
|
||||
def parse_cryptex_paths(manifest_path):
|
||||
"""Extract Cryptex DMG paths from BuildManifest.plist.
|
||||
|
||||
@@ -53,6 +61,9 @@ def inject_daemons(plist_path, daemon_dir):
|
||||
with open(src, "rb") as f:
|
||||
daemon = plistlib.load(f)
|
||||
|
||||
if name == "dropbear":
|
||||
patch_dropbear_daemon(daemon)
|
||||
|
||||
key = f"/System/Library/LaunchDaemons/{name}.plist"
|
||||
target.setdefault("LaunchDaemons", {})[key] = daemon
|
||||
print(f" [+] Injected {name}")
|
||||
@@ -61,7 +72,38 @@ def inject_daemons(plist_path, daemon_dir):
|
||||
plistlib.dump(target, f, sort_keys=False)
|
||||
|
||||
|
||||
def patch_dropbear_daemon(daemon):
|
||||
"""Make dropbear use host keys on writable Data instead of read-only /etc."""
|
||||
args = list(daemon.get("ProgramArguments", []))
|
||||
if not args:
|
||||
return
|
||||
|
||||
# -R generates default keys under /etc/dropbear, which is read-only during
|
||||
# normal VM boot. Use explicit /var/dropbear keys seeded by cfw_install.
|
||||
cleaned = []
|
||||
idx = 0
|
||||
while idx < len(args):
|
||||
arg = args[idx]
|
||||
if arg == "-R":
|
||||
idx += 1
|
||||
continue
|
||||
if arg == "-r":
|
||||
idx += 2
|
||||
continue
|
||||
cleaned.append(arg)
|
||||
idx += 1
|
||||
args = cleaned + DROPBEAR_KEY_ARGS
|
||||
daemon["ProgramArguments"] = args
|
||||
|
||||
|
||||
def patch_dropbear_plist(plist_path):
|
||||
with open(plist_path, "rb") as f:
|
||||
daemon = plistlib.load(f)
|
||||
patch_dropbear_daemon(daemon)
|
||||
with open(plist_path, "wb") as f:
|
||||
plistlib.dump(daemon, f, sort_keys=False)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
# CLI
|
||||
# ══════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
@@ -98,6 +98,21 @@ chown -R 501:501 /var/jb/var/mobile/Library/Preferences
|
||||
chmod 0755 /var/jb/var/mobile/Library/Preferences
|
||||
log " Ownership set"
|
||||
|
||||
log "[2a/8] Preparing dropbear host keys..."
|
||||
mkdir -p /var/dropbear
|
||||
DROPBEARKEY=""
|
||||
for p in /iosbinpack64/usr/local/bin/dropbearkey /iosbinpack64/usr/local/dropbearkey /var/jb/usr/bin/dropbearkey; do
|
||||
[ -x "$p" ] && DROPBEARKEY="$p" && break
|
||||
done
|
||||
if [ -n "$DROPBEARKEY" ]; then
|
||||
[ -f /var/dropbear/dropbear_rsa_host_key ] || "$DROPBEARKEY" -t rsa -f /var/dropbear/dropbear_rsa_host_key >/dev/null
|
||||
[ -f /var/dropbear/dropbear_ecdsa_host_key ] || "$DROPBEARKEY" -t ecdsa -f /var/dropbear/dropbear_ecdsa_host_key >/dev/null
|
||||
chmod 0600 /var/dropbear/dropbear_rsa_host_key /var/dropbear/dropbear_ecdsa_host_key
|
||||
log " dropbear host keys ready"
|
||||
else
|
||||
log " WARNING: dropbearkey not found"
|
||||
fi
|
||||
|
||||
# ═══════════ 3/7 RUN prep_bootstrap.sh ═══════════════════════
|
||||
log "[3/8] Running prep_bootstrap.sh..."
|
||||
if [ -f /var/jb/prep_bootstrap.sh ]; then
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Unit tests for CFW LaunchDaemon plist rewrites."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, os.path.join(ROOT, "scripts"))
|
||||
|
||||
from patchers.cfw_daemons import DROPBEAR_KEY_ARGS, patch_dropbear_daemon # noqa: E402
|
||||
|
||||
|
||||
class DropbearPlistTests(unittest.TestCase):
|
||||
def test_rewrites_readonly_root_key_generation(self):
|
||||
daemon = {
|
||||
"ProgramArguments": [
|
||||
"/iosbinpack64/usr/local/bin/dropbear",
|
||||
"--shell",
|
||||
"/iosbinpack64/bin/bash",
|
||||
"-R",
|
||||
"-E",
|
||||
"-F",
|
||||
"-p",
|
||||
"22222",
|
||||
"-a",
|
||||
]
|
||||
}
|
||||
|
||||
patch_dropbear_daemon(daemon)
|
||||
|
||||
args = daemon["ProgramArguments"]
|
||||
self.assertNotIn("-R", args)
|
||||
self.assertEqual(args[-len(DROPBEAR_KEY_ARGS):], DROPBEAR_KEY_ARGS)
|
||||
|
||||
def test_replaces_stale_explicit_key_paths(self):
|
||||
daemon = {
|
||||
"ProgramArguments": [
|
||||
"dropbear",
|
||||
"-r",
|
||||
"/etc/dropbear/dropbear_rsa_host_key",
|
||||
"-E",
|
||||
"-r",
|
||||
"/tmp/old_ecdsa_key",
|
||||
"-p",
|
||||
"22222",
|
||||
]
|
||||
}
|
||||
|
||||
patch_dropbear_daemon(daemon)
|
||||
|
||||
args = daemon["ProgramArguments"]
|
||||
self.assertNotIn("/etc/dropbear/dropbear_rsa_host_key", args)
|
||||
self.assertNotIn("/tmp/old_ecdsa_key", args)
|
||||
self.assertEqual(args, ["dropbear", "-E", "-p", "22222", *DROPBEAR_KEY_ARGS])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user