Frida—HOOK 学习笔记1

JAVA层HOOK

在开始之前,依旧是熟悉的工具官方文档。因本人英文水平不高,大佬们可通过官网(https://frida.re/docs/home/)或看雪(https://bbs.pediy.com/thread-222729.htm)自取准确说明文档观看。

1.JAVA方法基础

Java方法是语句的集合,它们在一起执行一个功能。

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

在Java中方法有一个的样子;

image-20220214111625540

修饰符:告诉编译器如何调用该方法。定义了该方法的访问类型。

返回值类型:就是功能结果的数据类型。当这个方法没有返回值的时候,返回值的类型为void;当这个方法有返回值的时候,返回值的类型根据返回的数据来确定*(如果有返回值,必须使用return)**。*

方法名:符合命名规则即可。

参数:实际参数:就是实际参与运算的。形式参数;就是方法定义上的,用于接收实际参数的。

参数类型:就是参数的数据类型

参数名:就是变量名

方法体语句:就是完成功能的代码。

return*:结束方法的。*

返回值:就是功能的结果,由return带给调用者。

在知晓基本的Java方法结构后,开始本处的重点之一。

1) 普通方法

定义:简单的说方法就是完成特定功能的代码块。

普通方法分为:有明确返回值的方法和没有明确返回值的方法。

A.有明确返回值的方法的调用

可以单独调用、输出调用、赋值调用。

B.没有明确返回值的方法调用(void类型方法的调用)

只能单独使用。

举个简单的例子:

public class Fangfa {

  //  主方法

  public static void main(String args[]) {

    System.out.println(add(10,20));

  }

  //返回两个整数相加

  public static int add(int a , int b){

    return a + b ;

  }

}

通过例子可以发现,普通方法就是我们写的最常见、最大众化的。满足方法基本结构。

2) 构造方法

构造方法是类的一种特殊方法,用来初始化类的一个新的对象,在创建对象(new 运算符)之后自动调用。Java 中的每个类都有一个默认的构造方法,并且可以有一个以上的构造方法。

构造方法需满足条件:

1、方法名与类名同名。

2、在方法中不能使用return 语句返回即为该方法没有任何返回值,包括 void。

3、在方法名的前面没有返回值的类型声明

通过上述条件可发现,构造方法会在普通的方法结构上发生一些变化,举个例子:

public class Constructor {

  // 给Constructor类定义了一个成员变量name

  private String name;

  // 无参构造方法,方法名必须跟类名一致,即首字母需要大写

  public Constructor() {

    System.out.println("调用无参数的构造方法。。");

  }

  // 带一个参数的构造方法

  public Constructor(String name) {

    // 通过this()调用无参构造方法

    this();

    this.name = name;

    // 构造方法里可以调用普通方法

    commonMethod();

  }

  public void commonMethod() {

    System.out.println("调用普通方法");

  }

  // 写个主函数测试一下

  public static void main(String[] args) {

    // 通过无参构造创建一个Constructor对象

    Constructor cons1 = new Constructor();

     cons1.name = "我是通过无参构造器创建的对象";

    System.out.println(cons1);

    System.out.println("=====================我是分隔线=====================");

    // 通过有参构造方法创建另一个对象

    Constructor cons2 = new Constructor("我是通过有参构造方法创建的对象");

    System.out.println(cons2);

  }

   public String toString() {

    return this.getClass().getSimpleName() + "[我的名字是:" + name + "]";

  }

}  

运行结果如下:

img

3) 重载方法

重载方法(Overloading)的定义:如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载。 具体满足条件包括:

  • 方法名相同
  • 方法的参数类型,参数个不一样
  • 方法的返回类型可以不相同
  • 方法的修饰符可以不相同
  • main 方法也可以被重载

举个例子:

class MyClass {

  int height;

  MyClass() {

	System.out.println("无参数构造函数");

    height = 4;

  }

  MyClass(int i) {

    System.out.println("房子高度为 " + i + " 米");

    height = i;

  }

  void info() {

    System.out.println("房子高度为 " + height + " 米");

  }

  void info(String s) {

    System.out.println(s + ": 房子高度为 " + height + " 米");

  }

}

public class MainClass {

  public static void main(String[] args) {

    MyClass t = new MyClass(3);

    t.info();

    t.info("重载方法");

    //重载构造函数

    new MyClass();

  }
}   

