Frida 通过 C 语言将 QuickJS 注入到目标进程中,获取完整的内存操作权限,达到在程序运行时实时地插入额外代码和数据的目的。官方将调用代码封装为 python 库,当然你也可以直接通过其他的语言调用 Frida 中的 C 语言代码进行操作。
Frida安装和启动
pip install frida-tools
C:\Users\当前用户名
,再重新使用命令安装。frida --version
来查看安装的版本,确认是否安装成功。adb push
命令将文件推送到手机端,建议放置在/data/local/tmp
文件夹中,并修改该文件的权限为 755,以便之后进行启动。/data/local/tmp
文件夹内,并将文件命名为frida-server
。adb shell
命令连接手机,运行/data/local/tmp/frida-server &
,将 Frida-server 放在系统后台自动运行。frida-ps -U
,结果如下展示手机中的进程信息,说明环境已经准备完毕。 PID Name
----- --------------------------------------------------
1313 adbd
12621 android.process.acore
18037 android.process.media
14455 com.android.defcontainer
11656 com.android.deskclock
...
目标应用介绍
package com.example.target_frida;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView winCountView;
TextView battleInfoTextView;
int winCount = 0;
@SuppressLint("SetTextI18n")
@Override
public void onClick(View view) {
if (winCount > 100) {
return;
}
if (view.getId() == R.id.tvButtonBlack) {
if (!getCPUResult()) {
winCount++;
winCountView.setText(winCount + "");
battleInfoTextView.setText("Right!");
} else {
winCount = 0;
winCountView.setText(winCount + "");
battleInfoTextView.setText("Wrong! Clean All!");
}
} else if (view.getId() == R.id.tvButtonWhite) {
if (getCPUResult()) {
winCount++;
winCountView.setText(winCount + "");
battleInfoTextView.setText("Right!");
} else {
winCount = 0;
winCountView.setText(winCount + "");
battleInfoTextView.setText("Wrong! Clean All!");
}
}
if (winCount >= 100) {
battleInfoTextView.setText("Win 100 times!!!");
}
}
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
winCountView = findViewById(R.id.winCount);
winCountView.setText(winCount + "");
battleInfoTextView = findViewById(R.id.battleInfo);
battleInfoTextView.setText("猜黑白!!!");
Button buttonBlack = (Button) findViewById(R.id.tvButtonBlack);
Button buttonWhite = (Button) findViewById(R.id.tvButtonWhite);
buttonBlack.setOnClickListener(this);
buttonWhite.setOnClickListener(this);
}
public boolean getCPUResult() {
//true为白,false为黑
return Math.random() > 0.5;
}
}
Hook 需求分析
winCount
,将连赢记录改成 99,这样只需要再赢一次就可以获得胜利;还有一种是通过修改getCPUResult
方法的返回值,让其固定返回一种可能性,这样只需要选择对应的颜色就可以连续获胜。接下来通过实现第一个方案,看看使用 Frida 如何达到想要的效果。import time
import frida, sys
date_str = time.strftime('%m-%d %H:%M:%S')
def on_message(message, data):
if message['type'] == 'send':
print(f"[{date_str}] {message['payload']}")
else:
print(f"[{date_str}] {message}")
def run_all():
# Java.perform方法:当 js 附加到目标的进程中时被执行,运行其中定义的函数
# Java.choose方法:通过完整类名,获取它的实例,从而对实例中的数据进行修改
# 通过 key:value 结构定义了两个函数:
# onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例
# onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作
jscode = """
Java.perform(function () {
Java.choose("com.example.target_frida.MainActivity",{
onMatch:function(instance){
console.log("winCount value is "+instance.winCount.value);
instance.winCount.value=99;
console.log("winCount value is "+instance.winCount.value);
},
onComplete:function(){
console.log("Complete!!!")
}
});
});
"""
# attach目标App进程
target_app = 'com.example.target_frida'
process = frida.get_usb_device().attach(target_app)
# 将JS代码注入进程,并附加监听方法,用来获取返回的日志信息
script = process.create_script(jscode)
script.on('message', on_message)
# 打印起始日志
print(f'[{date_str}] Start Frida on {target_app}')
# 加载注入的JS代码逻辑
script.load()
# 使用系统输入语句阻止函数运行完毕自动退出
sys.stdin.read()
if __name__ == '__main__':
run_all()
Java.choose
函数获取com.example.target_frida.MainActivity
类的实例。在获取到实例时,首先使用console.log
语句将当前实例中的 winCount 变量值(使用 winCount.value)打印到日志中,之后直接通过赋值语句把变量值改为 99,再次输出日志确认修改无误,修改逻辑就完成了。[04-15 18:19:57] Start Frida on com.example.target_frida
winCount value is 0
winCount value is 99
Complete!!!
第二个方案以及其他更多的可能性,就留给读者自行探索,在这里送上 Frida 官方 JavaScript API 链接:JavaScript API | Frida • A world-class dynamic instrumentation framework ,可以通过这个链接找到你所需要的 JS 函数。
通过示例可以看到 Frida 实现 Hook 功能的强大能力,它可以定位到类的实例,并且对实例中的数据进行直接的修改,达到场景构建的目的。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。