栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Android之Frida框架完全使用指南

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android之Frida框架完全使用指南

文章目录
    • Frida简介
    • 环境搭建
      • python安装与虚拟环境配置
      • Frida安装
      • 配置代码提示
      • Server环境配置
    • Frida Hook
      • 执行HOOK
      • Java层hook
        • Hook普通方法
        • 重载方法
        • 构造方法
        • 修改类字段
        • hook内部类和匿名类
        • 枚举所有类和方法
        • hook动态加载的DexClass
      • Native层hook
        • hook有导出函数
        • hook无导出函数

Frida简介

Frida是一款基于Python + Javascript 的hook框架,本质是一种动态插桩技术。可以用于Android、Windows、iOS等各大平台,其执行脚本基于Python或者Node.js写成,而注入代码用Javascript写成,所以有必要了解一些这些语言的语法。本文主要讲述了Android上Frida框架的使用。

环境搭建 python安装与虚拟环境配置

使用Frida需要Python 3环境,首先需要安装python3.7版本,安装完成之后再安装虚拟环境。

安装virtualenvwrapper

pip install virtualenvwrapper-win -i https://pypi.doubanio.com/simple

配置虚拟环境变量->WORKON_HOME

将WORKON_HOME添加到用户变量,可以修改虚拟环境的存储路径

创建虚拟环境

mkvirtualenv --python=C:Python37python.exe FridaHook

进入虚拟环境

workon FridaHook

建立好虚拟环境以后,所有的修改都是针对虚拟环境

Frida安装
pip install frida -i https://pypi.mirrors.ustc.edu.cn/simple/ 
pip install frida-tools -i https://pypi.mirrors.ustc.edu.cn/simple/ 

使用pip命令可以直接安装frida,但是速度会比较慢。坐下来喝杯茶慢慢等就行了。

(FridaHook) C:Users87321Desktop>frida --version
15.1.4

(FridaHook) C:Users87321Desktop>

安装完成之后可以查看版本表示安装成功

配置代码提示

安装vscode,配置vscode语言中文简体。打开"vscode" , 按快捷键"Ctrl+Shift+P",在顶部搜索框中输入"configure language"

安装nodejs,新建一个文件夹,在目录下执行下面这条命令

npm i @types/frida-gum

执行完成之后在文件夹中新建js脚本

此时就会出现相关的代码提示

Server环境配置
https://github.com/frida/frida/releases

下载Frida的Server端->frida-server-15.1.4-android-arm64.xz,下载完成之后解压。然后push到手机的data/local/tmp目录下,和IDA的动态调试有点类似

adb push .frida-server-15.1.4-android-arm64 /data/local/tmp/frida

然后修改权限

# chmod 777 frida

直接运行frida服务

./frida

开启端口转发

adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043

PC端输入

frida-ps -U

如果能显示进程列表说明环境搭建完成

注意这条命令需要在python虚拟环境中执行

安装低版本Frida

由于Frida的稳定性较差,我用Android6.0的系统安装Frida最新版本出现了问题。解决方案是安装低版本的Frida,用下面的命令即可。

pip install frida==12.8.0
pip install frida-tools==5.3.0
pip install objection==1.8.4
Frida Hook 执行HOOK

首先来说一下如何执行hook代码

  1. 启动时hook,CMD输入
frida -U -f com.test.apk -l test.js --no-pause

将 com.test.apk 换成你手机里安装好的任意apk包名

  1. 启动apk后 hook
frida -U -f com.test.apk --no-pause
%load test.js

看到这个提示说明hook成功

Java层hook

