Automated iOS Frida Gadget injection and Testflight deployment using Frida and Fastlane
Before you use this, you need to have access to an Apple Developer account as App Manager to create a new bundle ID and to generate an App Store Connect API key you must have Admin privileges.
- Create a new repository using this repositoriy as template
- Create an empty private git repository to store the certificate, the encrypted p12 and provisioning profiles ¹
- Create a Personal access token
- Create the below secrets
- This is not required if you do not wish to use the Fastlane MATCH action ( comment it on the Fastfile). Not using the MATCH action, means that you will be creating a new certificate each time you run the workflow and eventually you will reach the allowed distribution certificates threshold and you will have to go on the App Store Connect to manually revoke them.
DISCLAIMER This workflow uses MacOS github hosted runner, please do read the terms about billing for GitHub actions
-
ISSUERID - App Store Connect Issuer ID
-
KEY - App Store Connect Key
-
KEYID - App Store Connect Key ID
-
MATCH_GIT_BASIC_AUTHORIZATION - Basic Auth to access the certs github repository - base64(user:personal_access_token)
-
MATCH_PASSWORD - password for the certificate encryption process
-
MATCH_CERT_GIT_URL - Git repository to store the certificates - (https://github.com/your-certs-repo.git)
-
MATCH_TEAM_ID - App Store Team ID
Run the frilane workflow.
Input options:
- verbose: verbosity | default: true | required: false
- gum-graft-all: gum-graft LC_FUNCTION_STARTS offsets | default: false | required: false
- gum-graft-offset: gum-graft custom offsets ex.["0x1231","0x3134"] | default: '' | required: false
- upgrade_gadget: choose wether to upgrade and compile the frida Gadget | default: false | required: false
- arch: Frida Gadget architecture (only if upgrade_gadget is set to true) | options: ['arm64','arm64e','arm64eoabi','x86_64-simulator','arm64-simulator'] | default: 'arm64' | required: false
- appleid: AppleID | required: true
- bundleid: BundleID | required: true
- buildtype: Build type | options: ['appstore','development'] | default: 'appstore' | required: false
- bundleversion: Bundle Version (increase each run) | default: '1.23.45' | required: true
- ipaurl ¹: URL of the IPA file to be patched | required: true
- To serve the IPA file, you can combine ngrok and python http server module
- fastlane environment configuration
- Runs fastlane lane get_certificate:
- App connect api authentication
- CREATE_KEYCHAIN action to create a temporary keychain called frilane and unlock it
- MATCH action to fetch Codesign Certificate and p12 from private github repository (type: appstore / development)
- CERT and SIGH action to rename the cert and save it to file, generate provisioning profile and save to file. (Set to development if bundletype development is selected)
- obtains the signing identity and stores it in IOS_CERTID environment variable
- set the ACL on the keychain for codesigning
- OPTIONAL Upgrading Frida Gadget (if UPGRADE_GADGET variable is set to 'true'):
- clones latest frida github repository
- compiles Frida core-ios with FRIDA_JAILBREAK=disabled
- MATCH action to fetch Codesign Certificate and p12 from private github repository
- CERT and SIGH action to rename the cert and save it to file, generate provisioning profile and save to file.
- obtains the signing identity and stores it in IOS_CERTID environment variable
- set the ACL on the keychain for codesigning
- OPTIONAL Creates a arm64 framework from frida-gadget.dylib (if UPGRADE_GADGET variable is set to 'true')
- OPTIONAL Uploads Frida.framework content as an artifact (if UPGRADE_GADGET variable is set to 'true')
- Download the IPA file to patch using the URL provided on the input options (ipaurl input parameter)
- OPTIONAL Download gum-graft binary (if GUM_GRAFT_ALL is set to 'true' or GUM_GRAFT_OFFSET is not empty)
- OPTIONAL Saves gum-graft custom offsets to file, to be processed by the Frilane bash script (if GUM_GRAFT_OFFSET is not empty)
- Executes frilane script
- Prepare environment variables, folder and file paths
- Creates a temporary directory and extracts IPA file
- Executing gum-graft, two operating modes, Instrumentation of offsets from LC_FUNCTION_STARTS and Custom offsets (if GUM_GRAFT_ALL is set to 'true' or GUM_GRAFT_OFFSET is not empty)
- Copies SWIFT libs to the /SwiftSupport/iphoneos app directory
- Copy the framework directory to the app's Framework directory and load it using INSERT_DYLIB_TOOL (if BUILD_TYPE development, remove code_signign from config.json)
- Replaces CFBundleVersion and CFBundleShortVersion with X_BUNDLE_VERSION and X_SHORT_BUNDLE_VERSION provided on the input options
- Repacks IPA file
- fastlane resign_deploy
- resign action to re-sign IPA, frameworks and libs using the codesign certificate imported during step 1
- pilot action to eploy the patched IPA to TestFlight (if BUILD_TYPE is 'appstore')
- OPTIONAL Uploads patched IPA as an artifact that can be downloaded (if BUILD_TYPE is 'development')
- Commit and push the Frida framework upgraded version
- Refactor workflow and code
- Convert frilane script to python
- Prepare for multiple context execution, Local and CI/CD
- Install frida/frida-tools
- Install libimobiledevice (including usbmuxd)
- Start usbmuxd:
$ sudo usbmuxd -f -v
- Connect the device via USB
- Pair the device using idevicepair:
$ idevicepair pair
- Download an xcode developer disk image matching your devices iOS version ( you will find it on github :) )
- Mount the XCode developer disk image using ideviceimagemounter:
$ ideviceimagemounter <DeveloperDiskImage.dmg> <DeveloperDiskImage.dmg.signature>
- Start the patched app on the device
- Execute frida-ps and you should see the Gadget process:
$ frida-ps -Ua
- Attach to it using Frida or Objection
- Install ideviceinstaller
- Follow the above methods to connect the device and mount the developer disk
- Execute ideviceinstaller:
$ ideviceinstaller install <path to ipa file>
This is still work in progress, so please feel free to raise an issue or send a pm at Twitter if you would like to contribute or have any suggestions!