iOS App Pentest: From Frida Installation to the Keybreak Curet

Depov

Activist
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
126
Reaction score
115
Deposit
0$
On the audit of the fintech application for iOS, we stumbled in a three-layer jailbreak detection - file checks, sandbox recording in /private and analysis of loaded dylib for FridaGadget. Standard Team objection explore It led to a crash in 200 milliseconds: the app ended before Frida managed to cling to the process. Liberty Lite is also bypassing - the application used custom inline-checks on C instead of standard ObjC methods. It took four hours to see the mechanics and writing of the working hook, but it was this case that showed a gap between training stands like DVIA-2 and what is found in the production. Below is a step-by-step analysis from the preparation of the device to the working Frida scripts that circumvent specific protection mechanisms.
Jailbreak bypass in the chain of mobile pentest
Bypassing the jailbreak detection is not the final goal, but the entrance barrier. Without it, the dynamic analysis of iOS applications is dead: the application is either crashed when running or cuts functionality to a futile state, blocking access to critical API calls.

Typical chain of iOS application punch:
1. Jailbreak + SSH-access - root on the device via Palera1n or checkra1n
2. Jailbreak detection bypass - bypass checks to make the application start normally
3. SSL penning bypass - TLS-pinnings to intercept traffic in Burp Suite
4. Runtime manipulation - Frida-hohoi for interception of API-chooks, Keychain dump, logic modification
5. Static analysis - decompilation of binary in Hopper or Ghidra, search for hardcoded secrets
6. Operation - IDOR, business logic flaws, API abuse on backend
Without step 2, everything else is nothing more than a theory.

According to MITRE ATT&CK jailbreak bypass - analogue of Virtualization/Sandbox EvasionT1497): the application tries to determine the modification of the execution environment, and the attacker masks this fact. Frida-hohodes implement Hooking (T0874) for interception and substitution of return values in runtime. The very mechanism of implementation of Frida in the process - Process Injection (T1055)

According to the OWASP MASVS classification, the jailbreak detection belongs to the category MASVS-RESILIENCE - resistance to reverse-engineering. The standard describes root/jailbreak detection, anti-debug, and runtime integrity checks as mandatory for high-risk applications. The task of the pentester is to check how these measures are resistant to a real attacker, and not to an automated scanner.
Preparing the environment: from jailbreak to Frida
Adjustments to the environment

1780615289810.png

An alternative to the physical device is Corellium: a cloud-based iOS virtualization platform with pre-diglished devices and built-in Frida console. No need to mess with the physical jailbreak. Minus - the cost of subscription and the inability to test hardware-specific protections (Secure Enclava, biometrics through SEP). On real-world projects, I prefer physics - Corellium is good for quick testing of hypotheses, but does not replace the living device.
Frida Installation and Versions Compatibility Problem
After the jailbreak, the first thing is SSH. In Sileo, put the OpenSH package, port 22 on the device opens automatically. Default creeds: mobile:alpine and root:alpine - change their team passwd through SSH to connect to Wi-Fi. Seriously, before the connection. I saw the cases when the device was sent from the outside in the first seconds after connecting to the network.

To connect via USB (free Wi-Fi, which is safer) on macOS need usbmuxd: put through brew install usbmuxd, then the port by the team iproxy 2222 22 & and connection through ssh -p 2222 mobile@localhost.

Next up is the Frida server. In Sileo add a repository https://build.frida.re, put the Frida package - the server starts automatically. Verification: ps aux | grep frida should show the process /usr/sbin/frida-server.

And that's where the pain begins. The current version of Frida in Sileo is 17.5.2 (at the time of publication), and is compatible only with Frida 16.7.19. The discrepancy between the majority versions of the client and the server leads to a connection error - in silence, without a clear message. Solution - dawnreads Frida-servers on the device until 16.7.19 through the update script with the GitHub repository Frida (script downloads the desired version .deb-package and installs through dpkg) After the daungreyide is required to reboot the device and re-activation of the jailbreak team palera1n -f.

