导语:Frida是一个动态的代码工具包,它是一款基于python + javascript 的hook与调试框架,相比xposed和substrace cydia更加便捷,可以向Windows,Mac,Linux,iOS和Android上的app注入javascript代码片段,并完全访问程序的内存。

modifying-the-return-value-790x435.png

Frida——移动应用程序进行安全分析的主要工具,即使你从未使用过Frida,读完这篇文章,你也将对它有充分的了解。

Frida介绍

Frida是一个动态的代码工具包,它是一款基于python + javascript 的hook与调试框架,相比xposed和substrace cydia更加便捷,可以向Windows,Mac,Linux,iOS和Android上的app注入javascript代码片段,并完全访问程序的内存。

根据你使用的目的,Frida的一些使用场景如下:

1.hook特定函数并更改返回值,

2.分析特定协议,并迅速探测流量

3.根据你的需求,可以对应用程序进行适当地调试

4.从iOS应用程序中提取dumping类和类方法信息

……

总之 Frida的应用范围是非常的广泛,功能也非常的强大,是建立自己的安全或分析工具的首选。目前已经有几种基于Frida的安全分析工具,包括Needle和AppMon。

Needle是一个开源的模块化框架,主要简化iOS应用程序安全评估过程,并作为一个中心点。鉴于其模块化方法,Needle很容易扩展新模块,可以以Python脚本的形式加入。

AppMon可以通过二进制指令获取app程序运行记录,并显示调用函数和相关参数。其次,还包括了一系列app事件监控和行为修改脚本,并能通过web接口显示和操作。

多平台动态框架环境Frida之所以如此的能对安全检测如此有用,就是因为它能够在非越狱的设备上运行。 Frida提供了一个叫做“FridaGadget.dylib”的动态库,可以用来在未越狱设备上为应用程序插入FridaGadget.dylib。你可以使用Swizzler2等工具来修改应用程序以在应用程序中添加FridaGadget.dylib。

添加FridaGadget.dylib后,你就可以获取开发人员配置的文件和证书,配置文件是由苹果签名的、将一个或多个设备上的代码签名证书列入白名单的plist文件。换言之,这是苹果明确允许你的应用程序在某些上下文中运行,比如在选定设备的调试模式下。配置文件还列出了授予你的应用程序的权限。

设置Frida

在iOS应用程序中设置Frida是非常简单的,首先就是在你的iOS设备上安装Frida服务器,步骤如下。

1.在你的iOS设备上打开Cydia应用程序,

2.添加一个URL,URL为https://build.frida.re

1494308477956961.png

3.打开Source或搜索Frida,然后单击Modify,最后单击Install。

1494308694434033.png

同时,你还可以使用Python绑定来完成更复杂的任务,可以使用pip install frida来完成对Python的绑定。

使用Frida连接到iOS进程

Frida现在已经设置完成,可以开始使用了。本文利用了iOS安全专家Prateek Gianchandani的Damn Vulnerable iOS Application(DVIA)方法,具体的原理请点击此处了解。

接下来,我们将分析DVIA是如何对越狱环境进行检测的,如下图所示,该设备已经越狱了。

1494308619330804.png

我们先查看一下这个越狱设备上的所有正在运行的进程列表,

frida-ps –U

1494308765884172.png

从上图可以看出,我们现在已经查到了该iOS设备上运行的所有进程的列表。

现在就可以试着利用一个frida –U process-name把frida加载到其中任意一个进程中了,如下图所示,现在我们就可以在frida控制台中,访问所有目标进程的属性,内存内容和相关功能。

1494308829717610.png

现在,我们即可以在Frida的shell中工作,并与iOS设备上进程进行交互,也可以编写自己的JavaScript来获取我们想要的数据。

dump出class文件并method出信息

我们可以利用此操作来确定利用DVIA越狱时,哪个ViewController和function负责验证iOS设备是否越狱。

ViewController是iOS应用程序中重要的部分,是应用程序数据和视图之间的重要桥梁,ViewController管理应用中的众多视图。 iOS的SDK中提供很多原生ViewController,以支持标准的用户界面,例如表视图控制器(UITableViewController)、导航控制器(UINavigationController)、标签栏控制器(UITabbarController)和iPad专有的UISplitViewController等。

先来写一个基本的Frida脚本来dump目标应用程序中存在的所有各种class文件和method信息。此时,我们就可以开始寻找与越狱相关的任何内容了,然后利用Frida绕过越狱检测,如下图所示,就是整个过程的示意图。

