Object-C测试工具与Frida

Object-C测试工具与Frida

原文链接:rotlogix.com/2016/03/20

原文作者:Rotlogix

译者:lockdown(看雪ID:小调调)

搬运工:草莓丶(看雪ID:ksmokee)

微信公众号:看雪iOS安全小组

我们的微博:weibo.com/pediyiosteam

Overview

一个朋友最近在问怎么使用Frida来测试Objective-C的应用程序,我将这个过程分享给大家,这个简要的教程阐述了我是如何教他一步一步做到的。

Frida是一个非常强大的跨平台测试工具。对于那些不熟悉Frida是什么、能做什么的人,我强烈建议在开始这个教程之前,先去下面的网页查看一下。

frida.re/

在本教程中,我们将使用Frida在一个非常简单的Objective-C应用中,拦截一个方法(函数)。我们将使用Frida的Python通用接口来实现。

Objective-C Application

我们的Objective-C程序中有一个类叫Hook和一个实例化方法叫hookMe。该实例化方法有一个参数,并通过NSLog打印输出。

-(void)hookMe:(NSString *)arg {
NSLog(@"%@", arg);
}

在应用程序的main函数中,我们创建一个新的Hook实例,然后调用hookMe。

Hook *hook = [[Hook alloc]init];
[hook hookMe:@"Hello, World!"];

我们的目标是编写一个脚本,它将拦截hookMe并打印出其参数内容以及一些附加信息。

Hook.py

想要阅读完整的脚本,你可以在这里查看这里

在本教程中,我们仅关注注入到我们的目标进程中的JavaScript代码。我更倾向于对所有的Frida Python脚本使用相同的框架代码,所以你可以根据需要复制粘贴,并根据自己的需求添加自己所需要的功能。

for(var className in ObjC.classes) {  
    if (ObjC.classes.hasOwnProperty(className)) {
        if(className == "Hook") {
            send("Found our target class : " + className);
        }
    }
}

如果你查看Frida的文档中对Objective-C的支持,你会看到ObjC.classes返回当前注册类的映射表。 这些类可以很容易地通过for循环遍历,并且应该允许我们查找我们的目标类Hook。

它不包括在脚本中,但是可以使用以下的方式执行访问方法。

ObjC.classes.Hook.$methods;  

你可以使用特殊属性 $methods访问对象公开的方法数组。这将包括hookMe方法以及通过继承可用的任何其他方法。

事情从这里开始变的有趣了。

if(ObjC.available) {
    for(var className in ObjC.classes) {
        if (ObjC.classes.hasOwnProperty(className)) {
            if(className == "Hook") {
                send("Found our target class : " + className);
            }
        }
    }
    var hook = ObjC.classes.Hook["- hookMe:"];
    Interceptor.attach(hook.implementation, {
        onEnter: function(args) {
            var receiver = new ObjC.Object(args[0]);
            send("Target class : " + receiver);
            send("Target superclass : " + receiver.$superClass);
            var sel = ObjC.selectorAsString(args[1]);
            send("Hooked the target method : " + sel);
            var obj = ObjC.Object(args[2]);
            send("Argument : " + obj.toString());
        }
    });
} else {
    console.log("Objective-C Runtime is not available!");
}

首先,我们创建一个包含我们要拦截的方法的新变量。

var hook = ObjC.classes.Hook["- hookMe:"];  

在Objective-C中 “-“ 是描述实例方法的语法。如果你遍历$methods特殊属性返回的所有方法,你将看到hookMe以这种方式展现出来。

Objective-C运行时将所有方法调用转换为objc_msgSend调用。objc_msgSend函数声明如下:

id objc_msgSend(id self, SEL op, args);

当我们拦截的方法被 Objective-C 运行时调用时,Frida通过拦截方法的参数提供对底层objc_msgSend函数的访问接口。

var receiver = new ObjC.Object(args[0]);  
send("Target class : " + receiver);  
send("Target superclass : " + receiver.$superClass);

var sel = ObjC.selectorAsString(args[1]);  
send("Hooked the target method : " + sel);

var obj = ObjC.Object(args[2]);  
send("Argument : " + obj.toString()); 

第一个参数是一个指针,指向接收消息的实例类。在我们的例子中它指向 Hook 。 您还可以通过Frida还提供的$ superClass特殊属性访问对象的超类。

objc_msgSend声明中的第二个参数是SEL,它本质上是一个包含调用方法名的CString(selector)。你可以使用Frida的selectorAsString JavaScript函数将其转换并将其发送回您的Python代码。

我们可以访问传递给args [2]中的hookMe方法的参数,并从中创建一个新的ObjC.Object。 Frida对对象的处理允许我们简单地调用toString以获得参数的值。

下面是我们的hook.py脚本的最终输出:

Conclusion

我希望这些信息对你有帮助。再次,你可以仔细阅读整个脚本。我强烈建议深入了解Frida的文档和frida-gum,以更熟悉Frida。

References

github.com/frida/frida-

编辑于 2016-11-28

文章被以下专栏收录