我应该向 Frida `ObjC.api.class_addMethod()` 提供什么参数才能让它开心?

What parameter should I feed to Frida `ObjC.api.class_addMethod()` to make it happy?

我想使用 Frida 在 Mac OS 上现有的 Objective C class 添加一个 class 方法。在我阅读了 Frida docs 之后,我尝试了以下代码:

const NSString = ObjC.classes.NSString

function func (n) { console.log(n) }

var nativeCb = new NativeCallback(func, 'void', ['int'])

ObjC.api.class_addMethod(
  NSString.handle,
  ObjC.selector('onTest:'),
  nativeCb,
  ObjC.api.method_getTypeEncoding(nativeCb)
)

上面的代码看起来很简单。然而,ObjC.api.class_addMethod()调用后,附加的App和Frida REPL都卡住了,看来指针不对。

我试了很多可能的参数值一晚上,还是能解决问题。我的代码有什么问题?

只有两个问题:

  • method_getTypeEncoding() 只能在 Method 上调用,而 NativeCallback 则不能。您可以将现有 Objective-C 方法的句柄传递给它,该方法与您要添加的方法具有相同的签名,或者使用 Memory.allocUtf8String() 从头开始​​指定您自己的签名。
  • Objective-C 方法,在 C ABI 级别,在方法参数之前有两个隐式参数。这些都是:
      1. self: class/instance 正在调用该方法。
      1. _cmd:选择器。

这是一个完整的 TypeScript 示例:

const { NSAutoreleasePool, NSString } = ObjC.classes;

const onTest = new NativeCallback(onTestImpl, "void", ["pointer", "pointer", "int"]);

function onTestImpl(selfHandle: NativePointer, cmd: NativePointer, n: number): void {
    const self = new ObjC.Object(selfHandle);
    console.log(`-[NSString onTestImpl]\n\tself="${self.toString()}"\n\tn=${n}`);
}

function register(): void {
    ObjC.api.class_addMethod(
        NSString,
        ObjC.selector("onTest:"),
        onTest,
        Memory.allocUtf8String("v@:i"));
}

function test(): void {
    const pool = NSAutoreleasePool.alloc().init();
    try {
        const s = NSString.stringWithUTF8String_(Memory.allocUtf8String("yo"));
        s.onTest_(42);
    } finally {
        pool.release();
    }
}

function exposeToRepl(): void {
    const g = global as any;
    g.register = register;
    g.test = test;
}

exposeToRepl();

您可以将其粘贴到 https://github.com/oleavr/frida-agent-example,然后使用一个终端 运行 npm run watch 您可以使用 REPL 将其加载到 运行 应用程序:frida -n Telegram -l _agent.js.然后,您可以从 REPL 调用 register() 插入新方法,然后调用 test() 试一试。