我应该给Frida`ObjC.api.class_addMethod()`输入什么参数以使其满意?

时间:2020-02-02 18:06:45

标签: objective-c frida

我想使用Frida在Mac OS上向现有的Objective C类添加类方法。在阅读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都冻结了,看起来指针不正确。

我整夜尝试了许多可能的参数值,但仍然可以找出问题所在。我的代码有什么问题?

1 个答案:

答案 0 :(得分:1)

只有两个问题:

  • method_getTypeEncoding()只能在Method上被调用,而NativeCallback则不能。您可以将具有与要添加的签名相同签名的现有Objective-C方法的句柄传递给它,或使用Memory.allocUtf8String()从头开始指定自己的签名。
  • Objective-C方法在C ABI级别上,在方法的参数之前有两个隐式参数。这些是:
      1. self:要在其上调用该方法的类/实例。
      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()来进行旋转。