Android逆向学习之Frida逆向与抓包实战学习笔记(持续更新中)

学习资料:《安卓Frida逆向与抓包实战》陈佳林/著

基础环境

  1. 安装Android Studio并配置好adb
  2. 一台root的真机或者安卓虚拟机

第三章 Frida逆向入门之Java层hook

3.1 frida基础

3.1.3frida基础知识

frida存在两种操作模式
  1. CLI(命令行模式)
    通过命令行将js代码注入进程
  2. RPC模式
    通过python将js代码注入进进程,本质上还是使用js代码进行hook
frida操作App的方式有两种
  1. spwan模式
    将启动app的权利交由frida控制,即使目标App已启动,也会被
    frida重新启动.通过-f参数可以指定以spwan模式操作app
  2. attach模式
    app已经启动,frida通过ptrace注入程序从而执行hook.frida默认是attach模式操作app

3.1.4Frida IDE配置

  1. 安装node和npm环境
  2. git下载frida-agent-example仓库
git clone https://github.com/oleavr/frida-agent-example.git 下载frida-agent-example仓库
cd frida-agent-example/
npm install

使用vscode打开,在frida-agent-example文件夹内创建文件夹即可写脚本
在这里插入图片描述

3.2 frida脚本入门

3.2.1 frida脚本的概念

示例:

setTimeout(function(){
    Java.perform(function(){
        console.log("hello,world")
    })
})

代码分析:
1. 调用setTimeout方法将匿名函数注册到js运行库中
2. 在函数中调用Java.perform方法,将匿名函数注册到App的java运行库中,并执行函数

在手机上运行frida-server之后,可以使用frid-ps -U命令查看运行的进程
请添加图片描述
然后可以使用frida -U -l test0.js android.process.media将脚本注入进程,可以发现注入后打印了helloworld
请添加图片描述

在上面的参数中,-U指定usb设备,-l指定注入脚本所在路径,最后的androdi.process.media则是设备上正在运行的进程名

3.2.2 Java层hook基础

1.hook初探

android studio项目代码

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
        }
    }
    void fun(int x,int y)
    {
        Log.d("sum=",String.valueOf(x+y));
    }
}

运行结果: android studio控制台会持续输出x+y,并且x和y逐次自增
请添加图片描述

hook脚本代码:

function main(){
    console.log("Script loaded success")
    //Java.perform是frida的api函数,可以将其中的脚本注入到java运行库,参数是一个匿名函数
    //函数的主体内容是监控和修改java函数逻辑的主题内容,任何针对java层的操作都必须在这个api函数中
    Java.perform(function(){
        console.log("Inside java perform!")
        //java.use获取hook函数所在类的类名
        var Mainactivity=Java.use('com.example.hooktest1.MainActivity')
        console.log("Java.use.success!")
        //通过.连接函数名,比如这里的函数名是fun,表示想hookfun函数
        //implementation表示实现该函数,也就是hook掉,这里可以写自己的函数
        Mainactivity.fun.implementation=function(x,y)
        {
            console.log("x=",x,"y=",y,"x+y=",x+y)   //打印参数,这里应该是函数原本没有被修改时的参数,即函数正常执行时的参数情况
            var retvalue=this.fun(666,66)           //再次调用原函数并且传递原本的参数fun,即重新执行原函数,在这里就可以修改参数
            return retvalue      //返回函数返回值,返回值最好不要修改类型,否则可能出错
        }
    })
}
//参数是要被执行的函数,例如传入main,表示frida注入app后立刻执行main
//setTimeout可以指定frida注入app多久之后执行函数,用于延时注入
setImmediate(main)

将脚本注入进程frida -U -l test0.js com.example.hooktest1
可以看到注入之后命令台会输出js脚本函数的内容
请添加图片描述
再看看android studio命令台,可以发现控制台一直在输出sum=: 732
说明脚本中调用this.fun(666,66)成功
请添加图片描述

2.重载函数的hook

略微修改代码:

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
    private String total="hello";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
        return s.toLowerCase();
    }

程序运行结果:
请添加图片描述

hook脚本:

