Skip to content

Instantly share code, notes, and snippets.

@miticollo
Last active February 19, 2025 06:01
Show Gist options
  • Save miticollo/12e3fff5ba8fab7dd707c874105a508f to your computer and use it in GitHub Desktop.
Save miticollo/12e3fff5ba8fab7dd707c874105a508f to your computer and use it in GitHub Desktop.
How to build frida-server (≥ 16.2.2) for iOS jailbroken devices
#!/usr/bin/env bash
#
# Build Frida DEB.
# register the cleanup function to be called on the EXIT signal
trap cleanup INT
#######################################
# Deletes the temp directory.
# Globals:
# FRIDA_PREFIX
# Arguments:
# None
# Outputs:
# Writes location to stdout
#######################################
function cleanup {
# shellcheck disable=SC2317
rm -rf "${FRIDA_PREFIX}"
# shellcheck disable=SC2317
echo "Deleted temp working directory ${FRIDA_PREFIX}"
}
# Constant
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly WARN='\033[1;33m'
readonly NC='\033[0m' # No Color
if ! args=$(getopt hV: "${@}"); then echo "Try '$(basename "${0}") --help' for more information" >&2 ; exit 255 ; fi
# shellcheck disable=SC2086
set -- ${args}
set -e
function err() {
echo -e "${RED}[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*${NC}" >&2
}
function usage() {
# TODO(miticollo): list available Frida version
echo \
"Usage:
$(basename "$0") [-h] [-V | --version <version>]
Build Frida DEB.
Options:
-V <version> set which Frida version you want to build.
It only works on >= 16.2.1.
Default: latest.
-h display this help"
}
function is_command_installed() {
if ! command -v "${1}" &> /dev/null
then
err "${1} could not be found"
exit 1
fi
}
function main() {
is_command_installed 'git'
is_command_installed 'gmake'
is_command_installed 'xcrun'
is_command_installed 'python'
is_command_installed 'npm'
is_command_installed 'node'
while :; do
case "$1" in
-V | --version )
version="${2}"
shift 2
IFS='.' read -r -a array <<< "${version}"
if (( array[0] < 16 )) ; then
err "Invalid version: ${version}!"
exit 1
fi
if (( array[0] == 16 )) && (( array[1] < 2 )) ; then
err "Invalid version: ${version}!"
exit 1
fi
if (( array[0] == 16 )) && (( array[1] == 2 )) && (( array[2] < 1 )) ; then
err "Invalid version: ${version}!"
exit 1
fi
;;
-h | --help )
usage
exit 0
;;
-- )
# unreachable statement
break
;;
esac
done
export PYTHONWARNINGS=all
git clone https://github.com/frida/frida.git
pushd frida || exit 1
if [[ -z ${version+x} ]]; then
version="$(git describe --tags "$(git rev-list --tags --max-count=1)")"
echo -e "${GREEN}Latest Frida version: ${version}${NC}"
fi
readonly version
git checkout "${version}"
python3 -m venv --upgrade-deps '.venv'
# shellcheck source=/dev/null
source ./.venv/bin/activate
python3 -m pip install --upgrade pip setuptools wheel
# Set up environment
IOS_CERTID=frida-cert
export IOS_CERTID
# Check out releng
git submodule update --init --depth 1 releng
pushd releng || exit 2
git submodule update --init --depth 1
popd || exit 3
# Add convenience environment variable
FRIDA_VERSION=$(releng/frida_version.py)
export FRIDA_VERSION
FRIDA_PREFIX="$(mktemp -d /tmp/runner_workspace.XXXXXX)"
export FRIDA_PREFIX
export XCODE11=/Applications/Xcode-11.7.app
PYTHON="$(which python3)"
export PYTHON
mkdir -vp 'tmp'
if releng/deps.py sync 'sdk' 'ios-arm64eoabi' 'tmp' ; then
rm -rf tmp
else
# TODO(miticollo): Add option to skip arm64eoabi SDK build
echo -e "${WARN}SDK for ARM64e (old ABI) not found! I will compile it for you${NC}"
./releng/deps.py build --bundle=sdk --host=ios-arm64eoabi
fi
for arch in "" "oabi"; do
MESON_BUILD_ROOT="$(pwd)/build-arm64e${arch}"
export MESON_BUILD_ROOT
./configure \
--prefix=/usr \
--host=ios-"arm64e${arch}" \
-- \
-Dfrida-core:assets=installed
gmake -j$(($(/usr/sbin/sysctl -n hw.logicalcpu) + 1))
DESTDIR="${FRIDA_PREFIX}/dist-arm64e${arch}" gmake -j$(($(/usr/sbin/sysctl -n hw.logicalcpu) + 1)) install
done
mkdir -vp "${FRIDA_PREFIX}/ios-arm64e"{oabi,}
mkdir -vp "${FRIDA_PREFIX}/ios-assets/usr/"{bin,lib/frida}/
mkdir -vp "release-assets-${version}"
# Create universal frida-server for iOS
for arch in "64" "64e"; do
lipo "${FRIDA_PREFIX}/dist-arm64e/usr/bin/frida-server" -thin "arm${arch}" -output "${FRIDA_PREFIX}/ios-arm64e/frida-server-arm${arch}"
codesign -vf -s "-" --preserve-metadata=entitlements "${FRIDA_PREFIX}/ios-arm64e/frida-server-arm${arch}"
done
lipo "${FRIDA_PREFIX}/dist-arm64eoabi/usr/bin/frida-server" -thin arm64e -output "${FRIDA_PREFIX}/ios-arm64eoabi/frida-server-arm64eoabi"
codesign -vf -s "-" --preserve-metadata=entitlements "${FRIDA_PREFIX}/ios-arm64eoabi/frida-server-arm64eoabi"
# Sign universal frida-agent for iOS/arm64(e)
codesign -vf -s "-" --preserve-metadata=entitlements --timestamp=none "${FRIDA_PREFIX}/dist-arm64e/usr/lib/frida/frida-agent.dylib"
mv -v "${FRIDA_PREFIX}/dist-arm64e/usr/lib/frida/frida-agent.dylib" "${FRIDA_PREFIX}/ios-assets/usr/lib/frida/frida-agent.dylib"
./releng/mkfatmacho.py \
"${FRIDA_PREFIX}/ios-assets/usr/bin/frida-server" \
"${FRIDA_PREFIX}/ios-arm64e/frida-server-arm64" \
"${FRIDA_PREFIX}/ios-arm64eoabi/frida-server-arm64eoabi" \
"${FRIDA_PREFIX}/ios-arm64e/frida-server-arm64e"
for arch in "" "64" "64e"; do
./subprojects/frida-core/tools/package-server-fruity.sh \
"iphoneos-arm${arch}" \
"${FRIDA_PREFIX}/ios-assets" \
"release-assets-${version}/frida_${FRIDA_VERSION}_iphoneos-arm${arch}.deb"
done
cleanup
}
main "$@"
exit 0

