IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Frida笔记 - Android 篇 (一) -> 正文阅读

[移动开发]Frida笔记 - Android 篇 (一)

前言

相信不少小伙伴对Xposed、Cydia Substrate、Frida等hook工具都有所了解, 并且用在了自己的工作中, 本文主要分享Frida的环境配置以及基本使用, 以及相关功能在日常开发调试带来的帮助

配置Frida的环境

Frida的环境安装可以参考官方文档, 或者参考网上分享的实践, 使用较为稳定的特定版本

# 通过pip3安装Frida的CLI工具
pip3 install frida-tools
# 安装的frida版本
frida --version
# 本机目前使用的15.0.8的frida版本
# 在https://github.com/frida/frida/releases下载对应的server版本frida-server-15.0.8-android-arm64.xz
# unxz 解压缩
unxz frida-server-15.0.8-android-arm64.xz
adb root
adb push frida-server-15.0.8-android-arm64 /data/locl/tmp/
adb shell
chmod 755 /data/local/tmp/frida-server-15.0.8-android-arm64
/data/local/tmp/frida-server-15.0.8-android-arm64 &
# 打印已安装程序及包名
frida-ps -Uai

基本使用

  • Frida的开发环境, 可以参考作者在github上的exmaple

# 下载完成后通过vscode打开
git clone git://github.com/oleavr/frida-agent-example.git
npm install
  • 配置完成后, 使用对应函数就会有相应代码提示及函数说明

  • JavaScript API可以参考官方文档说明, 了解基本使用

Hook类的构造函数

// frida -U --no-pause -f com.gio.test.three -l agent/constructor.js

function main() {
  Java.perform(function () {
    Java.use(
      "com.growingio.android.sdk.autotrack.AutotrackConfiguration"
    ).$init.overload("java.lang.String", "java.lang.String").implementation =
      function (projectId, urlScheme) {
        // 调用原函数
        var result = this.$init(projectId, urlScheme);
        // 打印参数
        console.log("projectId, urlScheme: ", projectId, urlScheme);
        return result;
      };
  });
}

setImmediate(main);

Hook类的普通函数

// frida -U --no-pause -f com.gio.test.three -l agent/function.js

function main() {
  Java.perform(function () {
    Java.use(
      "com.growingio.android.sdk.CoreConfiguration"
    ).setDebugEnabled.implementation = function (enabled) {
      console.log("enabled: ", enabled);
      // 直接返回原函数执行结果
      return this.setDebugEnabled(enabled);
    };
  });
}

setImmediate(main);

修改类/实例参数

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/instance.js
function main() {
  Java.perform(function () {
    Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", {
      onMatch: function (instance) {
        console.log("instance.mProjectId", instance.mProjectId.value);
        console.log("instance.mUrlScheme", instance.mUrlScheme.value);
        // 修改变量时通过赋值, 如果变量与函数同名, 需要在变量前加'_', 如: _mProjectId
        instance.mProjectId.value = "t-bfc5d6a3693a110d";
        instance.mUrlScheme.value = "t-growing.d80871b41ef40518";
      },
      onComplete: function () {},
    });
  });
}

setImmediate(main);

构造数组

frida -U -n demos -l agent/array.js

function main() {
  Java.perform(function () {
    // 构造byte数组
    var byteArray = Java.array("byte", [0x46, 0x72, 0x69, 0x64, 0x61]);
    // 输出为: Frida
    console.log(Java.use("java.lang.String").$new(byteArray));
    
    // 构造char数组
    var charArray = Java.array("char", ["F", "r", "i", "d", "a"]);
    console.log(Java.use("java.lang.String").$new(charArray));
  });
}

setImmediate(main);

静态函数主动调用

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/staticFunction.js

function main() {
  Java.perform(function () {
    // setWebContentsDebuggingEnabled 需要在主线程调用
    Java.scheduleOnMainThread(function () {
      console.log("isMainThread", Java.isMainThread());
      // 主动触发静态函数调用, 允许WebView调试
      Java.use("android.webkit.WebView").setWebContentsDebuggingEnabled(true);
    });
  });
}

setImmediate(main);

动态函数主动调用

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/dynamicFunction.js

function main() {
  Java.perform(function () {
    Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", {
      onMatch: function (instance) {
        // 主动触发动态函数调用
        console.log("instance.isDebugEnabled: ", instance.isDebugEnabled());
        console.log("instance.getChannel: ", instance.getChannel());
      },
      onComplete: function () {},
    });
  });
}

setImmediate(main);

定义一个类

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/registerClass.js

function main() {
  Java.perform(function () {
    var TestRunnable = Java.registerClass({
        name: "com.example.TestRunnable",
        // 实现接口
        implements: [Java.use("java.lang.Runnable")],
        // 成员变量
        fields: {
          testFields: "java.lang.String",
        },
        methods: {
          // 构造函数
          $init: [
            {
              returnType: "void",
              argumentTypes: ["java.lang.String"],
              implementation: function (testFields) {
                // 调用父类构造函数
                this.$super.$init();
                // 给成员变量赋值
                this.testFields.value = testFields;
                console.log("$init: ", this.testFields.value);
              },
            },
          ],
          // 方法
          run: [
            {
              returnType: "void",
              implementation: function () {
                console.log(
                  "testFields: ",
                  this.testFields.value
                );
              },
            },
          ],
        },
      });
      
      TestRunnable.$new("simple test").run();
  });
}