程序执行结果如下:

img

2.Frida安装

对于安装这部分,大家可在互联网自行搜索安装。个人建议是使用python2的旧版本,因为在burp中有一个brida工具来帮助使用Frida。Brida的使用可参考下述文章(https://blog.csdn.net/weixin_39190897/article/details/102691898),网络上存在说python3也可使用该工具,不过本人尝试后未成功。

在安装Frida时要主要参考最新安装教程所涉及的Frida及frida-tools的版本,直接使用pip进行安装存在frida安装最新版可以成功,但是安装frida-tools时则会报错。

3.普通方法HOOK

针对普通方法、构造方法、重载方法可使用APP安装包:方法hook.app

安装并启动APP:

此处插入一个题外话,大佬们是不是看见一个可爱的群号呀,是不是想去搜一下呀。我替大家搜过了,知道了结果也就不打码了。结果是这个样子滴:

imgimg

看到这个结果是不是可以放下手机了???

言归正传,发现APP在启动后弹出3000,点击普通方法弹出4000。

使用JADX等反编译工具对APP进行反编译操作,获取到源码。

在安卓源码中存在文件AndroidManifest.xml,在这个文件内可寻找到中找到app的入口地址。访问MainActivity,其代码如下:

通过代码可看出应用在运行后执行了一个onCreate方法,方法中包含一个方法为getCalc。这部分主要是写了三个按键的事件和监听,在方法最后一行出现了和按键无关的数字1000,2000。这个时候还记得应用运行时的弹出的3000吗?

本节是使用Frida对普通函数进行hook,在app界面对应为按钮1(button1),对于按键的响应事件被定义在onClick方法里,效果为点击button1后弹出一个文本。在代码中的关键方法为Utils.getCalc,这也是要hook的关键。在查看该方法的代码:

发现该方法为简单的加法运算。启动firda对该函数进行hook。需要编写一个脚本来进行操作,具体代码这么写呢?不要着急,frida官网给出了脚本的模版(https://frida.re/docs/examples/android/)通过本例写出的脚本,告诉大家每部分是干嘛的。

frida的hook代码如下:

import frida, sys 

//导入脚本所需的包

 

jscode = """ 

//hook主要执行的代码区域

Java.perform(function () {

//hook核心代码包含在Java.perform函数之中。 

  var util = Java.use('com.xiaojianbang.app.Utils');

//此处com.xiaojianbang.app.Utils为将要hook的方法所处的类的路径。 

  util.getCalc.implementation = function (a, b) { 

// getCalc为在获取类路径后将要hook方法名。在这里更改类的方法的实现(implementation)

  console.log("Hook Start..."); 

    send(a);

    send(b);

  send("Success!");

    return this.getCalc(a,b)

//以上三行为hook代码的执行代码。

  } }); 

""" 

 

def message(message, data): 

  if message["type"] == 'send': 

      print("[] {0}".format(message['payload']))   

  else:     

    print(message) 

 

process = frida.get_remote_device().attach('com.xiaojianbang.app') 

//利用Frida包中函数对要hook的app包名创建一个进程 

script= process.create_script(jscode) 

script.on("message", message) 

script.load() 

sys.stdin.read() 

对代码了解之后可发现只需对标红处代码进更改即可。编写的重点在于执行代码处。对于代码标绿处有如图两种情况:

img

代码正常执行后结果为:

img

将执行代码进行如下修改:

img

执行结果如下:

img

通过以上执行结果发现传入的100,300成功的进行了加运算。说明对该函数成功进行了hook。

本节所涉及代码框架应用于全文,建议大家理解普通方法的hook脚本后继续向下。后文代码将以hook处理代码为主。

4.构造方法HOOK

本节利用上节APP进行构造方法hook,对应功能为button2,点击后效果如下:

img

按键代码如下:

img

查看代码中关键方法Utils.getMoney。

img

发现getMoney方法内存在一个new的实例化方法Money,查看该方法的代码。根据最开始对Java方法的基础学习发现这个方法符合构造方法的特征。

img

要hook这个函数,依据上节的经验开始编写:

img

正常的写代码到这个位置了,但是这时突然想起构造方法名是不是和类名一模一样的。那就没有必要在这个地方再写方法名称。这个时候拿出了一个固定写法为$init。将上述代码改为:

img

代码执行结果如下:

img

出现上述结果说明hook成功了,但是要利用工具对我们输入的值进行操作,可将代码改写为:

img

执行代码之后,app的执行结果应为下图所示,说明hook并成功利用了方法。

img

5.重载方法HOOK

本节进入重载的hook,事件绑定在button3。其按键监听代码为:

img

代码中关键方法为Utils.test。查看其代码:

img

发现有两个方法都叫test,根据掌握的知识,这两个方法互为重载。对该函数进行hook。根据上面两节的经验在进行更改类的实现的时候,会有一个疑惑:两个方法名字一样,代码如何去选择?这个地方引入一个overload(),该方法()填写内容为hook方法的参数的类型,空参时该括号内容也为空。例如:overload(“int”)

hook的测试代码为:

img

执行结果如下:

img

img

通过上述过程,脚本在hook同名方法时,只需在overload()中将参数的类型依次填入。在遇到string类型的参数时,应填写为:Java.lang.String,因为string是Java提供用来来创建和操作字符串的类。

img

6. 函数参数类型表示

不同的参数类型都有自己的表示方法

对于基本类型,直接用它在Java中的表示方法就可以了,不用改变,例如:

· int

· short

· char

· byte

· boolean

· float

· double

· long

基本类型数组,用左中括号接上基本类型的缩写

基本类型缩写表示表:

基本类型缩写
booleanZ
byteB
charC
doubleD
floatF
intI
longJ
shortS

例如:int[]类型,在重载时要写成[I

任意类,直接写完整类名即可

例如:java.lang.String

对象数组,用左中括号接上完整类名再接上分号

例如:[java.lang.String;

1) 带参数的构造函数

修改参数为byte[]类型的构造函数的实现

ClassName.$init.overload('[B').implementation=function(param){

  //do something

}

注:ClassName是使用Java.use定义的类;param是可以在函数体中访问的参数

修改多参数的构造函数的实现

ClassName.$init.overload('[B','int','int').implementation=function(param1,param2,param3){

  //do something

}

2) 无参数构造函数

ClassName.$init.overload().implementation=function(){

  //do something

}

调用原构造函数

ClassName.$init.overload().implementation=function(){

  //do something

  this.$init();

  //do something

}

注意:当构造函数(函数)有多种重载形式,比如一个类中有两个形式的func:void func()和void func(int),要加上overload来对函数进行重载,否则可以省略overload

3) 一般函数

修改函数名为func,参数为byte[]类型的函数的实现

ClassName.func.overload('[B').implementation=function(param){

  //do something

  //return ...

}

4) 无参数的函数