On the macOS host client is put through pip install frida==16.7.19 frida-tools==12.3.0 (version frida-tools must comply with the version of Frida - check in release notes). Verification: frida --version must return 16.7.19. If the versions have dispersed at least to the minor - prepare for slurred errors when connected.
Anatomy jailbreak detection in iOS applications
To get around the defense, you need to understand what exactly she is checking. According to the results of the analysis of the source code of iOS Security Suite (discussed published by the researchers of Appknox) and the real behavior of banking applications, the checks are divided into three categories.
File checks and URL diagrams
The most common and weakest method. The annex calls NSFileManager.fileExistsAtPath: or C-functions fopen()/access() for the paths characteristic of the jailbreaked device:
• /Applications/Cydia.app- classic marker
• /usr/sbin/sshd- OpenSSH server
• /bin/bash- non-standard shell
• /usr/bin/ssh- SSH client
• /etc/aptand /private/var/lib/apt/- traces of APT-manager packets
In parallel, URL schemes are checked: UIApplication.canOpenURL: Testing Accessibility sileo://, cydia://, undecimus://. At least one is available - the jelbreaker marker.

By source code iOS Security Suite, method performChecks() implements eight separate inspections:
1. Check URL Schemes - Availability sileo://and analogues
2. Check Existence Of Suspificend Files - fileExists(atPath:), fopen, accessin read-only
3. Check Suspiced Files Can Be Opened - isReadableFile(atPath:)and write-regime
4. Check Restricted Directories Writable - Attempt to Record /, /root, /private
5. Check Fork - sandbox violation through fork()
6. Check Symbolic Links - non-standard symlinks in system directories
7. Check DYLD - uploaded libraries: FridaGadget, CydiaSubstrate
8. Check Suspicious ObjC Classes - Shadow detection (bypass-twick)
Method amIJailbroken() Aggregates the results: at least one check is not passed - returns true, the device is considered compromised. Sounds threatening, but most apps use three to four of eight checks.
Sandbox tests, fork() and system calls
File checks cost simply - hunch on fileExistsAtPath: and a change of answer. More Seriously - Sandbox Tests: The app is trying to create and delete a file in a directory that is only available for reading on iOS (/private, /root) The recording was successful - sandbox is broken.

Challenge fork() - another indicator. On the flow of iOS sandbox prohibits the creation of child processes. If fork() returns the valid PID instead of an error - the device jelbreakuto. This test is more difficult to bypass: fork() - a system call, not ObjC-method, and an interception requires a hook at the level of C-functions.
DYLD analysis: Frida and Substrate detection
Advanced applications are included in the list of downloaded dynamic libraries through _dyld_image_count() and _dyld_get_image_name(). The list is looking for lines:
• FridaGadgetand frida-agent- Frida
• CydiaSubstrateand SubstrateLoader- Cydia Substrate
• libhooker- LibHooker (Substrate)
If Frida is implemented through frida-server, her agent appears in the dylib list - the app sees and paints it. Some additionally scan TCP port 27042 (Fida default port) or check the presence of ObjC classes associated with bypass-twos.

This is a direct detection of the pentester’s tools, and standard bypass-twicks (Liberty Lite, Shadow) is not always closed: iOS Security Suite in check No. 8 itself detects Shadow by the name ObjC-class. Classic Arms Race.
Bypass jailbreak detection: practice with Frida
Working with Swift modules and iOS Security Suite
With Swift, the situation is fundamentally different. Swift methods are not exported to ObjC runtime - their names are subject to name mangling, and direct access through ObjC.classes Impossible. For a hook, you need an accurate offset method in a binary.

Workflow to bypass iOS Security Suite in the Swift app (according to the Appknox methodology):
1. Unpack the IPA: unzip target.ipa -d Payload/
2. Find a framework: Payload/<name>.app/Frameworks/IOSSecuritySuite.framework
3. Open a binary in radare2: r2 IOSSecuritySuite, perform aaafor full analysis
4. Find the target method: afl | grep amIJail- get offset method amIJailbroken
5. Calculate runtime address: Module.getBaseAddress("IOSSecuritySuite")+ offset
6. Put Interceptor.attachthe Calcified Address
For Flutter applications that use flutter_jailbreak_detection (wrapper on iOS Security Suite), it is enough to bypass one method - amIJailbroken(). Flutter-plugin inside causes IOSSecuritySuite.amIJailbroken() and broadcasts the result in the Dart layer. Bypass at the level of the native framework breaks the whole chain. One hook – and Flutter part of the app doesn’t even know that the device is jailbreaked.

