Skip to content

Instantly share code, notes, and snippets.

@boska
Created April 30, 2026 15:04
Show Gist options
  • Select an option

  • Save boska/43398b27c110126ee3678c84fa07c3ea to your computer and use it in GitHub Desktop.

Select an option

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)
// 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.");
// 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