Frida简单入门

admin 101 0

为什么要用Frida

Frida是逆向的一个基本工具, 具体原理不多介绍, 参看文章: www.jianshu.com/p/018498c65…


我们利用一些hook工具, 比如说Xposed, 来调用or查看其它app的一些实现, 但是比较烦人的是, Xposed每修改安装一次, 手机就需要重启一次, 这显然是不行的. Frida的优势就在于不用重启, 就可以完成调用.

配置

配置指导链接 www.jianshu.com/p/018498c65… 配置前请使用python3.7, 并将npm和node升级到最新版本, 否则安装的时候会出错

pip install frida 
pip install frida-tools 
npm install frida

然后到 github.com/frida/frida… 中下载对应平台的服务端, 解压

adb push frida-server-12.5.7-android-x86 /data/local/tmp/ 
adb shell 
cd  /data/local/tmp/ 
chmod 777 frida-server-12.5.7-android-x86 
./frida-server-12.5.7-android-x86

同时要在电脑上完成adb命令的转发端口

adb forward tcp:27042 tcp:27042

要注意,如果手机装了Magisk,是需要关掉MagiskHide才可以使用。

hook示例

一个程序如下:

#!/usr/bin/env python
# encoding: utf-8
import frida
import sys


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


if __name__ == '__main__':
    print("this is main")
    jscode = """
        if(Java.available){
            Java.perform(function(){
                var homeProfileFragmentClazz = Java.use("com.plbear.hookdemo.Utils");
                var mainActivity = homeProfileFragmentClazz.$new();
                var result = mainActivity.cal(3,3);
                mainActivity.$dispose();
                send(result)
            });
        } 
    """
    # 查找USB设备并附加到目标进程
    session = frida.get_usb_device().attach('com.plbear.hookdemo')
    # 在目标进程里创建脚本
    script = session.create_script(jscode)
    # 注册消息回调
    script.on('message', on_message)
    print('[*] Start attach')
    # 加载创建好的javascript脚本
    script.load()
    # 读取系统输入
    sys.stdin.read()

主要改变的是, js代码部分. 这里js中会经常用的接口如下

  • Java.use(className) 获取类的JavaScript wrapper(即包装Java类)

  • $new 调用构造器

  • $dispose() 清除实例

  • Java.choose(className,classBack) 枚举Java堆中存活的实例

  • $init 实例的构造方法 具体其他API 请参考完整的API文档 frida.re/docs/javasc…

下面给出部分示例, 来演示下不同的调用

调用Activity中的方法(私有方法也可以调用到, 方法一样)

Android App实现

package com.plbear.hookdemo

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    private fun cal(a: Int, b: Int): Int {
        return a + b
    }

    override fun onResume() {
        super.onResume()
        val v = findViewById<TextView>(R.id.tv)
        v.text = cal(1, 2).toString()
    }
}

主动调用Activity的cal方法

if(Java.available){
    Java.perform(function(){
        var homeProfileFragmentClazz = Java.use("com.plbear.hookdemo.MainActivity");
        var looperClazz = Java.use("android.os.Looper");
        looperClazz.prepare(); // 这里注意, 需要掉调用下这个, 否则没有办法创建一个新的Activity示例
        var mainActivity = homeProfileFragmentClazz.$new();
        var result = mainActivity.cal(3,3);
        send(result)
    });
}

hook cal方法, 每次系统调用cal方法, 就可以看到结果

if(Java.available){
    Java.perform(function(){
        var homeProfileFragment = Java.use("com.plbear.hookdemo.MainActivity");
        homeProfileFragment.cal.overload("int","int").implementation=function(a,b){
            console.log("[javascript] isExcellent be called.");
            send("isExcellent be called.");
            send(a);
            send(b);
            return this.cal(75,1); // 修改系统调用的结果, 当然这个地方可以用a,b, 只是打印下日志
        }
    });
}

静态方法的调用

静态方法其实差不多 app 代码

package com.plbear.hookdemo;

public class UtilsV2 {
    public static int cal(int i, int j) {
        return i + j;
    }
}

hook代码

if(Java.available){
    Java.perform(function(){
        var homeProfileFragmentClazz = Java.use("com.plbear.hookdemo.UtilsV2");
        var result = homeProfileFragmentClazz.cal(3,3);
        send(result)
    });
}


ok, 到这里就完成了简单的入门, 基本上可以满足日常需要. 更高级的用法还是要参看frida的官方API





标签: 安卓 逆向

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~