4,frida-rpc远程调用

简述

获取对象的方法

frida获取对象有2中, 1种是从内存中获取(程序自己创建的), 还有一种就是我们自己去new对象, 当然推荐第一种, 因为我们手动new对象只是调用其构造方法,如果是复杂的构造方法, 我们获取器参数也就特别复杂, 而且有些成员属性在程序的运行中被改变了, 这样会导致错误的结果。

从内存中获取对象api

var result = null;
Java.choose("com.xx.xx.xx.xx",{ // xx代表类名
	// 匹配到该对象要执行的函数
    onMatch: function(instance){
        result = instance.function();
    },
    // 搜索完毕后要执行的函数
    onComplete: function(){

    }
});

简单测试手动调用

https://www.52pojie.cn/thread-1128884-1-1.html

我们以上面frida hookjava的实例, 我们要实现主动调用testFrida方法

  • 新建一个testFrida.js, 写入如下代码
function call_fridajava(){
    var result = null;
    Java.perform(function(){
        Java.choose("com.example.testfrida.MainActivity",{ // xx代表类名
            // 匹配到该对象要执行的函数
            onMatch: function(instance){
                result = instance.testFrida();
            },
            // 搜索完毕后要执行的函数
            onComplete: function(){

            }
        });
    }); 
    return result;   
}

手动调用

# 1, 手机端frida-server
# 2, adb连接
# 3, 端口转发 27042, 27043
# 4, 运行下面的命令, 注入js
frida -U testfrida -l d:\app\frida\testFrida.js
# call_fridajava() // 调用方法
image-20210807104009247

测试rpc调用

设置导出函数, 上面的代码下面加入 rpc.exports

注意: 导出函数的key必须是消息callfridajava --> 如果你写成callFridaJava 会导致方法找不到

function call_fridajava(){
    var result = null;
    Java.perform(function(){
        Java.choose("com.example.testfrida.MainActivity",{ // xx代表类名
            // 匹配到该对象要执行的函数
            onMatch: function(instance){
                result = instance.testFrida();
            },
            // 搜索完毕后要执行的函数
            onComplete: function(){

            }
        });
    }); 
    
    console.log("--------------------");
    console.log(result);
    return result;   
}

rpc.exports = {
	callfridajava: call_fridajava
}

添加主函数(socket连接, 最好使用http, 方便入门)

# -*- coding: utf-8 -*-
import codecs
import frida
import socket

if __name__ == '__main__':
    #附加到目标进程
    # session = frida.get_usb_device().attach(u'testfrida')
    process = frida.get_remote_device().attach('testfrida')
    
       #读取JS脚本 如果找不到就写全路径
    with codecs.open('./testFrida.js', 'r', 'utf-8') as f:
        source = f.read()
    
    script = process.create_script(source)
    script.load()
    
    #调用导出的函数
    rpc = script.exports
    rpc.callfridajava()

    # 构建web服务器 start
    HOST, PORT = '', 8888

    listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listen_socket.bind((HOST, PORT))
    listen_socket.listen(1)
    print('Serving HTTP on port %s ...' % PORT)
    while True:
        client_connection, client_address = listen_socket.accept()
        request = client_connection.recv(1024)
        print(request.decode("utf-8"))

        http_response = rpc.callfridajava()
        client_connection.sendall(http_response.encode("utf-8"))
        client_connection.close()
    # 构建web服务器 end
    
    process.detach()

运行主函数,打开socket客户端连接工具

https://www.onlinedown.net/soft/55038.htm socket工具下载

python ./testFridaMain.py
image-20210807114403174
image-20210807114526282

由于是socket, 并且代码中发送一次, 就会断一次, 因此我们改成http的

rpchttp服务调用

我们先学习这个简单的web框架

https://www.jianshu.com/p/6452596c4edb

并安装好环境

# -*- coding: utf-8 -*-
import codecs
import frida
import socket
from flask import Flask

app = Flask(__name__)
 
@app.route('/hi')
def hi():
    return 'Hello World'

@app.route('/frida')
def callfrida():
    return rpc.callfridajava()

if __name__ == '__main__':
    #附加到目标进程
    # session = frida.get_usb_device().attach(u'testfrida')
    print(frida.get_remote_device)
    process = frida.get_remote_device().attach('testfrida')
    
       #读取JS脚本 如果找不到就写全路径
    with codecs.open('C:/Users/xdb/Desktop/testFrida.js', 'r', 'utf-8') as f:
        source = f.read()
    
    script = process.create_script(source)
    script.load()
    
    #调用导出的函数
    rpc = script.exports
    rpc.callfridajava()

    # 构建flask服务器 start
    app.run(host='127.0.0.1',port=5000)
    # 构建web服务器 end
    
    process.detach()

    
image-20210807120416768

如果有多个方法, 以及参数,我们可以通过扩展Flask的请求,获取请求参数, 然后参入到rpc的方法中。