A separate headache - applications where iOS Security Suite is compiled statically (compiled into the main binary, and not as a separate .framework) Method amIJailbroken is not in a separate module, but mainly an executable file. Search offset through radare2 remains the same, but Module.getBaseAddress You need to call for the main binary of the application. Smallness, but at the first collision takes an hour for debugging.
What to Use: Decision Tree for iOS Pentest

1780615306762.png

Algorithm of choice:
1. Run objection explore- The app works? Yes - go to SSL penning bypass, jailbreak detection is decided.
2. No (crash at startup) - run through spawning: frida -U -f com.target.app -l bypass.js --no-pause. The bypass.js script contains hookies from the previous section.
3. Frida is detected - check if the application scans port 27042. Change the port: stop on the device frida-serverand restart with the flag frida-server -l 0.0.0.0:1337. Alternative - implementation through Frida Gadget (dylib, compiled to IPA) instead of frida-server.
4. Still shaking - static analysis of the binary. In the disassembler, find a conditional transition (CBZ/CBNZ in ARM64), responsible for the branching “jailbroken / not jaybroken”, and replace with NOP. Resign binary through ldid -Sor codesign.
Restrictions of the techniques bypass the jailbreak detection
1780615318724.png

Specific scenarios where standard approaches break:

Server-side validation. The application sends the result of jailbreak-checking for a backend, and the server already decides to block. Customer bypass is useless - you need to intercept an HTTP request through Burp Suite (after bypassing SSL pinning) and replace the value isJailbroken: true on false in the body of the request. In fact, all customer protection is reduced to one parameter in JSON.

Obfuscation of names. Commercial SDKs obfuscate the names of classes and methods. Instead of isJailbroken - a3x_k9m. Search through ObjC.classes by name will not give a result. Solution - static analysis in Hopper or Ghidra with branching from the point of dap back by call graph. It's flouty, but it works.

Anti-Frida. Applications that purposefully detect Frida (DLDD-check on frida-agent. port scan 27042, Detection Interceptor through integrity checks), require the modification of the Frida itself - reassembled from the source with modified string literals and a default port. The lesson is not for the faint of heart, but sometimes it is the only way.

Timing-based detection. A number of protective SDK measures the time of the check: if the jailbreak function worked abnormally quickly (hook instantly returned false without real execution of checks), the application treats it as bypass. Bypass - adding delay to the hook through Thread.sleep(0.1) or execution of part of the original logic before changing return value. Cleverly, but predictable.

Integrity checks. The application calculates the hash of its own binary at launch and compares with the standard. Pattled binary (NOP instead of CBZ) - the hash does not match - the application refuses to work. To bypass, you need either runtime-hook function of checking hash, or a recalculation of the reference value after the patch.

Liberty Lite (Dar, A-Bypass) intercept system APIs: when the application asks “is there? /Applications/Cydia.app?", Twik replaces the answer to "no". But the updates are behind the SDK. Shadow is detectable by the iOS Security Suite in the No. 8 (Check Suspicious ObjC Classes) is a classic example of an arms race that jsmon.sh called “Cat and Mouse Game.”


Conclusion.
Over the past couple of years, the jailbreak detection has turned into the first serious barrier of the mobile pentest. Banking and fintech applications combine file analysis, DYLD inspection, sandbox tests and server-side validation. According to MASSVS-RESILIENCE - so it should be.

But here’s what I’m seeing in real audits: the vast majority of apps still rely on one or two methods from iOS Security Suite without customization. Bypass takes 15 minutes and ten lines of JavaScript. Really sustainable implementations – with inline C, immemorial obfuscation, anti-Frida and server-side confirmation – have met me in about three of the twenty audits over the past year. The remaining seventeen break down a standard Frida script with retval.replace(0x0).

This does not mean that the jailbreak detection is useless. This means that client protection without server validation is a decoration. So far the result amIJailbroken() not confirmed on backend, one Interceptor.attach reduces all the protection to zero. Pentesters who understand this architectural weakness, spend time not on another option to bypass fileExistsAtPath, and for the analysis of server logic - and it is there that the vulnerabilities that really cost the report are found.
 
Top Bottom