15. Frida 入门与实战教程:动态 Hook 与逆向分析全面指南

1 frida介绍

Frida 是一个强大的动态二进制插桩(dynamic instrumentation)工具,主要用于逆向工程、安全研究、App 调试和分析等领域。

它允许你在运行时对本地应用程序(包括 Android、iOS、Windows、macOS、Linux 的原生和托管程序)进行动态修改或观察,无需修改原始二进制。

其主要功能如下:

  • 动态 Hook:可以在运行时 hook 任何函数(Java, native C/C++, Obj-C)
  • 跨平台支持*:支持 Android、iOS、Windows、Linux、macOS 等平台
  • 无须 Root/Jailbreak(可选):有些场景下 Frida 可以在无 root 环境下工作(需绕过限制)
  • 脚本化 :支持 JavaScript 和 Python 编写 hook 脚本
  • 远程调试 :可连接远程设备并注入目标程序进行分析

运行原理:

+--------------+         +------------------+
| 你写的脚本(JS/Py) |<=====>|  Frida Server (on target) |
+--------------+         +------------------+
        |                        |
        |------ Hook ----------->|
        |<---- Data / Log -------|

本文将一步步带你了解这个工具的安装与基本使用。

2 frida安装

我目前使用的是Windows系统,因此本文也将以windows系统作为示例进行讲解。且为了方便,安卓系统用的是模拟器,并不是真机。

首先我们需要下载Frida,而Frida的下载,可以通过python工具pip完成。

所以推荐你先去安装python环境:Welcome to Python.org

安装完python后,在终端输入命令:pip install frida-tools,进行安装。

安装完成后,可以输入命令:frida --version,来输出版本,看是否成功安装:

image-20231026164133014

完成后,我们还需要能够安卓开发调试工具包,如果你已经安装了Android Studio,则已经有该工具包了,如果没有,可以直接下载:platform-tools-windows

下载完成后,是一个压缩包,将其解压,然后放在你觉得比较稳妥的位置,最后将其路径添加到环境变量中即可。

不知道什么是环境变量的可以参考另一篇文章;程序员必懂的常识

将其路径添加到用户环境变量、PATH变量下即可。

添加完成后,直接输入命令:adb,打印出相关的帮助信息,则说明你已经操作完成:

image-20231026164955542

然后还需要去下载逍遥模拟器:逍遥安卓模拟器_

这个很简单直接下载安装即可,安装完成后,打开它,然后打开root权限:

image-20231026165215481

一般默认就是打开的,就不用管,然后还要打开开发者模式,首先找到设置

image-20231026165408809

这个设置可能放在了系统应用框中,点击它打开即可。

然后直接顶部搜索:关于平板电脑

image-20231026165616713

点进去,翻到最下面,多次点击版本号:

image-20231026165701075

直到它弹出提示:你已经处于开发者模式。

然后搜索:开发者选项

image-20231026165756528

打开USB调试:

image-20231026165819210

然后我们就可以回到终端,输入命令:adb kill-server,先关闭这个调试服务。

然后就可以连接我们的安卓模拟器了:adb connect 127.0.0.1:21503

image-20231026170058224

注意,逍遥模拟器虚拟设备默认端口为21503,并且目前处于局域网,所以链接为上面那个,如果有多个设备,那么每增加一个设备,端口号就会增加10,如果有第二个虚拟设备,那么端口号就是21513了。

然后进入安卓的终端:adb shell

输入命令:getprop ro.product.cpu.abi,查看安卓的架构信息。

最后退出:exit

image-20231026170444171

比如我这里输出的是x86_64,那么要记住这个名字。

去官网:Releases · frida/frida (github.com)下载相应的服务器:

image-20231026170628575

一般直接选择最新的即可,因为前面pip安装是安装的也是最新的。

下载下来先解压,然后你可以将其重新命名,方便后面使用,我这里只保留了前面的frida-server

然后将这个文件传到安卓模拟器中:

adb push D:\Download\frida-server-16.1.4-android-x86_64\frida-server /data/local/tmp

注意,前面的D:\Download\frida-server-16.1.4-android-x86_64\frida-server是我下载解压后保存在我电脑上的路径,你需要更换成你的。