Here, I'll show you how to compile frida-server (≥ 16.2.2) for rootfull, rootless and RootHide jailbreaks.

Old Instructions

If you want to compile an old version of Frida (< 16.2.2) you can use my old guide.

Build Instructions

Requirements

macOS

macOS is required because you need to use Apple's proprietary software like Xcode, lipo, and codesign.

Warning

Before starting, read carefully up to the end.

Build

  1. Install the latest version of Xcode with command-line tools from the App Store. Without it, you won't have iPhoneOS SDKs.
  2. Download Xcode 11.7 directly from Apple at the following link: Xcode_11.7.xip. You will need to authenticate with your Apple ID to download it. Then set the following env:
    export XCODE11=/Applications/Xcode-11.7.app

Tip

To better manage multiple Xcode versions, you can use a CLI tool called xcodes. Alternatively, if you prefer an equivalent GUI app, you can use XcodesApp.

  1. Once downloaded, opening the .xip archive will begin extracting it. After extraction, rename the app to avoid conflicting with your primary installation of Xcode and move it to /Applications/ (e.g., mv Xcode.app /Applications/Xcode-11.7.app).
  2. Download this script, change gdb_codesign to frida-cert, and then run it.
  3. Run brew install dpkg to install dpkg-deb.

Note

To compile Frida I use gmake. If you don't want to install it you can use make shipped by Apple with Xcode Command Line Tools.

  1. Clone the frida-core project:
    git clone https://github.com/frida/frida-core.git
    cd frida-core
  2. (Optional) Check out the latest stable release:
    git checkout "$(git describe --tags "$(git rev-list --tags --max-count=1)")"
    To go back to origin/main, run git switch -.
  3. (Optional) Select your preferred Xcode version:
    export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer  
  4. Export the identity previously created in an enviroment variable called IOS_CERTID:
    export IOS_CERTID=frida-cert
  5. To package everything you must set the following env:
    gmake git-submodules
    FRIDA_VERSION=$(releng/frida_version.py)
    export FRIDA_VERSION
  6. (Optional) If you want to edit frida-server behaviour, you can do it now!