setImmediate(main);

打印函数调用堆栈

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/printStackTrace.js

function main() {
  Java.perform(function () {
    Java.use(
      "com.growingio.android.sdk.autotrack.click.ViewClickInjector"
    ).viewOnClick.overload(
      "android.view.View$OnClickListener",
      "android.view.View"
    ).implementation = function (listener, view) {
      // 打印当前调用堆栈信息
      console.log(
        Java.use("android.util.Log").getStackTraceString(
          Java.use("java.lang.Throwable").$new()
        )
      );
      return this.viewOnClick(listener, view);
    };
  });
}

setImmediate(main);

枚举classLoader

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/enumerateClassLoaders.js
// 适用于加固的应用, 找到对应的classloader
// 通常直接在application.attach.overload('android.content.Context').implementation获取context对应的classloader

function main() {
  Java.perform(function () {
    Java.enumerateClassLoaders({
      onMatch: function (loader) {
        try {
          // 判断该loader中是否存在我们需要hook的类
          if (loader.findClass("com.growingio.android.sdk.CoreConfiguration")) {
            console.log("found loader:", loader);
            Java.classFactory.loader = loader;
          }
        } catch (error) {
          console.log("found error: ", error);
          console.log("failed loader: ", loader);
        }
      },
      onComplete: function () {
        console.log("enum completed!");
      },
    });
    console.log(
      Java.use("com.growingio.android.sdk.CoreConfiguration").$className
    );
  });
}

setImmediate(main);

枚举类

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/enumerateLoadedClasses.js

function main() {
  Java.perform(function () {
    Java.enumerateLoadedClasses({
      onMatch: function (name, handle) {
        // 判断是否是我们要查找的类
        if (name.toString() == "com.growingio.android.sdk.CoreConfiguration") {
          console.log("name, handle", name, handle);
          Java.use(name).isDebugEnabled.implementation = function () {
            return true;
          };
        }
      },
      onComplete: function () {},
    });
  });
}

setImmediate(main);

加载外部dex并通过gson打印对象

// 以attach的方式附加到进程, 或者使用setTimeout替换setImmediate
// frida -U -n demos -l agent/printObject.js
// 通过d8将 gson.jar 转为 classes.dex
// ~/Library/Android/sdk/build-tools/30.0.3/d8 --lib ~/Library/Android/sdk/platforms/android-30/android.jar gson-2.8.8.jar
// 如果SDK中已经有了, 可以直接使用Java.use加载
// adb push classes.dex /data/local/tmp 

function main() {
  Java.perform(function () {
    Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", {
      onMatch: function (instance) {
        // 加载外部dex
        Java.openClassFile("/data/local/tmp/classes.dex").load();
        var Gson = Java.use("com.google.gson.Gson")
        // JSON.stringify:  "<instance: com.growingio.android.sdk.autotrack.AutotrackConfiguration>"
        console.log("JSON.stringify: ", JSON.stringify(instance));
        // Gson.$new().toJson:  {"mImpressionScale":0.0,"mCellularDataLimit":10,"mDataCollectionEnabled":true,"mDataCollectionServerHost":"http://api.growingio.com","mDataUploadInterval":15,"mDebugEnabled":true,"mOaidEnabled":false,"mProjectId":"bfc5d6a3693a110d","mSessionInterval":30,"mUploadExceptionEnabled":false,"mUrlScheme":"growing.d80871b41ef40518"}
        console.log("Gson.$new().toJson: ", Gson.$new().toJson(instance));
      },
      onComplete: function () {},
    });
  });
}

setImmediate(main);

使用场景

  1. 绕过证书绑定、校验, 进行埋点请求验证

  2. SDK开发过程中, 一般客户反馈问题都需要使用客户的app进行问题的复现及排查, 此时通过frida获取运行时特定函数的参数信息及返回信息, 能有效缩短与客户的沟通时间, 该场景使用objection最为方便

  3. 新客户在集成前, 希望看到SDK能够提供的效果, 通过frida加载dex并完成初始化, 可以提前发现兼容性问题

  4. 当碰到集成早期版本SDK的应用反馈异常, 通过类似Tinker热修复的思想替换SDK验证是否已经在当前版本修复

  5. 开放SDK相关函数远程rpc调用, 用于测试埋点的协议等场景

外链地址

  1. Frida官方文档: https://frida.re/docs/installation/

  2. Frida作者提供的example github地址: https://github.com/oleavr/frida-agent-example

  3. JavaScript API官方文档: https://frida.re/docs/javascript-api/

  4. 功能介绍中所使用demo: https://github.com/growingio/growingio-sdk-android-autotracker

  5. r0capture 安卓应用层通杀脚本 github地址: https://github.com/r0ysue/r0capture

  6. objection github地址: https://github.com/sensepost/objection

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 10:58:28  更:2021-09-10 10:58:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:08:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码