ClassName.func.overload().implementation=function(){

  //do something

}

注: 在修改函数实现时,如果原函数有返回值,那么我们在实现时也要返回合适的值

ClassName.func.overload().implementation=function(){

  //do something

  return this.func();

}

7. 构造对象参数HOOK

本节进入重载的hook,事件绑定在button4。执行效果为:

img

其按键监听代码为:

img

发现关键方法test中传入了一个对象。查看关键函数代码:

img

对比三个test方法,发现最后一个test的参数为一个对象还是一个重载。

img

按照重载方法hook的方式,我们可以编写代码:

var utils = Java.use('com.xiaojianbang.app.Utils');

utils.test.overload().implementation = function (a) 

但是因为本次传入的内容是个人定义的内容。overload方法这里填写内容这个时候可参考string的传入。我们将overload内容要求变成传入方法的全路径。

utils.test.overload('com.xiaojianbang.app.Money').implementation

代码整理后为:

img

运行结果如下:

img

这个时候在输出中文时会出现如下报错:

img

解决办法是:

img

但是本节的结果是构造对象参数,将随机输入的参数利用hook函数进行处理。操作代码如下;

jscode = """

Java.perform(function () {

    var utils = Java.use('com.xiaojianbang.app.Utils');

    var money = Java.use('com.xiaojianbang.app.Money');

    //上述两行是将hook方法中涉及的方法所在类导入

  utils.test.overload('com.xiaojianbang.app.Money').implementation = function (a) {

    send("Hook Start...");

send(a.getInfo());

//利用hook方法内方式进行输出,简单就是将money这个参数值标示变成了a

    var mon = money.$new(2000,'gangyuan');

 //因为test内输入参数所利用的Money为构造函数,在使用时需利用$new进行实例化使用,可当一个通用方式来写。

    send(mon.getInfo());

    return this.test(mon);

  }

});

"""

