Skip to content

Instantly share code, notes, and snippets.

@Forgo7ten
Created August 20, 2026 17:16
Show Gist options
  • Select an option

  • Save Forgo7ten/d0f2d495f329af4511a8dd5a6984cd06 to your computer and use it in GitHub Desktop.

Select an option

Save Forgo7ten/d0f2d495f329af4511a8dd5a6984cd06 to your computer and use it in GitHub Desktop.
frida-update-ios.sh
#!/bin/bash
set -Eeuo pipefail
#
# Frida version
#
FRIDA_VER="${1:-}"
if [ -z "$FRIDA_VER" ]; then
echo "Usage: $0 <frida-version>"
echo "Example: $0 16.1.4"
exit 1
fi
#
# Only allow reasonable Frida version strings.
#
# Prevent accidental path characters such as / or spaces,
# especially because this script runs as root.
#
case "$FRIDA_VER" in
*[!0-9A-Za-z._-]*)
echo "[-] Invalid Frida version: $FRIDA_VER"
exit 1
;;
esac
#
# Must be root
#
if [ "$(id -u)" -ne 0 ]; then
echo "[-] This script must be run as root."
exit 1
fi
#
# Dopamine / rootless paths
#
JBROOT="/var/jb"
PLIST="${JBROOT}/Library/LaunchDaemons/re.frida.server.plist"
BACKUP="${PLIST}.backup"
SERVER="${JBROOT}/usr/sbin/frida-server"
DEB="/tmp/frida_${FRIDA_VER}_iphoneos-arm64.deb"
URL="https://github.com/frida/frida/releases/download/${FRIDA_VER}/frida_${FRIDA_VER}_iphoneos-arm64.deb"
#
# Confirm rootless environment
#
if [ ! -d "$JBROOT" ]; then
echo "[-] ${JBROOT} does not exist."
echo "[-] This does not look like a Dopamine/rootless environment."
exit 1
fi
#
# Find rootless launchctl.
#
# Prefer the Procursus/rootless version if present.
#
if [ -x "${JBROOT}/bin/launchctl" ]; then
LAUNCHCTL="${JBROOT}/bin/launchctl"
elif command -v launchctl >/dev/null 2>&1; then
LAUNCHCTL="$(command -v launchctl)"
else
echo "[-] launchctl not found."
exit 1
fi
echo "[*] Frida version : ${FRIDA_VER}"
echo "[*] Jailbreak root: ${JBROOT}"
echo "[*] launchctl : ${LAUNCHCTL}"
echo
#
# ------------------------------------------------------------
# STEP 1
#
# Download FIRST.
#
# Do not stop the currently working Frida until we know that
# the new package has been downloaded successfully.
# ------------------------------------------------------------
#
echo "[*] Downloading Frida ${FRIDA_VER}..."
rm -f "$DEB"
if command -v curl >/dev/null 2>&1; then
curl \
--fail \
--location \
--show-error \
--output "$DEB" \
"$URL"
elif command -v wget >/dev/null 2>&1; then
wget \
-O "$DEB" \
"$URL"
else
echo "[-] Neither curl nor wget is installed."
exit 1
fi
#
# Basic download sanity check
#
if [ ! -s "$DEB" ]; then
echo "[-] Download failed or downloaded file is empty."
rm -f "$DEB"
exit 1
fi
echo "[+] Package downloaded:"
ls -lh "$DEB"
echo
#
# ------------------------------------------------------------
# STEP 2
#
# Check existing plist
# ------------------------------------------------------------
#
HAD_OLD_PLIST=0
if [ -f "$PLIST" ]; then
HAD_OLD_PLIST=1
echo "[*] Existing Frida plist found:"
echo " $PLIST"
#
# Validate XML/plist before preserving it.
#
if command -v plutil >/dev/null 2>&1; then
echo "[*] Checking existing plist..."
if ! plutil -lint "$PLIST"; then
echo "[-] Existing plist is invalid."
echo "[-] Aborting before changing anything."
rm -f "$DEB"
exit 1
fi
fi
else
echo "[!] Existing Frida plist not found."
echo "[!] The plist provided by the new package will be used."
fi
echo
#
# ------------------------------------------------------------
# STEP 3
#
# Backup customized plist
# ------------------------------------------------------------
#
if [ "$HAD_OLD_PLIST" -eq 1 ]; then
echo "[*] Backing up existing plist..."
rm -f "$BACKUP"
cp -p \
"$PLIST" \
"$BACKUP"
if [ ! -f "$BACKUP" ]; then
echo "[-] Failed to create plist backup."
rm -f "$DEB"
exit 1
fi
echo "[+] Backup created:"
echo " $BACKUP"
fi
echo
#
# ------------------------------------------------------------
# Recovery function
#
# If something fails after this point, try to put the old
# plist back and start Frida again.
# ------------------------------------------------------------
#
RECOVERY_REQUIRED=1
recover()
{
EXIT_CODE=$?
if [ "$RECOVERY_REQUIRED" -eq 0 ]; then
return
fi
echo
echo "[-] Update failed."
echo "[*] Attempting recovery..."
#
# Stop whatever Frida package may have started.
#
if [ -f "$PLIST" ]; then
"$LAUNCHCTL" unload "$PLIST" 2>/dev/null || true
fi
#
# Restore previous plist.
#
if [ -f "$BACKUP" ]; then
echo "[*] Restoring previous plist..."
mv -f \
"$BACKUP" \
"$PLIST"
chown root:wheel "$PLIST" 2>/dev/null || true
chmod 644 "$PLIST" 2>/dev/null || true
echo "[*] Reloading previous Frida service..."
"$LAUNCHCTL" load "$PLIST" 2>/dev/null || true
fi
rm -f "$DEB"
echo "[-] Recovery finished."
exit "$EXIT_CODE"
}
trap recover ERR INT TERM
#
# ------------------------------------------------------------
# STEP 4
#
# Stop current Frida
# ------------------------------------------------------------
#
if [ "$HAD_OLD_PLIST" -eq 1 ]; then
echo "[*] Stopping existing Frida service..."
#
# unload returns an error when the service isn't currently
# loaded, which is harmless for an upgrade.
#
"$LAUNCHCTL" unload "$PLIST" 2>/dev/null || true
fi
#
# Extra safety: terminate a leftover frida-server only if
# launchctl didn't stop it.
#
sleep 1
echo "[*] Current Frida processes:"
ps aux | grep '[f]rida-server' || true
echo
#
# ------------------------------------------------------------
# STEP 5
#
# Install new Frida
# ------------------------------------------------------------
#
echo "[*] Installing Frida ${FRIDA_VER}..."
dpkg -i "$DEB"
echo "[+] dpkg completed."
echo
#
# ------------------------------------------------------------
# STEP 6
#
# Verify server binary
# ------------------------------------------------------------
#
if [ ! -x "$SERVER" ]; then
echo "[-] Installation completed but frida-server was not found:"
echo " $SERVER"
false
fi
echo "[*] Installed frida-server:"
echo " $SERVER"
echo "[*] Installed version:"
"$SERVER" --version
echo
#
# ------------------------------------------------------------
# STEP 7
#
# Restore customized plist
# ------------------------------------------------------------
#
if [ "$HAD_OLD_PLIST" -eq 1 ]; then
echo "[*] Restoring customized plist..."
#
# dpkg may have installed a new plist and may even have
# started Frida automatically.
#
# Stop that instance before restoring our configuration.
#
"$LAUNCHCTL" unload "$PLIST" 2>/dev/null || true
mv -f \
"$BACKUP" \
"$PLIST"
chown root:wheel "$PLIST" 2>/dev/null || true
chmod 644 "$PLIST"
fi
#
# Validate the final plist.
#
if command -v plutil >/dev/null 2>&1; then
echo "[*] Checking final plist..."
plutil -lint "$PLIST"
fi
#
# ------------------------------------------------------------
# STEP 8
#
# Start Frida
# ------------------------------------------------------------
#
echo "[*] Starting Frida..."
#
# In case the package already loaded it.
#
"$LAUNCHCTL" unload "$PLIST" 2>/dev/null || true
"$LAUNCHCTL" load "$PLIST"
#
# Give launchd a moment.
#
sleep 1
#
# ------------------------------------------------------------
# STEP 9
#
# Verify
# ------------------------------------------------------------
#
echo
echo "[*] Checking frida-server process..."
if ps aux | grep '[f]rida-server'; then
echo
echo "[+] frida-server is running."
else
echo
echo "[-] frida-server does not appear to be running."
false
fi
#
# Everything succeeded.
#
RECOVERY_REQUIRED=0
trap - ERR INT TERM
#
# Cleanup
#
rm -f "$DEB"
#
# Backup is temporary; the original plist is already restored.
#
rm -f "$BACKUP"
echo
echo "========================================"
echo "[+] Frida update completed successfully"
echo "========================================"
echo
echo "Version:"
"$SERVER" --version
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment