frida入门级详细讲解

frida入门级详细讲解

观文须知

由于文章在编辑时使用的markdown,但论坛禁止调用外部图床,为了方便编写,文章未提供图片,如果真的对frida感兴趣,可以根据文章内容对操作进行复现。

文章后半部分充斥着大量的java、python和javascript代码,可能会产生不良副作用,如有不适请快速关闭页面,因此产生的不良后果本人概不负责。

读万卷书,不如行万里路;行万里路,不如阅人无数。

环境准备

  • Android Studio(其他APP开发IDE也可以)
  • mumu模拟器(重点安利对象,无广告小清新、无广告小清新、无广告小清新,重要的事情说三遍,夜神、雷电、闪电等等其他模拟器也可以)
  • frida(笔者使用的是12.4.4版本,其他版本也可以)

Android Studio

这个没什么好说的,在官网下载安装即可。

mumu模拟器

这个更没什么好说的,在官方下载安装即可。

frida

客户端安装

笔者在这里使用的是Ubuntu for windows 10,直接使用pip install frida-tools

服务端安装

使用frida --version命令获取frida客户端的版本,在frida官方github下载相同版本的frida-server。

使用adb push frida-server /data/local/tmp/命令将frida-server文件push到模拟器的tmp文件夹,使用adb shell命令进入到模拟器的shell,再shell中使用cd /data/local/tmp/命令切换至tmp文件夹,使用chmod 755 frida-server命令对frida-server文件的权限进行修改。

frida连接

在服务端执行./frida-server命令启动服务。
在客户端执行frida-ps -U命令可以看到进程列表。

frida的使用

测试APP准备

这里表弟随便写了一个APP,这个APP的功能是计算两个数的和,具体代码如下:

package com.test.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private Button btButton;
    private EditText et1,et2;
    private int num1,num2,num3;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btButton = (Button)findViewById(R.id.button);
        tv = (TextView)findViewById(R.id.textView6);

        btButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                et1 = (EditText)findViewById(R.id.editText2);
                et2 = (EditText)findViewById(R.id.editText3);
                num1 = Integer.parseInt(et1.getText().toString());
                num2 = Integer.parseInt(et2.getText().toString());
                num3 = testbug(num1,num2);
                tv.setText(String.valueOf(num3));
            }

        });
    }
     public  int testbug(int testnum1,int testnum2) {
        return testnum1+testnum2;
     }
}

修改方法

目标

通过hook修改方法为获取两个数的差。

loaderHook.py代码

import time
import frida

device = frida.get_usb_device()
pid = device.spawn(["com.test.test"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("hook.js") as f:
    script = session.create_script(f.read())
script.load()
input()

hook.js代码

Java.perform(function() {
    var my_class = Java.use("com.test.test.MainActivity");
    my_class.testbug.implementation = function(num1,num2) {
        console.log("num1:" + num1 + " num2:" + num2);
        var ret_value = test(num1,num2);
        return ret_value;
    }
    function test(num1,num2) {
        return num1-num2;
    }
})

方法执行前修改参数

目标

通过hook在计算两数和之前对数值进行修改。

loaderHook.py代码

import time
import frida

device = frida.get_usb_device()
pid = device.spawn(["com.test.test"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("hook.js") as f:
    script = session.create_script(f.read())
script.load()
input()

hook.js代码

Java.perform(function() {
    var my_class = Java.use("com.test.test.MainActivity");
    my_class.testbug.implementation = function(num1,num2) {
        console.log("num1:" + num1 + " num2:" + num2);
        num1=8;
        num2=10;
        var ret_value = this.testbug(num1,num2);
        return ret_value;
    }
})

方法执行后修改结果

目标

通过hook在计算两数和之后对结果进行修改。

loaderHook.py代码

import time
import frida

device = frida.get_usb_device()
pid = device.spawn(["com.test.test"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("hook.js") as f:
    script = session.create_script(f.read())
script.load()
input()

hook.js代码

Java.perform(function() {
    var my_class = Java.use("com.test.test.MainActivity");
    my_class.testbug.implementation = function(num1,num2) {
        console.log("num1:" + num1 + " num2:" + num2);
        var ret_value = this.testbug(num1,num2);
        ret_value = 86;
        return ret_value;
    }
})

调用APP内部的方法

目标

通过call直接调用APP内部编写的计算两数和的方法。

loaderCall.py代码

import time
import frida

device = frida.get_usb_device()
pid = device.spawn(["com.test.test"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("call.js") as f:
    script = session.create_script(f.read())
script.load()
script.exports.callhidefunction(88,66)

call.js代码

function callHideFun(num1,num2) {
    Java.perform(function() {
        Java.choose("com.test.test.MainActivity", {
            onMatch: function(hideFun) {
                console.log(hideFun.testbug(num1,num2));
            },
            onComplete: function() {
            }
        });
    });
}
rpc.exports = {
    callhidefunction : callHideFun
};

问题汇总

mumu模拟器adb连接不上

启动mumu模拟器后,使用adb devices命令查看连接设备发现没有设备,这个时候需要使用adb connect 127.0.0.1:7555进行连接,再执行adb devices命令即可看到mumu模拟器。

./frida-server: not executable: 32-bit ELF file

执行./frida-server命令时可能会报./frida-server: not executable: 32-bit ELF file错误,引起这个的原因是因为下载的frida服务端与模拟器的架构不符。

瞎扯淡

不知道是由于两耳不闻窗外事,一心只读圣贤书,还是因为真的风平浪静,一个季度过去了,貌似也没有发生什么大的事件。

想找一群有意思的人,一起做一些有意思的事,无关金钱与利益,只想追寻心和灵魂。

诗和远方最后都成为了自律和坚持。

大家有什么关于技术上的想法或者思路,哪怕是一些有意思的事,都可以告诉我,我可以和你一起通过努力去实现它或让距离变得更近。