执行结果如下,说明我们成功对目标方法进行了hook,并修改了传入值。

img

img

8. 实例

在渗透测试过程中常会遇到数据包加密的情况。如下APP

img

用户登陆数据如下:

img

针对数据包提示信息在源码中进行搜索。

img

或者依据数据包提示接口位置进行搜索,在代码附近找寻加密方式。各位大佬也可以用自己习惯的方式去找寻。

img

通过搜索关键字等方式,是为找到代码中执行加密的部分:

img

我们发现传输的内容经过RequestUtil.encodeDesMap进行了处理。处理的数据内容为addMap,数据传输流程如下:

1.函数接受输入参数发送,在login方法流程最后调用了requesNetwork方法。

img

2.requestNetwork方法中para2接受的参数一路传递至addRequestMap。

img

加密流程至加密处理时要加密内容进入到addMap。故获取encodeDesMap相关信息。

img

RequestUtil.paraMap相关信息如下:

img

按上文获取到加密代码,目前可确定将要HOOK内容为paraMap:

img

在查看处理代码时发现paraMap处理的内容为Map集合,直接HOOK该处内容为Map集合,涉及到字符串的拼接等不便于数据展示。在该方法的代码中可发现Utils.md5方法,该方法对拼接后的数据进行了处理:

img

此处HOOK结果如下:

img

我们对encodeDesMap进行HOOK可获取到加密后的结果。

img

9. 工具使用HOOK

