Skip to main content

Installing Frida on a Jailbroken Device

1

Add Frida Repository

Open Cydia or Sileo, go to Manage → Sources → Edit → Add, and enter:
https://build.frida.re
2

Install Frida Package

Find and install the Frida package from the newly added source.
3

Install Frida Tools on Host

pip install frida-tools frida
4

Verify Connection

frida-ls-devices   # List connected devices
frida-ps -Uia      # List running processes on USB device
If using Corellium, download the Frida release from GitHub (frida-gadget-[version]-ios-universal.dylib.gz), unpack it, and copy to the dylib location Frida requests (e.g., ~/.cache/frida/gadget-ios.dylib).

Frida on Non-Jailbroken Devices

Without jailbreak, you can use Frida Gadget embedded in the IPA. See the blog post on using Frida + Objection on non-jailbroken devices without patching.

Frida Trace

# Trace all functions containing "log"
frida-trace -U <program> -i "*log*"
frida-trace -U <program> -i "*log*" | swift demangle  # Demangle Swift names

# Trace all Objective-C methods
frida-trace -U <program> -m "*[* *]"

# Trace authentication methods in classes starting with "NE"
frida-trace -U <program> -m "*[NE* *authentication*]"

# Hook a plugin binary that is momentarily executed
frida-trace -U -W <plugin-binary> -m '*[* *]'

Enumerate Classes and Methods

List All Classes

// frida -U <program> -l script.js
var filterClass = ""  // Leave empty for all, or set to "NSString"

if (ObjC.available) {
  var classList = []
  for (var className in ObjC.classes) {
    if (!filterClass || className.toLowerCase().includes(filterClass.toLowerCase())) {
      classList.push(className)
    }
  }
  classList.sort().forEach(function(name) { console.log(name) })
} else {
  console.log("[!] Objective-C runtime not available")
}

List Methods of a Class

var specificClass = "NSURL"
var filterMethod = ""

if (ObjC.available && ObjC.classes.hasOwnProperty(specificClass)) {
  var methods = ObjC.classes[specificClass].$ownMethods
  methods
    .filter(function(m) { return !filterMethod || m.includes(filterMethod) })
    .forEach(function(m) { console.log(specificClass + ": " + m) })
}

Hook Objective-C Methods

// frida -U <program> -l hook-objc.js
function hookMethod(className, methodName) {
  var hook = ObjC.classes[className][methodName]
  if (!hook) { console.log("[!] Not found: " + className + "." + methodName); return }

  Interceptor.attach(hook.implementation, {
    onEnter: function(args) {
      console.log("\n[*] Called: [" + className + " " + methodName + "]")
      try {
        var selfObj = new ObjC.Object(args[0])
        console.log("    self: " + selfObj)
      } catch (e) {}
    },
    onLeave: function(retval) {
      try { console.log("    => " + new ObjC.Object(retval)) } catch (e) {}
    }
  })
  console.log("[+] Hooked: [" + className + " " + methodName + "]")
}

if (ObjC.available) {
  hookMethod("LoginViewController", "- authenticate:")
  hookMethod("NSUserDefaults", "- setObject:forKey:")
  hookMethod("NSURLSession", "- dataTaskWithRequest:completionHandler:")
}

Method Swizzling — Always Return True

function swizzleMethod(className, methodName, newImpl) {
  var method = ObjC.classes[className][methodName]
  if (!method) return
  method.implementation = ObjC.implement(method, function(self, sel) {
    return newImpl(self, sel, arguments)
  })
}

// Bypass authentication
swizzleMethod("AuthManager", "- isAuthenticated", function() {
  console.log("[!] Bypassing auth check")
  return 1
})

LLDB + Frida: Bypassing Jailbreak & Frida Detection in Swift Apps

Remote Debugging Pipeline

# 1. SSH port forwarding
iproxy 2222 22 &
ssh root@localhost -p 2222

# 2. On device: attach debugserver
debugserver *:5678 --waitfor <BundleName>
# Then launch app from SpringBoard

# 3. From macOS: connect LLDB
iproxy 1234 5678 &
lldb
(lldb) process connect connect://localhost:1234

Patch Swift Jailbreak Check

# Find the sanity check function
(lldb) image lookup -rn 'frida'
(lldb) image lookup -rn 'Check' FridaInTheMiddle.debug.dylib
(lldb) breakpoint set --name 'FridaInTheMiddle.systemSanityCheck'
(lldb) c        # Continue until breakpoint
(lldb) finish   # Run until return
(lldb) register write x0 0   # Set return value to false (arm64)
(lldb) c

Discovering Swift Function Names for Frida

# Dynamically discover mangled Swift symbol names
frida-trace -U <BundleName> -i "*dummy*"
# Trigger UI action — frida-trace logs the exact symbol
# e.g.: $s16FridaInTheMiddle11ContentViewV13dummyFunction4flagySS_tF

Hooking Swift String Arguments (arm64 ABI)

const mod = Module.load('FridaInTheMiddle.debug.dylib')
const fn = mod.findExportByName('$s16FridaInTheMiddle11ContentViewV13dummyFunction4flagySS_tF')
Interceptor.attach(fn, {
  onEnter() {
    const inlineLen = this.context.x0.and(0xff)
    if (inlineLen.toInt32() > 0 && inlineLen.toInt32() <= 15) {
      // Small string (≤15 bytes): packed inline in x0/x1
      console.log('flag:', this.context.x0.readUtf8String(inlineLen.toInt32()))
      return
    }
    // Large string: heap-backed, content at x1+32
    const heapPtr = ptr(this.context.x1).add(32)
    console.log('flag:', heapPtr.readUtf8String())
  }
})

Frida Stalker — Code Tracing

Interceptor.attach(func_addr, {
  onEnter: function (args) {
    Stalker.follow(Process.getCurrentThreadId(), {
      events: { compile: true },
      onReceive: function (events) {
        const bbs = Stalker.parse(events, { stringify: false, annotate: false })
        console.log("[+] Executed " + bbs.flat().length + " basic blocks")
      },
    })
  },
  onLeave: function (retval) {
    Stalker.unfollow(Process.getCurrentThreadId())
    Stalker.flush()
    Stalker.garbageCollect()
  },
})

Frida-Based Fuzzing with fpicker

fpicker is a Frida-based fuzzing suite supporting AFL++ mode and passive tracing.
# Install fpicker and radamsa
git clone https://github.com/ttdennis/fpicker
cd fpicker
wget https://github.com/frida/frida/releases/download/16.1.4/frida-core-devkit-16.1.4-macos-arm64.tar.xz
tar -xf ./*tar.xz && cp libfrida-core.a libfrida-core-macos.a
make fpicker-macos
brew install radamsa

# Prepare directories
mkdir -p examples/target-app/{out,in}
echo Hello World > examples/target-app/in/0

# Compile fuzzer script
frida-compile examples/target-app/myfuzzer.js -o harness.js

# Run fpicker
fpicker -v --fuzzer-mode active -e attach -p <TargetApp> -D usb \
  -o examples/target-app/out/ -i examples/target-app/in/ -f harness.js \
  --standalone-mutator cmd --mutator-command "radamsa"

References

Build docs developers (and LLMs) love