I’m using Frida to hook into my Swift iOS app called TestApp2. I want to read and modify the class property counter. The class is:
// ContentView.swift
class ContentViewModel: ObservableObject {
@Published var counter: Int = 0
func incrementCounter() {
counter += 1
}
}
I’ve successfully hooked the incrementCounter() method and captured the self pointer, which I assume is the pointer to the ContentViewModel class instance:
// hook.js
const TARGET_SYMBOL = '$s8TestApp216ContentViewModelC16incrementCounteryyF';
const module = Process.findModuleByName('TestApp2');
const targetAddress = module.findExportByName(TARGET_SYMBOL);
var selfPtr = null
Interceptor.attach(targetAddress, {
onEnter: function(args) {
selfPtr = args[0]; // ContentViewModel instance pointer
console.log(`[+] Self pointer: ${selfPtr}`);
}
});
I run the above script with this frida command:
frida -U TestApp2 --auto-reload -l hook.js
I open the app and tap the Increment button, which shows this result in Frida:
[iPhone::TestApp2 ]-> [+] Self pointer: 0x280eb0860
Question
How do I read and modify the current value of counter given this pointer?
What I’ve Tried
- Using
Swift.Objectwrapper:
[iPhone::TestApp2 ]-> var temp = new Swift.Object(selfPtr, "ContentViewModel");
[iPhone::TestApp2 ]-> temp.counter; // undefined
[iPhone::TestApp2 ]-> temp
{
"handle": "0x280eb0860" // not sure what to do with this handle
}
- Accessing through
Swift.classes:
[iPhone::TestApp2 ]-> Swift.classes.ContentViewModel
{
"$conformances": [
"ObservableObject"
],
"$fields": [
{
"isVar": true,
"name": "_counter", // the _counter variable name is shown but the value is not
"typeName": "Published"
}
],
"$methods": []
}
- Direct memory reading (trying different offsets):
[iPhone::TestApp2 ]-> selfPtr.add(0x10).readS64() // not sure of correct offset
"10785265760"
Environment
- iOS 15.8.5 (jailbroken)
- Frida 17.3.2
- Swift class (not
@objcexposed)
Full TestApp2 Code for Context
The whole app consists of just these two files below.
ContentView.swift:
import SwiftUI
import Combine
class ContentViewModel: ObservableObject {
@Published var counter: Int = 0
func incrementCounter() {
counter += 1
}
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
var body: some View {
VStack(spacing: 20) {
TextField("Counter", value: $viewModel.counter, format: .number)
.textFieldStyle(RoundedBorderTextFieldStyle())
.multilineTextAlignment(.center)
.frame(width: 100)
Button("Increment") {
viewModel.incrementCounter()
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
#Preview {
ContentView()
}
TestApp2App.swift
import SwiftUI
@main
struct TestApp2App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}