1494308855212421.png

用DVIA方法查找Frida可以绕过哪些越狱检测

我们先来看看应用程序中的所有class文件。

for (var className in ObjC.classes)
    {
        if (ObjC.classes.hasOwnProperty(className))
        {
            console.log(className);
        }
}

一旦运行以上这些指令, Frida就会附加到目标进程,一旦加载完成,它将在目标进程中显示出许多class文件。如下图所示,我们可以在iOS设备上,利用Frida管理JavaScript,

1494308942194267.png

当我们使用grep命令来运行上述越狱命令时,我们会看到一个JailbreakDetectionVC的class文件,如下图所示,我们就是用Frida来识别iOS应用程序的目标class文件。

1494308951688327.png

用DVIA进行越狱检测的方法

我们需要使用ObjC.classes.class-name.$methods才能找到进行越狱检测的方法。本文中,我们只介绍查找我们的目标class文件的方法,即使用JailbreakDetectionVC。

console.log("[*] Started: Find All Methods of a Specific Class");
if (ObjC.available)
{
    try
    {
        var className = "JailbreakDetectionVC";
        var methods = eval('ObjC.classes.' + className + '.$methods');
        for (var i = 0; i < methods.length; i++)
        {
            try
            {
                console.log("[-] "+methods[i]);
            }
            catch(err)
            {
                console.log("[!] Exception1: " + err.message);
            }
        }
    }
    catch(err)
    {
        console.log("[!] Exception2: " + err.message);
    }
}
else
{
    console.log("Objective-C Runtime is not available!");
}
console.log("[*] Completed: Find All Methods of a Specific Class");

运行以上的命令后,如下所示,同时利用Jailbreak,Jailbroken 和Detection的grep,来进行精确字符串 查找。

1494309029772322.png

如上图所示,我们发现Jailbroken,jailbreakTest1Tapped:和jailbreakTest2Tapped:含有我们要查找的目标。

其中isjailbroken看起来像是检测设备是否越狱,并最有可能发送返回值。

利用DVIA修改Frida越狱检测方法的返回值

让我们来看看Jailbroken会发送什么样的返回值。

console.log("[*] Started: Find All Methods of a Specific Class");
if (ObjC.available)
{
    try
    {
        var className = "JailbreakDetectionVC";
        var methods = eval('ObjC.classes.' + className + '.$methods');
        for (var i = 0; i < methods.length; i++)
        {
            try
            {
                console.log("[-] "+methods[i]);
            }
            catch(err)
            {
                console.log("[!] Exception1: " + err.message);
            }
        }
    }
    catch(err)
    {
        console.log("[!] Exception2: " + err.message);
    }
}
else
{
    console.log("Objective-C Runtime is not available!");
}
console.log("[*] Completed: Find All Methods of a Specific Class");

运行此命令后,请在iOS应用程序中选择Jailbreak Test 1按钮,这样我们就能在Frida控制台中看到显示的返回值。

1494309091194732.png

由于我们的设备此时已经越狱,所以它显示的返回值为0x1,这意味着函数返回为True。

接下来,我们将修改此返回值并修改该方法,以便以后在应用程序中选择Jailbreak Test 1按钮时,它将返回false或0x0。

可以通过添加一行代码来改变这个特定函数的返回值,如下图所示该代码行可以更改返回值并将其记录到Frida控制台。

newretval = ptr("0x0")
retval.replace(newretval)
console.log("t[-] New Return Value: " + newretval)

最后的代码如下,

if (ObjC.available)
{
    try
    {
        var className = "JailbreakDetectionVC";
        var funcName = "- isJailbroken";
        var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
        Interceptor.attach(hook.implementation, {
          onLeave: function(retval) {
            console.log("[*] Class Name: " + className);
            console.log("[*] Method Name: " + funcName);
            console.log("t[-] Type of return value: " + typeof retval);
            console.log("t[-] Original Return Value: " + retval);
            newretval = ptr("0x0")
            retval.replace(newretval)
            console.log("t[-] New Return Value: " + newretval)
          }
        });
    }
    catch(err)
    {
        console.log("[!] Exception2: " + err.message);
    }
}
else
{
    console.log("Objective-C Runtime is not available!");
}

一旦我们运行上面这些命令,就可以看到返回值已经被修改,如下图所示。

1494309161976149.png

如果现在再查看我们的iOS应用程序,则会发现该设备没有越狱,如下图所示。

1494309174972932.png

源链接

Hacking more

...