frida概观与初步使用

随笔

ARMv7(我的小米3/4)是32位的
linux命令 & 表示任务在后台执行。
python3\Scripts被自动加入路径
python3被自动加入路径

frida原理

Frida可以“将你自己的JavaScript代码片段或代码库注入到Windows,MACOS,Linux, iOS,Android和QNX 的本地应用中”。多平台可注非常强大,重点研究。

具体过程实现未看…之后记得看看源码

frida安装

只看官方:https://www.frida.re/docs/home/
前提:

  1. python 3
  2. ptyhon自带的pip

运行pip install frida即可

为了调试android需要下载frida-server对应android上的。adb push并777运行之

使用

frida的运行依靠py脚本,其核心用c写的,注入代码为js。
基本用法为编写python脚本实现输入,里面提供的一些工具也是py脚本+js代码注入写出的。因此可参考api写出自己的工具。

注入用js的api:https://www.frida.re/docs/javascript-api/
针对android多看它的java部分。https://www.frida.re/docs/javascript-api/#java

还有非常多功能,比如dump等

一般分析流程

  1. 反编译apk,分析代码寻找hook点。
  2. 编写js代码,调用类的方法或者替换。
  3. 在python中执行即可。

hook已知地址函数

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
# -*- coding: utf-8 -*-
#头文件
from __future__ import print_function
import frida
import sys
#附着于目标进程
session = frida.attach("hello.exe")
#在目标进程中创建脚本,脚本内容为hook某地址的函数,后面为进入函数前对参数的处理,send是往py脚本发送的消息
#ptr字串化数字
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
onEnter: function(args) {
args[0] = ptr("1337");
send(args[0].toInt32());
}
});
""" % int(sys.argv[1], 16))
#定义了一个函数用来接收send
def on_message(message, data):
print(message)
#注册函数用于接受
script.on('message', on_message)
script.load()
sys.stdin.read()

调用已知地址函数

1
2
3
4
5
6
7
8
9
10
11
12
13
# -*- coding: utf-8 -*-
import frida
import sys
session = frida.attach("hello.exe")
# 注入脚本字串,其创建了一个原生函数指针。并调用
script = session.create_script("""
var f = new NativeFunction(ptr("%s"), 'void', ['int']);
f(1911);
f(1911);
f(1911);
""" % int(sys.argv[1], 16))
script.load()

分配字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-
from __future__ import print_function
import frida
import sys
session = frida.attach("hi.exe")
#在对象内存中分配字串,并传入本地函数f中
script = session.create_script("""
var st = Memory.allocUtf8String("TESTMEPLZ!");
var f = new NativeFunction(ptr("%s"), 'int', ['pointer']);
// In NativeFunction param 2 is the return value type,
// and param 3 is an array of input types
f(st);
""" % int(sys.argv[1], 16))
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()

目标往py发送数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# -*- coding: utf-8 -*-
from __future__ import print_function
import frida
import sys
session = frida.attach("hello.exe")
#演示发送信息的脚本在目标中运行了
script = session.create_script("send(1337);")
# 结果为:{'type': 'send', 'payload': 1337} type为send 值为1337 message为字典
def on_message(message, data):
print(message)
# 您可以发送任何可串行化为JSON的JavaScript值
script.on('message', on_message)
script.load()
sys.stdin.read()

py与目标交互

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
38
39
40
41
42
43
44
45
46
# -*- coding: utf-8 -*-
from __future__ import print_function
import frida
import sys
session = frida.attach("hello.exe")
#注册接受函数 recv()方法本身是异步的(非阻塞的)。已注册的回调(onMessage)将只收到一条消息。要接收下一条消息,必须使用recv()重新注册回调。
script = session.create_script("""
recv('poke', function onMessage(pokeMessage) { send('pokeBack'); });
""")
def on_message(message, data):
print(message)
script.on('message', on_message)
#注入脚本启动
script.load()
#发送消息,向注入的脚本,指定type来判断是否接受
script.post({"type": "poke"})
script.post({"type": "poke"})
sys.stdin.read()
from __future__ import print_function
import frida
import sys
session = frida.attach("hello")
#让recv等待返回结果后再处理
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
onEnter: function(args) {
send(args[0].toString());
var op = recv('input', function(value) {
args[0] = ptr(value.payload);
});
op.wait();
}
});
""" % int(sys.argv[1], 16))
def on_message(message, data):
print(message)
#用的是字典取值
val = int(message['payload'], 16)
script.post({'type': 'input', 'payload': str(val * 2)})
script.on('message', on_message)
script.load()
sys.stdin.read()

目标为android时py脚本写法

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
38
39
40
# -*- coding: utf-8 -*-
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
#植入的是js脚本 写的是py脚本
jscode = """
Java.perform(function () {
// Function to hook is defined here
var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
// Whenever button is clicked
MainActivity.onClick.implementation = function (v) {
// Show a message to know that the function got called
send('onClick');
// Call the original onClick handler
this.onClick(v);
// Set our values after running the original onClick handler
this.m.value = 0;
this.n.value = 1;
this.cnt.value = 999;
// Log to the console that it's done, and we should have the flag!
console.log('Done:' + JSON.stringify(this.cnt));
};
});
"""
# get_usb_device()是获取usb设备的中的服务,直接attach是对本地的
process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

在hook了的函数中调用原函数

这样可以实现调用前后hook,但具体this与implementation执行法未知

1
2
3
4
5
6
7
8
Java.perform(function(){
var hook_Activity = Java.use('de.fraunhofer.sit.premiumapp.LauncherActivity');
hook_Activity.verifyClick.implementation= function (arg16) {
send("got called! before");
this.verifyClick(arg16);
send("got called! after");
};

所含快速脚本工具

Frida CLI

一个命令行窗口模式的交互工具
开始分析android的chrom:
frida -U -f com.android.chrome
即可通过交互分析

frida-ps

用于显示进程
frida-ps -U USB接口的设备

frida-trace

frida-trace是一个动态跟踪函数调用的工具。

1
2
3
4
5
6
7
8
# Trace recv* and send* APIs in Safari
$ frida-trace -i "recv*" -i "send*" Safari
# Trace ObjC method calls in Safari
$ frida-trace -m "-[NSView drawRect:]" Safari
# Launch SnapChat on your iPhone and trace crypto API calls
$ frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"

frida-trace -U -i open com.android.chrome
在当前目录生成handlers文件内含js脚本用于注入指定函数

frida-discover

frida-discover是一个用于发现程序内部函数的工具,可以使用frida-trace来追踪内部函数。