Created
April 30, 2026 15:04
-
-
Save boska/43398b27c110126ee3678c84fa07c3ea to your computer and use it in GitHub Desktop.
Mobile App Hooking: Attack & Defense — Frida hook examples + iOS detection (companion to LinkedIn post)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // frida_hook_example.js | |
| // Educational: how Frida hooks a running iOS app | |
| // Reference: https://frida.re/docs/javascript-api/ | |
| // Run with: frida -U -n "TargetApp" -s frida_hook_example.js | |
| // --- Hook 1: Payment validation --- | |
| // Forces validatePurchase to always return YES | |
| var PaymentValidator = ObjC.classes.PaymentValidator; | |
| if (PaymentValidator) { | |
| var validatePurchase = PaymentValidator["- validatePurchase:"]; | |
| Interceptor.attach(validatePurchase.implementation, { | |
| onLeave: function(retval) { | |
| console.log("[*] Original result: " + retval); | |
| retval.replace(0x1); // Force return YES | |
| console.log("[*] Patched to: true"); | |
| } | |
| }); | |
| } | |
| // --- Hook 2: Biometric authentication bypass --- | |
| var LAContext = ObjC.classes.LAContext; | |
| if (LAContext) { | |
| var evaluatePolicy = LAContext["- evaluatePolicy:localizedReason:reply:"]; | |
| Interceptor.attach(evaluatePolicy.implementation, { | |
| onEnter: function(args) { | |
| var replyBlock = new ObjC.Block(args[4]); | |
| replyBlock.implementation = function(success, error) { | |
| console.log("[*] Biometric auth intercepted — forcing success"); | |
| replyBlock.implementation.call(this, 1, null); | |
| }; | |
| } | |
| }); | |
| } | |
| // --- Hook 3: SSL pinning bypass --- | |
| var SecTrustEvaluateWithError = Module.findExportByName( | |
| "Security", "SecTrustEvaluateWithError" | |
| ); | |
| if (SecTrustEvaluateWithError) { | |
| Interceptor.replace(SecTrustEvaluateWithError, new NativeCallback( | |
| function(trust, error) { | |
| console.log("[*] SSL trust evaluation bypassed"); | |
| return 1; // kSecTrustResultProceed | |
| }, | |
| "int", ["pointer", "pointer"] | |
| )); | |
| } | |
| console.log("[*] All hooks installed."); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // FridaDetection.swift | |
| // Basic Frida detection for iOS — simplified examples | |
| // | |
| // Further reading: | |
| // - Frida: https://frida.re | |
| // - OWASP Mobile Top 10: https://owasp.org/www-project-mobile-top-10/ | |
| // - iOS Security Guide: https://support.apple.com/guide/security/welcome/web | |
| // - Objection (Frida-based pentest tool): https://github.com/sensepost/objection | |
| import Foundation | |
| import MachO | |
| struct FridaDetector { | |
| // 1. Known Frida dylib names loaded in memory | |
| static func detectFridaLibraries() -> Bool { | |
| let signatures = ["frida-agent", "FridaGadget", "frida-gadget", "libfrida"] | |
| for i in 0..<_dyld_image_count() { | |
| guard let name = _dyld_get_image_name(i) else { continue } | |
| let lower = String(cString: name).lowercased() | |
| if signatures.contains(where: { lower.contains($0) }) { return true } | |
| } | |
| return false | |
| } | |
| // 2. Frida default server port (27042) | |
| static func detectFridaPort() -> Bool { | |
| var addr = sockaddr_in() | |
| addr.sin_family = sa_family_t(AF_INET) | |
| addr.sin_port = UInt16(27042).bigEndian | |
| addr.sin_addr.s_addr = inet_addr("127.0.0.1") | |
| let sock = socket(AF_INET, SOCK_STREAM, 0) | |
| defer { close(sock) } | |
| return withUnsafePointer(to: &addr) { | |
| $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { | |
| connect(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.size)) | |
| } | |
| } == 0 | |
| } | |
| // 3. Suspicious environment variables | |
| static func detectSuspiciousEnv() -> Bool { | |
| return ["DYLD_INSERT_LIBRARIES", "FRIDA_SERVER"] | |
| .contains(where: { getenv($0) != nil }) | |
| } | |
| // Run all checks — call early in app lifecycle | |
| static func isCompromised() -> Bool { | |
| return detectFridaLibraries() | |
| || detectFridaPort() | |
| || detectSuspiciousEnv() | |
| } | |
| } | |
| // Usage: | |
| // if FridaDetector.isCompromised() { | |
| // // terminate, degrade functionality, or alert backend | |
| // } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment