Frida学习04-RPC及其自动化
目录日期:Mar-3-2022
作者:狐狸大剑眼镜
书籍:安卓Frida逆向与抓包实战-陈佳林
3.1节中,曾介绍过Frida存在两种操作模式,其中第一种命令行模式在之前的章节中一直使用,在这一节中,将介绍一些关于RPC模式以及使用RPC完成自动化的相关知识。在Frida中,可以使用Python完成JavaScript脚本对进程的注入以及相应的Hook。
package com.example.myapplication;
import androidx.annotation.LongDef;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private String total = "hello";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("MainActivity","hollowed!");
while (true){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
fun(50,30);
Log.d("MainActivity.string", fun("LoWeRcAsE !!!!!!!!!!!!!"));
}
}
void fun(int x ,int y) {
Log.d("MainActivity", String.valueOf(x+y));
}
String fun(String x) {
return x.toLowerCase();
}
void secret(){
total += "secretFunc";
Log.d("MainActivity.secret", "secret: 999");
}
static void staticSecret(){
Log.d("MainActivity.Secret", "staticSecret: 777");
}
}
增加了一个字符串类型的实例变量total,同时每次调用secret()函数对字符串进行扩展。
这次的目的是获取total的值。
在主动调用时需要注意的是,Java中的变量也存在是否使用static
修饰的区别。在用Frida对Java中的变量进行处理时也要区分是否使用
static修饰:类变量,使用static修饰,可以直接通过类进行获取;实
例变量,不使用static修饰,和特定的对象绑定在一起。
function CallSecretFunc() {
Java.perform(function () {
//动态函数主动调用
Java.choose("com.example.myapplication.MainActivity", {
onMatch: function (instance) {
instance.secret()
},
onComplete: function () {
}
})
})
}
function getTotalValue() {
Java.perform(function () {
var MainActivity = Java.use("com.example.myapplication.MainActivity")
//动态函数主动调用
Java.choose("com.example.myapplication.MainActivity", {
onMatch: function (instance) {
console.log("total value = ", instance.total.value)
},
onComplete: function () {
console.log("search complate")
}
})
})
}
setImmediate(getTotalValue)
这是如果直接调用getTotalValue的值会报错,需要先执行CallSecretFunc()函数,调用所在动态函数。
在确认我们的函数都没有写错且功能达到预期后,接下来我们开始
RPC远程调用。将CallSecretFunc()函数和getTotalValue()函数导
出,使得外部可以进行调用,在JavaScript代码末尾加上RPC相关代
码:
rpc.exports = {
callsecretfunc: CallSecretFunc,
gettotalvalue: getTotalValue
};
部分代码实现的功能就是将CallSecretFunc()函数和
getTotalValue()函数分别导出为callsecretfunc和gettotalvalue。需
要注意的是,导出名不可以有大写字母或者下划线。接下来在外部就可
以调用这两个函数了
import frida
import sys
def on_message(message, data):
if message['type'] == 'send':
print("{*} {0}".format(message['payload']))
else:
print(message)
# 首先通过frida.get_usb_device()获取到USB设备句柄
device = frida.get_usb_device()
# device.attach()进程进行注入
process = device.attach('com.example.myapplication')
with open('javahook4.js') as f:
jscode = f.read()
# 使用create_script()函数加载了编写的JavaScript代码
script = process.create_script(jscode)
"""
使用script.on('message', on_message)注册了自己的消息对应的函
数,每当JavaScript想要输出时都会经过这里指定的on_message进行
"""
script.on('message', on_message)
script.load()
command = ''
while True:
"""
最重要的RPC调用代码,即通过script.exports访问所
有我们在JavaScript中定义的导出名,进而调用导出函数。这样就完成
了RPC远程调用,达到在主机上可以随意调用App代码的目的。
"""
command = input(
"\nEnter command:\n:Exit\n2:Call secret function\n3:Get Total value:\nchoice:")
if command == '1':
break
elif command == '2':
script.exports.callsecretfunc()
elif command == '3':
script.exports.gettotalvalue()
运行frida-server
运行python脚本,好像有点bug,js的这句注释掉//setImmediate(getTotalValue),先不获取Total值。