frida教程(一)

frida教程(一)

首先,frida是啥,github目录Awesome Frida这样介绍frida的:

Frida is Greasemonkey for native apps, or, put in more technical terms, it’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript into native apps that run on Windows, Mac, Linux, iOS and Android. Frida is an open source software.
frida是平台原生appGreasemonkey,说的专业一点,就是一种动态插桩工具,可以插入一些代码到原生app的内存空间去,(动态地监视和修改其行为),这些原生平台可以是WinMacLinuxAndroid或者iOS。而且frida还是开源的。

安装

  • 安装pc工具

建议使用python虚拟环境
venv — 创建虚拟环境 — Python 3.10.7 文档

python3 -m venv ./frida_venv

然后在虚拟环境中安装frida

cd ./frida_venv
source bin/activate
pip install frida
pip install frida-tools
  • 查看工具版本
firda --version

image

image

  • 将service push 到 机器中
    adb push .\frida-server-15.2.2-android-x86_64 /data/local/tmp

    adb shell # 进入安卓系统

系统内操作

su # root 模式进入
cd /data/local/tmp # 打开frida service 的目录
chmod 777 ./frida-server-15.2.2-android-x86_64 # 添加权限
./frida-server-15.2.2-android-x86_64 # 启动服务

pc 端验证服务是否启动成功

frida-ps -U

成功后会显示所有进程
image

IDE 环境搭建

工具:vscode
API提示:
可以在package.json中安装"@types/frida-gum": "^18.1.0",,或者可以直接在官方的demo上进行修改
官方demo:
oleavr/frida-agent-example: Example Frida agent written in TypeScript (github.com)
然后在控制台中输入npm install 就会自动安装Frida 开发工具包

Hello world

api 脚本:
JavaScript API | Frida • A world-class dynamic instrumentation framework

创建一个ts脚本
helloworld.ts

function hello_world(){

    log("hello world")

}


// setImmediate(hello_world)
setTimeout(hello_world, 1000)

setImmediate :
在Frida 的JavaScript线程上循环调用hello_world这个方法
setTimeout
1s后,在Frida 的JavaScript线程上调用hello_world这个方法

执行脚本:

frida -U -l .\helloworld.ts 应用报名

在这里,我们使用的attch方式启动脚本

控制台输出:
Pasted image 20220909221557

Hook JAVA方法

JavaScript API | Frida • A world-class dynamic instrumentation framework

进入JVM环境

打印所有加载的类

function showAllLoadedClass() {

    Java.perform(function () {

        console.log("附加到JVM成功");

        Java.enumerateLoadedClasses({
            onMatch: function (_className) {
            // 列出所有加载的类
                console.log("[*] found instance of '" + _className + "'");
            },

            onComplete: function () {
// 方法执行完成
                console.log("[*] class enuemration complete");
            }
        });
    });

}

Java.perform:
让当前线程进入附加到JVM中,

Java.enumerateLoadedClasses:
使用Frida的enumerateLoadedClasses方法,枚举当前所有加载的类

控制台输出:
Pasted image 20220909222300

Hook方法

function hookResume() {
    Java.perform(() => {
   // 查找所有的activity类
        const Activity = Java.use('android.app.Activity');
        // 查找Exception类
        const Exception = Java.use('java.lang.Exception');

// 当Activity 执行onResume方法时,进行回调
        Activity.onResume.implementation = function () {
        // new 一个Exception 对象,并抛出异常
            throw Exception.$new('Oh noes!');
        };
   
   // 有参数的情况
var fm = Java.use('androidx.fragment.app.Fragment')
fm.onCreateView.implementation = funcation(inflater: any, container:any, savedInstanceState: any) {
//在这里先得到运行的结果,因为我们要输出这个函数的结果                    
          var res = this.onCreateView(inflater, container, savedInstanceState);
         
// 将结果返回
return res;
}

    });
}

Java.use : 查找实例

控制台输出:
每当Activity执行onResume方法后就会抛出异常
Pasted image 20220909223925

获取对象

利用 Java.choose 来寻找堆上实例化的对象。

function getObject() {

    Java.perform(()=>{
        Java.choose("android.view.View", {
            onMatch: function (instance) {
                log(instance.toString())
            },
            onComplete: function () { console.log("完成"); }
        });
    })
}

控制台输出:
可以在控制台看到View的信息
Pasted image 20220909230753

使用对象

function useJavaFun(){
Java.perform(()=>{
var body2 = Java.use('java.util.HashMap').$new();
body2.put("build", "8078");
console.log("myfunc result: " + body2.get('build'));
})
}

控制台输出:
Pasted image 20220912154918

获取成员变量

var d = this._d;//获取成员属性d  
console.log("old d:"+d.value);//获取成员属性的值
this._d.value = null;//置空

通过反射获取所有成员变量

var fields = Java.cast(this.getClass(),Java.use('java.lang.Class')).getDeclaredFields();  
//console.log(fields);
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
field.setAccessible(true);
var name = field.getName();
var value =field.get(this)

获取一个就把getDeclaredFields() 改成 getDeclaredField(‘FieldName’);
同上。记得开启强制读取以及是否为空。否则容易报错碍眼。

作者

AriaLyy

发布于

2023-01-03

许可协议

CC BY-NC-SA 4.0

评论