然后再次打开模拟器终端:adb shell

进入上面文件保存到的安卓系统路径:cd /data/local/tmp

更改这个文件的权限:chmod 777 frida-server

然后运行这个文件:./frida-server

image-20231026171138587

至此,我们环境就搭建完成,你可以再开启一个终端,输入命令:frida-ps -U,来验证其是否成功:

image-20231026171250200

这个命令是用来输出当前安卓系统中所有进程信息的,能获取并输出,则说明环境已经陈功搭建。

3 frida开发环境搭建

使用frida工具进行开发工作时,最简洁易用的便是js,所以这里介绍一下如何搭建它的开发环境。

没有代码提示写js是一件很痛苦的事情,因此最终实现的效果就是:

  1. 有代码提示信息
  2. 可以分模块开发

编辑器使用的vscode,如何安装就不多说了,除此之外还需要node环境,没有的可以直接点击这里去官方下载安装。

安装好node后,先自己新建一个文件夹,比如我这里名字为FridaEnv,然后从终端进入这个文件夹,使用npm初始化这个文件夹,命令为npm init

image-20231104200030773

后面会让选择很多东西,不用管,直接一直按Enter即可,即默认选项。

紧接着就是安装frida代码提示的包:npm i @types/frida-gum

image-20231104200258814

js代码本身是没有类型提示的,很多时候看不到函数参数用起来很麻烦,所以我们还可以安装一下TypeScript,它的使用与JavaScript基本一样,但它有类型提示,用起来更加舒服。

安装命令为:npm i ts-loader typescript -D

image-20231104200910900

后面的-D意思是只在开发环境下使用它。

因为其工作原理是将TypeScript代码重新编译成为JavaScript代码,我们最终运行的依旧只能是js代码,所以最后的结果是不需要这两个包的。

每次自己手动编译也很麻烦,所以还需要一个webpack工具,它可以将这一个过程自动化。

不仅如此,它更强大的作用其实是可以让我们分模块开发不同功能的代码,然后最后将其打包成为一个js文件。

安装命令为:npm i webpack webpack-cli -D

image-20231104201237763

安装完成后,输入code .,用vscode打开这个文件夹,新建一个文件webpack.config.js,这是打包工具webpack的配置文件,我们需要用它来配置一些选项:

const path = require("path");
module.exports = {
    mode: "production",
    entry: './entry.ts', //入口文件,从项目根目录指定
    module:{
        rules:[
            {
                test:/\.tsx?$/,
                use:'ts-loader',
                exclude:/node_modules/
            },
        ]
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
      },
    output: {
        path: path.resolve(__dirname, "."), //将js文件直接打包到根目录
        filename: "script.js" //打包到script.js文件中
    },
    watch: true
}

具体有哪些选项,或者这些选项有什么作用,可以去其官网查看:webpack

此时项目结构如下:

image-20231104201757663

然后TypeScript也需要一个配置文件,名字为tsconfig.json,内容如下:

{
    "compilerOptions": {
      "target": "es2016", 
      "module": "commonjs",
       "outDir": "./dist/",
      "esModuleInterop": true,
      "forceConsistentCasingInFileNames": true,
      "strict": true,
    },
    "files": ["entry.ts"]
}

更多参数、或者其含义,可以去官网查看:TypeScript,此时项目结构如下:

image-20231104202344561

它报错了,原因是这里我填入的入口文件没有创建,在根目录创建一个即可,这个文件便是后面我们写代码的主文件了:

image-20231104202711963

然后进入这个包管理文件,写一个脚本命令,让webpack能够实时监视我们的目录变化,自动编译:

  "scripts": {
    "watch": "webpack --config webpack.config.js"
  },

自此,我们的环境就搭建好了。

现在来使用一下试一试,比如frida提供了一个Java的类:

image-20231104202946187

可以看到,此时它就能自动列出所有可用的函数与类了。

然后还有自动编译代码的功能,现在运行命令:npm run watch

image-20231104203238925

此时只要你在entry.ts文件中写的任何代码,都会被实时编译到script.js文件中去,并且还会进行优化:

image-20231104203400325