//定位重载函数,使用overload即可,overload内指定重载函数参数类型,如果函数有返回值要注意返回
 function main(){
    console.log("Loaded sucess!")
    Java.perform(function(){
        console.log("Inside java perform")
        var activity=Java.use("com.example.hooktest1.MainActivity")
        console.log("定位activity成功")
        activity.fun.overload('java.lang.String').implementation=function(x){
            console.log("hook fun string=",x)
            return x
        }
        activity.fun.overload('int','int').implementation=function(x,y){
            console.log("x=",x,"y=",y)
           var ret= this.fun(66,55)
           return ret;
        }
    })
 }
 setImmediate(main)

hook结果
请添加图片描述

控制台:
请添加图片描述

3.2.3 Java层主动调用

上述实现的是被动调用:即随着app正常逻辑执行函数
主动调用则是可以直接调用关键函数,不需要app去执行该函数
这里又分两种情况:

  1. 类函数(静态方法) 直接使用Java.use找到函数所在类即可
  2. 实例方法(动态方法) 使用Java.choose这个api函数在java堆中寻找指定类实例
1. 主动调用例1

程序代码:
添加了secret和staticSecret两个方法

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
        return s.toLowerCase();
    }
    void secret(){
        Log.d("this is secret","find secret func!");
    }
    static void staticSecret(){
        Log.d("this is staticSecret","Find static!");
    }
}

程序执行结果:
请添加图片描述

hook脚本:

function main(){
    Java.perform(function(){
        console.log("Inside java perform")
        var MainActivity=Java.use("com.example.hooktest1.MainActivity")
            
        MainActivity.staticSecret()
        //动态函数主动调用
        //java.choose先从内存中寻找类的实例对象,然后再调用实例对象的函数
        Java.choose('com.example.hooktest1.MainActivity',{
            onMatch: function(instance){
                console.log("instance found",instance)
                instance.secret()
            },
            onComplete: function(){
                console.log('search Complete')
            }
        })

    })
}
setImmediate(main)

hook结果
可以看到成功打印了实例对象所在类及其地址
请添加图片描述

控制台可以看见成功调用了secret和staticSecret这两个函数
请添加图片描述

注意:调用这两个函数输出的结果是在android studio控制台,不在frida控制台,frida控制台输出的是js脚本中的内容.

2. 主动调用例2

略微修改上述程序代码,增加了两个私有变量,尝试hook变量值

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    private String total="hello";
    private int count=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
        return s.toLowerCase();
    }
    void secret(){
        total+="call"+count;
        count++;
        Log.d("this is secret","find secret func!");
    }
    static void staticSecret(){
        Log.d("this is staticSecret","Find static!");
    }
}

程序运行结果:
请添加图片描述

hook脚本:

//调用secret函数,需要控制台手动进行,
function callSecretFunc(){
    Java.perform(function(){
        Java.choose('com.example.hooktest1.MainActivity',{
            onMatch:function(instance){
                instance.secret()
            },
            onComplete:function(){

            }
        })
})
}

//获取total的值
function getTotalValue(){
    Java.perform(function(){
        Java.choose('com.example.hooktest1.MainActivity',{
            onMatch:function(instance){
                console.log("find instance=",instance)
                console.log("totalAddr=",instance.total)//获取类变量的值要使用.value,total本身是一个引用类型
                console.log("total=",instance.total.value)
            },
            onComplete:function(){
                console.log("search end")
            }
        })
    })
}
setImmediate(getTotalValue)

hook结果
可以看到程序先调用了getTotalValue函数,输出了total的值
然后我们在frida控制台调用callSecretFunc()脚本函数来调用secret函数修改total的值
再次调用getTotalValue输出total的值发现成功修改
请添加图片描述

总结:

  1. 获取类中的实例变量要用.value才可以得到他的值,如果直接打印得不到值(可以得到变量有关信息,因为total本身是一个引用类型)
  2. frida控制台中我们可以反复调用脚本的函数来达到反复调用程序函数的目的

第四章 Objection快速入门

4.2 Objection的安装与使用

4.2.1 objection安装

pip install -U objection

注意:由于frida更新较快,需要保证objection版本的发布时间在frida之后.最新的objection版本为1.11.0,对应的frida版本最大为14.2.14,frida-tools为9.2.2

4.2.2 objection使用

1. 注入进程进入REPL

objection默认通过USB连接设备,不需要像frida使用-U参数指定usb
以’设置’应用演示注入进程命令:objection -g com.android.settings explore
成功注入会显示如下信息:
请添加图片描述