Frida的Java层重要函数

  1. 使用java平台—>Java.perform(function () {}
  2. 获取Java类 —>Java.use(className)
  3. 当我们获取到Java类之后,我们直接通过 ..implementations =function() {}的方式来hook wrapper类的method方法,不管是实例方法还是静态方法都可以
Hook普通方法

被hook的代码如下;

package com.example.hookdemo01;


public class Student {
    static public int Add(int a,int b)
    {
        return a+b;
    }

}

接着编写Hook代码

function main()
{
     //使用java平台
     Java.perform(
        function() {
            //获取java类
            var student=Java.use("com.example.hookdemo01.Student");
            //hook Add方法(重写Add方法) 
            student.Add.implementation=function(a,b)
            {
                //修改参数
                a=123;
                b=456;
                //调用原来的函数
                var res = this.Add(a,b);
                //输出结果
                console.log(a,b,res);
                return res;
            }
        }

     );
    
}

setImmediate(main)

实际效果:

接着我们执行hook,可以看到Frida成功打印出了我们修改后的参数

重载方法

修改一下目标代码,新增三个重载函数,接着编写hook代码

//hook重载方法
function hookTest1()
{
    //获取java类
    var student=Java.use("com.example.hookdemo01.Student");
    //hook test
    student.test.overload('int').implementation=function(a)
    {
        //修改参数
        a=123;
        //调用原来的函数 
        var res = this.test(a);
       
        //输出结果
        console.log(a,res);
        return res;
    }
}

hook重载函数和hook普通方法有所区别,需要在方法名后调用overload()函数,并在括号内传入需要hook的重载函数的参数。

实际效果:

执行hook,同样可以对函数参数进行修改。

//hook所有重载函数
function hookTest2()
{
    //获取java类
    var student=Java.use("com.example.hookdemo01.Student");
    //重载方法的个数
    var overlength=student.test.overloads.length;
    //循环hook所有重载方法
    for(var i=0;i 

同时,我们也可以用overloads来对所有的重载函数进行hook,每一个重载函数只需要用arguments.length来进行区分即可。

构造方法

再次修改代码,添加一个构造函数,接着编写hook代码

//hook构造函数
function hookTest3()
{
    //获取java类
    var student=Java.use("com.example.hookdemo01.Student");
    
    student.$init.implementation=function(name,age)
    {
        //输出参数
        console.log(name,age);

        //调用原函数
        this.$init(name,age);

        //调用构造函数
        //student.$new("guishou",888);

    }
      
}

hook构造函数需要用$init来代替函数名,另外,可以用$new方法来调用构造函数,并且获取一个新的对象

修改类字段

修改代码,添加一个静态字段和一个私有字段,接着编写Hook代码

//修改类字段
function hookTest4()
{
    //获取java类
    var student=Java.use("com.example.hookdemo01.Student");
     //修改静态字段
    student.nickname.value="GuiShouFlags";
    console.log(student.nickname.value);
    
    //修改非静态字段
    Java.choose("com.example.hookdemo01.Student",{
        //每遍历一个对象都会调用onMatch
        onMatch:function(obj)
        {
            //修改每个对象的字段
            obj.number.value=999;
            console.log(obj.number.value);
            
            //字段名和函数名相同需要加下划线
            //obj._number.value=999;
        },
        //遍历完成后调用onComplete
        onComplete:function()
        {

        }
    }); 
      
}

修改静态字段的方法较为简单,直接用类名点出字段名再加上value值即可直接修改,修改非静态字段需要调用choose函数,传入类名和回调函数进行修改

修改后效果如图

hook内部类和匿名类

修改目标代码

添加一个内部类,然后hook内部类中的innerPrint

//hook内部类
function hookTest5()
{
    //获取java类
    var inner=Java.use("com.example.hookdemo01.Student$innerClass");
    
    student.innerPrint.implementation=function()
    {
        //其他操作相同

    }
      
}

hook内部类需要在获取java类时,在类名后加上$符号连接内部类,这个完整的类名可以在smali代码中看到。匿名类的hook方法和内部类一样,可以通过查看smali代码的类名来hook。

枚举所有类和方法

代码如下:

function hookTest6()
{
    //枚举已经加载的类 异步方式
    Java.enumerateLoadedClasses({
        //每枚举一个类调用一次
        onMatch:function(name,handler)
        {
            //对类名进行过滤 
            if(name.indexOf("com.example.hookdemo01")!=-1)
            {
                //输出类名
                console.log(name);

                //根据类名获取java类
                var clz=Java.use(name);
                //获取类的所有方法
                var methods=clz.class.getDeclaredMethods();
                
                //循环输出所有方法
                for(var i=0;i 

在Frida中枚举所有已加载的需要用到enumerateLoadedClasses函数,在获取到所有类之后,再通过Java.use获取类,接着通过Java中的getDeclaredMethods函数,获取所有的函数名称,接着循环输出即可

hook动态加载的DexClass

对于一些使用DexClassLoader动态加载dex文件的apk来说,直接使用Java.user必然是找不到当前的类,因为当前apk的ClassLoader并不存在这个类。想要hook动态加载的类需要先解决ClassLoader的问题。

function hookTest7()
{
    //枚举ClassLoder
    Java.enumerateClassLoaders({
        onMatch:function(loader)
        {
            try 
            {
              //如果能找到需要hook的类
                if(loader.loadClass("com.example.hookdemo01.Student"))
                {
                    //替换当前的ClassLoader
                    Java.ClassFactory.loader=loader;

                    //实现hook代码
                    var inner=Java.use("com.example.hookdemo01.Student$innerClass");
                }   
            } catch (error) 
            {
                
            }   
        },

        onComplete:function()
        {

        }
    });
}

对于动态加载的类,Frida提供了enumerateClassLoaders函数来枚举ClassLoder,当枚举的ClassLoder中有需要Hook的类时,可以修改loader为当前的ClassLoader,然后再进行hook即可。

Native层hook hook有导出函数
//hook有导出函数
function hookTest8()
{
    //so名称
    var so_name="libnative-lib.so";
    //要Hook的函数名
    var fun_name="test";

    //通过名称找到导出函数
    var add_fun=Module.findExportByName(so_name,fun_name);

    Interceptor.attach(add_fun,{
        //在hook函数之前执行
        onEnter:function(args)
        {
            //args[0],arg[1]
            console.log("hook enter");
        },
        //在hook函数之后执行
        onLeave:function(retval)
        {
            console.log("hook leaver");
        }

    });     
}

hook有导出函数直接通过导出函数名称找到函数地址即可进行hook

hook无导出函数
//hook无导出函数
function hookTest9()
{
    //so名称
    var so_name="libnative-lib.so";
    //要Hook的函数偏移
    var fun_off=0x7078;

   //加载到内存后,函数地址=so地址+函数偏移
   var so_add=Module.findbaseAddress(so_name);
   var add_func=parseInt(so_add,16)+fun_off;
   var ptr_fun=new NativePointer(add_func);

 
    Interceptor.attach(ptr_fun,{
        //在hook函数之前执行
        onEnter:function(args)
        {
            console.log("hook enter");
        },
        //在hook函数之后执行
        onLeave:function(retval)
        {
            console.log("hook leaver");
        }

    });     
}

未导出的函数我们需要手动的计算出函数地址,然后将其转化成一个NativePointer的对象然后进行hook操作

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/339067.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号