这里用到的工具及环境有

  1. BurpSuite,

  2. HTTPDecrypt(https://github.com/lyxhh/lxhToolHTTPDecrypt),

  3. Python3。

注意这个地方环境变成了python3,对应的Frida和frida-tools要重新安装。

拿到一个新的app之后,总会有一段懵逼🤔寻找hook点的时候。HTTPDecrypt可以帮我较快的获取到相应的内容。

  1. 获取到源码,安装所需要的环境库。

img

  1. 浏览器访问地址,加载应用列表。如列表为空,多刷新刷新。

img

将想要操作的APP的报名填入空格,点击confirm。

img

  1. 使用Finds功能对app内类、方法进行搜索。

img

这个时候可以将目标类进行HOOKS,会讲类中存在的方法进行逐一HOOK。

img

进入HOOKS功能后,可看到上步选择的类。点击一下confirm。然后运行APP,进行正常的操作。

img

​ 这时在该页面会出现对HOOK函数结果的输出:

img

​ 在结果中寻找自己想要的结果,查看对应的方法。之后就可以自己写脚本或者使用工具自带的方法进行加密操作。

​ 大佬们后可使用一下该工具与burp的结果使用,比brida较为方便。Brida涉及自己js脚本编写,使用复杂度比较高,推荐使用该工具。

隐私合规涉及部分方法HOOK

HOOK脚本

//此脚本为基于Frida的安卓权限检测脚本,HOOK函数因Android版本问题,存在误差,可自行测试
//打印堆栈信息,需要手动在下面的函数里自己添加调用,也可以自己再写一个输出函数。
//function showStacks() {
//    var Exception = Java.use("java.lang.Exception");
//    var ins = Exception.$new("Exception");
//    var straces = ins.getStackTrace();
//    if (undefined == straces || null == straces) {
//        return;
//   }
//    console.log("============================= Stack strat=======================\r\n");
//    console.log("");
//    for (var i = 0; i < straces.length; i++) {
//        var str = "   " + straces[i].toString();
//        console.log(str\r\n);
//    }
//    console.log("");
//    console.log("============================= Stack end=======================\r\n");
 //   Exception.$dispose();
//}

// APP申请权限
function checkRequestPermission() {
    try {
        var ActivityCompat = Java.use("androidx.core.app.ActivityCompat")
    } catch (e) {
        console.log(e)
        return
    }
    ActivityCompat.requestPermissions.overload('android.app.Activity', '[Ljava.lang.String;', 'int').implementation = function(p1, p2, p3) {
        var temp = this.requestPermissions(p1, p2, p3);
        console.log("APP申请权限", "申请权限为: " + p2);
        return temp
    }
}
// APP获取IMEI/IMSI
function getPhoneState() {
    try {
        var TelephonyManager = Java.use("android.telephony.TelephonyManager");
    } catch (e) {
        console.log(e)
        return
    }
    // API level 26 获取单个IMEI的方法
    TelephonyManager.getDeviceId.overload().implementation = function() {
        var temp = this.getDeviceId();
        console.log("获取IMEI", "获取的IMEI为: " + temp)
        return temp;
    };
    //API level 26 获取多个IMEI的方法
    TelephonyManager.getDeviceId.overload('int').implementation = function(p) {
        var temp = this.getDeviceId(p);
        console.log("获取IMEI", "获取(" + p + ")的IMEI为: " + temp);
        return temp;
    };
    //API LEVEL26以上的获取单个IMEI方法
    TelephonyManager.getImei.overload().implementation = function() {
        var temp = this.getImei();
        console.log("获取IMEI", "获取的IMEI为: " + temp)
        return temp;
    };
    // API LEVEL26以上的获取多个IMEI方法
    TelephonyManager.getImei.overload('int').implementation = function(p) {
        var temp = this.getImei(p);
        console.log("获取IMEI", "获取(" + p + ")的IMEI为: " + temp);
        return temp;
    };
    //imsi/iccid
    TelephonyManager.getSimSerialNumber.overload().implementation = function() {
        var temp = this.getSimSerialNumber();
        console.log("获取IMSI/iccid", "获取IMSI/iccid为(String): " + temp);
        return temp;
    };
    //imsi
    TelephonyManager.getSubscriberId.overload().implementation = function() {
        var temp = this.getSubscriberId();
        console.log("获取IMSI", "获取IMSI为(int): " + temp);
        return temp;
    }
    //imsi/iccid
    TelephonyManager.getSimSerialNumber.overload('int').implementation = function(p) {
        var temp = this.getSimSerialNumber(p);
        console.log("获取IMSI/iccid", "参数为:(" + p + "), 获取IMSI/iccid为(int): " + temp);
        return temp;
    }
}
// 获取系统属性(记录关键的)。意义不大,frida获取不到。暂时留着
function getSystemProperties() {
    try {
        var SystemProperties = Java.use("android.os.SystemProperties");
    } catch (e) {
        console.log(e)
        return
    }
    SystemProperties.get.overload('java.lang.String').implementation = function(p1) {
        var temp = this.get(p1);
        if (p1 == "ro.serialno") {
            console.log("获取设备序列号", "获取(" + p1 + "),值为:" + temp);
        }
        if (p1 == "ro.build.display.id") {
            console.log("获取版本号", "获取(" + p1 + "),值为:" + temp);
        }
        //MEID
        if (p1 == "ril.cdma.meid") {
            console.log("获取MEID", "获取(" + p1 + "),值为:" + temp);
        }
        //手机型号
        if (p1 == "ro.product.model") {
            console.log("获取手机型号", "获取(" + p1 + "),值为:" + temp);
        }
        //手机厂商
        if (p1 == "ro.product.manufacturer") {
            console.log("获取手机厂商", "获取(" + p1 + "),值为:" + temp);
        }
        return temp;
    }
    SystemProperties.get.overload('java.lang.String', 'java.lang.String').implementation = function(p1, p2) {
        var temp = this.get(p1, p2)
        if (p1 == "ro.serialno") {
            console.log("获取设备序列号", "获取(" + p1 + " 、 " + p2 + "),值为:" + temp);
        }
        if (p1 == "ro.build.display.id") {
            console.log("获取版本号", "获取(" + p1 + " 、 " + p2 + "),值为:" + temp);
        }
        //MEID
        if (p1 == "ril.cdma.meid") {
            console.log("获取MEID", "获取(" + p1 + " 、 " + p2 + "),值为:" + temp);
        }
        //手机型号
        if (p1 == "ro.product.model") {
            console.log("获取手机型号", "获取(" + p1 + " 、 " + p2 + "),值为:" + temp);
        }
        //手机厂商
        if (p1 == "ro.product.manufacturer") {
            console.log("获取手机厂商", "获取(" + p1 + " 、 " + p2 + "),值为:" + temp);
        }
        return temp;
    }
    SystemProperties.getInt.overload('java.lang.String', 'int').implementation = function(p1, p2) {
        var temp = this.getInt(p1, p2)
        if (p1 == "ro.build.version.sdk") {
            console.log("获取SDK版本号", "获取(" + p1 + "),值为:" + temp);
        }
        return temp;
    }
}
//获取content敏感信息
function getContentProvider() {
    try {
        // 通讯录内容
        var ContactsContract = Java.use("android.provider.ContactsContract");
        var contact_authority = ContactsContract.class.getDeclaredField("AUTHORITY").get('java.lang.Object');
    } catch (e) {
        console.log(e)
    }
    try {
        // 日历内容
        var CalendarContract = Java.use("android.provider.CalendarContract");
        var calendar_authority = CalendarContract.class.getDeclaredField("AUTHORITY").get('java.lang.Object');
    } catch (e) {
        console.log(e)
    }
    try {
        // 浏览器内容
        var BrowserContract = Java.use("android.provider.BrowserContract");
        var browser_authority = BrowserContract.class.getDeclaredField("AUTHORITY").get('java.lang.Object');
    } catch (e) {
        console.log(e)
    }
    try {
        var ContentResolver = Java.use("android.content.ContentResolver");
        ContentResolver.query.overload('android.net.Uri', '[Ljava.lang.String;', 'android.os.Bundle', 'android.os.CancellationSignal').implementation = function(p1, p2, p3, p4) {
            var temp = this.query(p1, p2, p3, p4);
            if (p1.toString().indexOf(contact_authority) != -1) {
                console.log("获取content敏感信息", "获取手机通信录内容");
            } else if (p1.toString().indexOf(calendar_authority) != -1) {
                console.log("获取content敏感信息", "获取日历内容");
            } else if (p1.toString().indexOf(browser_authority) != -1) {
                console.log("获取content敏感信息", "获取浏览器内容");
            }
            return temp;
        }
    } catch (e) {
        console.log(e)
        return
    }
}
// 获取安卓ID
function getAndroidId() {
    try {
        var SettingsSecure = Java.use("android.provider.Settings$Secure");
    } catch (e) {
        console.log(e)
        return
    }
    SettingsSecure.getString.implementation = function(p1, p2) {
        if (p2.indexOf("android_id") < 0) {
            return this.getString(p1, p2);
        }
        var temp = this.getString(p1, p2);
        console.log("获取Android ID", "参数为:" + p2 + ",获取到的ID为:" + temp.toString());
        return temp;
    }
}
//获取其他app信息
function getPackageManager() {
    try {
        var PackageManager = Java.use("android.content.pm.PackageManager");
        PackageManager.getInstalledPackages.overload('int').implementation = function(p1) {
            var temp = this.getInstalledPackages(p1);
            console.log("获取其他app信息", "1获取的数据为:" + temp);
            return temp;
        };
        PackageManager.getInstalledApplications.overload('int').implementation = function(p1) {
            var temp = this.getInstalledApplications(p1);
            console.log("获取其他app信息", "getInstalledApplications获取的数据为:" + temp);
            return temp;
        };
    } catch (e) {
        console.log(e)
    }
    try {
        var ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager");
        ApplicationPackageManager.getInstalledPackages.overload('int').implementation = function(p1) {
            var temp = this.getInstalledPackages(p1);
            console.log("获取其他app信息", "getInstalledPackages获取的数据为:" + temp);
            return temp;
        };
        ApplicationPackageManager.getInstalledApplications.overload('int').implementation = function(p1) {
            var temp = this.getInstalledApplications(p1);
            console.log("获取其他app信息", "getInstalledApplications获取的数据为:" + temp);
            return temp;
        };
        ApplicationPackageManager.queryIntentActivities.implementation = function(p1, p2) {
            var temp = this.queryIntentActivities(p1, p2);
            console.log("获取其他app信息", "参数为:" + p1 + p2 + ",queryIntentActivities获取的数据为:" + temp);
            return temp;
        };
        ApplicationPackageManager.getApplicationInfo.implementation = function(p1, p2) {
            var temp = this.getApplicationInfo(p1, p2);
            var string_to_recv;
            // 判断是否为自身应用,是的话不记录
            console.log("APP包名是:"+ p1);
            recv(function(received_json_object) {
                string_to_recv = received_json_object.my_data;
            }).wait();
            if (string_to_recv) {
                console.log("获取其他app信息", "getApplicationInfo获取的数据为:" + temp);
            }
            return temp;
        };
    } catch (e) {
        console.log(e)
    }
    try {
        var ActivityManager = Java.use("android.app.ActivityManager");
        ActivityManager.getRunningAppProcesses.implementation = function() {
            var temp = this.getRunningAppProcesses();
            console.log("获取其他app信息", "获取了正在运行的App"+temp);
            return temp;
        };
    } catch (e) {
        console.log(e)
    }
}
// 获取位置信息
function getGSP() {
    try {
        var locationManager = Java.use("android.location.LocationManager");
    } catch (e) {
        console.log(e)
        return
    }
    locationManager.getLastKnownLocation.overload("java.lang.String").implementation = function(p1) {
        var temp = this.getLastKnownLocation(p1);
        console.log("获取位置信息", "获取位置信息,参数为:" + p1)
        return temp;
    }
    locationManager.requestLocationUpdates.overload("java.lang.String", "long", "float", "android.location.LocationListener").implementation = function(p1, p2, p3, p4) {
        var temp = this.requestLocationUpdates(p1, p2, p3, p4);
        console.log("获取位置信息", "获取位置信息");
        return temp;
    }
}
// 调用摄像头(hook,防止静默拍照)
function getCamera() {
    try {
        var Camera = Java.use("android.hardware.Camera");
    } catch (e) {
        console.log(e)
        return
    }
    Camera.open.overload("int").implementation = function(p1) {
        var temp = this.open(p1);
        console.log("调用摄像头", "调用摄像头id:" + p1.toString());
        return temp;
    }
}
//获取网络信息
function getNetwork() {
    try {
        var WifiInfo = Java.use("android.net.wifi.WifiInfo");
        //获取ip
        WifiInfo.getIpAddress.implementation = function() {
            var temp = this.getIpAddress();
            var _ip = new Array();
            _ip[0] = (temp >>> 24) >>> 0;
            _ip[1] = ((temp << 8) >>> 24) >>> 0;
            _ip[2] = (temp << 16) >>> 24;
            _ip[3] = (temp << 24) >>> 24;
            var _str = String(_ip[3]) + "." + String(_ip[2]) + "." + String(_ip[1]) + "." + String(_ip[0]);
            console.log("获取网络信息", "获取IP地址:" + _str);
            return temp;
        }
        //获取mac地址
        WifiInfo.getMacAddress.implementation = function() {
            var temp = this.getMacAddress();
            console.log("获取Mac地址", "获取到的Mac地址: " + temp);
            return temp;
        }
        WifiInfo.getSSID.implementation = function() {
            var temp = this.getSSID();
            console.log("获取wifi SSID", "获取到的SSID: " + temp);
            return temp;
        }
        WifiInfo.getBSSID.implementation = function() {
            var temp = this.getBSSID();
            console.log("获取wifi BSSID", "获取到的BSSID: " + temp);
            return temp;
        }
    } catch (e) {
        console.log(e)
    }
    try {
        var WifiManager = Java.use("android.net.wifi.WifiManager");
        // 获取wifi信息
        WifiManager.getConnectionInfo.implementation = function() {
            var temp = this.getConnectionInfo();
            console.log("获取wifi信息", "获取wifi信息");
            return temp;
        };
    } catch (e) {
        console.log(e)
    }
    try {
        var InetAddress = Java.use("java.net.InetAddress");
        //获取IP
        InetAddress.getHostAddress.implementation = function() {
            var temp = this.getHostAddress();
            console.log("获取网络信息", "获取IP地址:" + temp.toString());
            return temp;
        }
    } catch (e) {
        console.log(e)
    }
    try {
        var NetworkInterface = Java.use("java.net.NetworkInterface");
        //获取mac
        NetworkInterface.getHardwareAddress.overload().implementation = function() {
            var temp = this.getHardwareAddress();
            console.log("获取Mac地址", "获取到的Mac地址: " + temp);
            return temp;
        }
    } catch (e) {
        console.log(e)
    }
    try {
        var NetworkInfo = Java.use("android.net.NetworkInfo");
        NetworkInfo.getType.implementation = function() {
            var temp = this.getType();
            console.log("获取网络信息", "获取网络类型:" + temp.toString());
            return temp;
        }
        NetworkInfo.getTypeName.implementation = function() {
            var temp = this.getTypeName();
            console.log("获取网络信息", "获取网络类型名称:" + temp);
            return temp;
        }
        NetworkInfo.getExtraInfo.implementation = function() {
            var temp = this.getExtraInfo();
            console.log("获取网络信息", "获取网络名称:" + temp);
            return temp;
        }
        NetworkInfo.isAvailable.implementation = function() {
            var temp = this.isAvailable();
            console.log("获取网络信息", "获取网络是否可用:" + temp.toString());
            return temp;
        }
        NetworkInfo.isConnected.implementation = function() {
            var temp = this.isConnected();
            console.log("获取网络信息", "获取网络是否连接:" + temp.toString());
            return temp;
        }
    } catch (e) {
        console.log(e)
    }
}
//获取蓝牙设备信息
function getBluetooth() {
    try {
        var BluetoothDevice = Java.use("android.bluetooth.BluetoothDevice");
        //获取蓝牙设备名称
        BluetoothDevice.getName.overload().implementation = function() {
            var temp = this.getName();
            console.log("获取蓝牙信息", "获取到的蓝牙设备名称: " + temp)
            return temp;
        }
        //获取蓝牙设备mac
        BluetoothDevice.getAddress.implementation = function() {
            var temp = this.getAddress();
            console.log("获取蓝牙信息", "获取到的蓝牙设备mac: " + temp)
            return temp;
        }
    } catch (e) {
        console.log(e)
    }
    try {
        var BluetoothAdapter = Java.use("android.bluetooth.BluetoothAdapter");
        //获取蓝牙设备名称
        BluetoothAdapter.getName.implementation = function() {
            var temp = this.getName();
            console.log("获取蓝牙信息", "获取到的蓝牙设备名称: " + temp)
            return temp;
        };
    } catch (e) {
        console.log(e)
    }
}
//获取基站信息
function getCidorLac() {
    try {
        // 电信卡cid lac
        var CdmaCellLocation = Java.use("android.telephony.cdma.CdmaCellLocation");
        CdmaCellLocation.getBaseStationId.implementation = function() {
            var temp = this.getBaseStationId();
            console.log("获取基站信息", "获取到的cid: " + temp);
            return temp
        }
        CdmaCellLocation.getNetworkId.implementation = function() {
            var temp = this.getNetworkId();
            console.log("获取基站信息", "获取到的lac: " + temp);
            return temp
        }
    } catch (e) {
        console.log(e)
    }
    try {
        // 移动 联通卡 cid/lac
        var GsmCellLocation = Java.use("android.telephony.gsm.GsmCellLocation");
        GsmCellLocation.getCid.implementation = function() {
            var temp = this.getCid();
            console.log("获取基站信息", "获取到的cid: " + temp);
            return temp
        }
        GsmCellLocation.getLac.implementation = function() {
            var temp = this.getLac();
            console.log("获取基站信息", "获取到的lac: " + temp);
            return temp
        }
    } catch (e) {
        console.log(e)
    }
}

Java.perform(function() {
    console.log("合规检测敏感接口开始监控...");
    checkRequestPermission();
    getPhoneState();
    getContentProvider();
    getAndroidId();
    getPackageManager();
    getGSP();
    getCamera();
    getNetwork();
    getBluetooth();
    getCidorLac();
    //getSystemProperties();
})

脚本执行结果

image-20220209170838214

不足

学习环境为Android 8.0版本,因后期安卓版本更新带来的安全特性,使得脚本在高版本下使用效果不是很理想。

Frida是一个强大的动态分析工具,可以用于对应用程序进行hookFrida提供了多种hook方式,包括在应用程序启动前注入代码、通过USB连接和远程连接等。通过在应用程序启动前注入代码,可以在应用程序启动时即实现hook的效果。可以使用frida.get_usb_device()方法连接待调试的USB设备,并使用frida.get_device()方法指定调试的设备。此外,也可以通过远程连接方式进行hook,使用frida -U -f 包名 -l xxx.js --no-pause指令进行注入。以上是使用Frida进行hook的一些基本操作方式。需要根据具体的场景和需求选择合适的方法和参数进行操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Frida hook零基础教程](https://blog.csdn.net/cyjmosthandsome/article/details/120906998)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [python之frida安卓逆向之hook大法好](https://blog.csdn.net/weixin_51111267/article/details/125109497)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值