这样就成功进入了objection的REPL界面,可以输入exit退出

2. 常用命令:

空格键可以提示输入命令
请添加图片描述

  1. help 如果不知道当前命令是什么效果,可以在命令前跟help,会输出命令的解释信息
    请添加图片描述

  2. jobs命令
    jobs list 显示当前作业
    jobs kill 删除作业
    请添加图片描述

  3. frida命令
    查看frida信息
    请添加图片描述

  4. 内存漫游相关命令
    (1)android hooking list classes
    打印内存中的所有类
    请添加图片描述

    (2)android hooking search classes key
    搜索包含关键词key的所有类
    请添加图片描述

    (3)android hooking search methods key
    搜索包含关键词key的所有方法
    请添加图片描述

    (4)android hooking list class_methods classname
    查看名为classname的类的所有方法
    请添加图片描述

    (5)android hooking list activities(services receivers providers)
    打印四大组件,列出进程所有的activity活动(service receiver provider)
    请添加图片描述

  5. hook相关命令
    android hooking watch class_method methodName
    对指定方法进行hook
    请添加图片描述

持续更新中…

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Frida是个轻量级so级别的hook框架,它可以帮助逆向人员对指定的进程的so模块进行分析。它主要提供了功能简单的python接口和功能丰富的js接口,使得hook函数和修改so编程化,值得一提的是接口包含了主控端与目标进程的交互接口,由此我们可以即时获取信息并随时进行修改。使用frida可以获取进程的信息(模块列表,线程列表,库导出函数),可以拦截指定函数和调用指定函数,可以注入代码,总而言之,使用frida我们可以对进程模块进行手术刀式剖析。 它主要的工作方式是将脚本库注入到目标进程,在目标进程执行脚本。这里需要注意的是,它是将脚本库注入到已经启动的进程,但并不是说,对于进程初始化所做的动作,frida无能为力,frida提供了一个接口spawn,可以启动并暂时挂起进程,然后待我们布置好hook代码后再恢复进程运行,但是这个时间很短,大概2秒,也可能是我的使用姿势不对,求大佬指正。 此外,frida提供了相关的文档,但是frida官网提供的关于python接口的文档实在是少的可怜,连工具命令行的参数都没有,这点需要下载frida的python接口的源代码自己去分析了。值得高兴的一点是,Frida官网提供的js接口的文档稍微详细一些,并附有一些可喜的例子。 除了用于脚本编程的接口外,frida还提供了一些简单的工具,比如查看进程列表,追踪某个库函数等。 剩下就是关于frda学习路线了,Frida学习还是蛮简单的,只需要了解两方面的内容: 1)主控端和目标进程的交互(message) 2)Python接口和js接口(查文档)
Frida逆向抓包实战是一本关于移动端应用逆向抓包技术的实践指南。本书主要介绍了Frida这一强大的逆向工具的使用方法,并结合实际案例进行讲解。 首先,Frida是一款强大的动态分析工具,可以在运行的应用程序注入自定义的JavaScript代码,从而实现应用程序的行为监控与控制。本书以Frida为基础,详细介绍了如何使用Frida进行Android和iOS应用程序的逆向分析。读者可以学习到如何使用Frida的API来动态修改应用程序的行为,如动态调试、函数替换、Hook等。 其次,本书还介绍了抓包技术在移动应用逆向的应用。通过抓包技术,读者可以捕获应用程序与服务器之间的通信数据,分析应用程序的网络请求和响应,了解应用程序的数据传输方式和协议。本书讲解了常用的抓包工具和技术,如使用Fiddler、Charles等工具进行HTTPS抓包,分析加密通信数据等。 本书还通过实例演示了如何使用Frida抓包技术进行实际的应用分析。例如,通过使用Frida获取应用程序的敏感数据并进行修改,探测应用程序的漏洞,发现应用程序的安全问题等。通过抓包技术,读者可以分析应用程序的通信过程,了解应用程序与服务器之间的交互,发现潜在的数据泄漏风险等。 综上所述,Frida逆向抓包实战是一本介绍了Frida工具的基本原理和实际应用的实践指南。通过学习本书,读者可以了解到Frida的使用方法以及如何利用抓包技术进行移动应用逆向分析,并能够应用这些技术进行实际的应用分析与调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OrientalGlass

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值