Warning

If you don't want to cross-compile Frida for rootfull remove it from for loop. But to compile RootHide rootless is always required!

  1. Build frida-server and frida-agent.dylib for 3 different architectures:
    mkdir -vp release-assets
    for jb in rootless rootfull; do
      for arch in arm64 arm64e arm64eoabi; do
        MESON_BUILD_ROOT="$(pwd)/build-${arch}-${jb}"
        export MESON_BUILD_ROOT
        if [ "${jb}" = "rootless" ]; then
          ./configure --prefix='/var/jb' --host=ios-"${arch}" --enable-server
        else
          ./configure --host=ios-"${arch}" --enable-server --with-devkits=core
        fi
        gmake -j$(($(/usr/sbin/sysctl -n hw.logicalcpu) + 1))
      done
      frida_ios_universal_path="$(pwd)/ios-${jb}-assets/$(if [ "${jb}" = "rootless" ]; then echo "var/jb/"; fi)"
      mkdir -vp "${frida_ios_universal_path}"/usr/{bin,lib/frida}/
      python ./releng/mkfatmacho.py "${frida_ios_universal_path}/usr/bin/frida-server" "$(pwd)/build-"{arm64,arm64e,arm64eoabi}"-${jb}/server/frida-server"
      codesign -vf -s "-" --preserve-metadata=entitlements "${frida_ios_universal_path}/usr/bin/frida-server"
      lipo "$(pwd)/build-"{arm64,arm64e}"-${jb}/lib/agent/frida-agent.dylib" -create -output "${frida_ios_universal_path}/usr/lib/frida/frida-agent.dylib"
      install_name_tool -id 'FridaAgent' "${frida_ios_universal_path}/usr/lib/frida/frida-agent.dylib"
      codesign -s "$IOS_CERTID" -fv --timestamp=none --generate-entitlement-der "${frida_ios_universal_path}/usr/lib/frida/frida-agent.dylib"
      arch=$(if [ "${jb}" = "rootless" ]; then echo "arm64"; else echo "arm"; fi)
      ./tools/package-server-fruity.sh "iphoneos-${arch}" "${frida_ios_universal_path}" release-assets/"frida_${FRIDA_VERSION}_iphoneos-${arch}.deb"
    done
    mkdir -vp "$(pwd)/ios-roothide-assets/var/jb/usr/"{bin,lib/frida}/
    cp -v "$(pwd)/ios-rootless-assets/var/jb/usr/bin/frida-server" "$(pwd)/ios-roothide-assets/var/jb/usr/bin/"
    cp -v "$(pwd)/ios-rootless-assets/var/jb/usr/lib/frida/frida-agent.dylib" "$(pwd)/ios-roothide-assets/var/jb/usr/lib/frida/"
    ./tools/package-server-fruity.sh "iphoneos-arm64e" "$(pwd)/ios-roothide-assets/var/jb/" release-assets/"frida_${FRIDA_VERSION}_iphoneos-arm64e.deb"

Note

To properly instrument all applications, all necessary architectures must be in place. For instance, to instrument Safari, the frida-agent.dylib for ARM64e is required. However, for Spotify, the required architecture is ARM64. If the frida-agent.dylib does not contain both slices, you will likely encounter an Incompatible Mach-O image error when using the frida CLI tool.
To check what I said, compare the output of the following two commands:

file /Applications/MobileSafari.app/MobileSafari
file /var/containers/Bundle/Application/<UUID>/Spotify.app/Spotify
  1. Check the release-assets/ directory to find your DEBs file. Enjoy!
@zhaojiafu
Copy link

Hello, do you have a deb installation package for arm64e? Share it? I refer to your tutorial steps here, and the compilation has been stuck and failed. I have been working on it all day today but I have failed

@miticollo
Copy link
Author

Hi @zhaojiafu! Go to https://miticollo.github.io/repos/#roothide and add my repo. I know it is outdated but I tried that version of frida-server with Frida 16.5.5 from Pypi and it works. Maybe I will add other versions. Anyway you can compile your own with build_frida.sh script.

@zhaojiafu
Copy link

Thank you, your https://miticollo.github.io/repos/#roothide can be used

@faryx
Copy link

faryx commented Feb 19, 2025

Hi @miticollo this repo https://miticollo.github.io/repos/#roothide can used in iPhone 12 Mini with Jailbreak Roothide Dopamine ? because i dont understand to build frida

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment