技术分享 | Frida 实现 Hook 功能的强大能力
本文节选自霍格沃兹测试学院内部教材
Frida 通过 C 语言将 QuickJS 注入到目标进程中,获取完整的内存操作权限,达到在程序运行时实时地插入额外代码和数据的目的。官方将调用代码封装为 python 库,当然你也可以直接通过其他的语言调用 Frida 中的 C 语言代码进行操作。
Frida 安装和启动
电脑端 Frida 安装 Frida 支持 python2 和 python3 版本,演示所使用的版本为 python3.8pip install frida-tools 如果在安装中卡住,需要在 Frida 的 pypi 页面下载对应系统的 egg 文件,对应页面地址为:frida · PyPI ,并将该文件放置到个人文件夹路径下,例如 C:\Users\当前用户名 ,再重新使用命令安装。安装完毕后可以通过命令 frida --version 来查看安装的版本,确认是否安装成功。手机端 Frida-server 安装本次示例使用 Android App 作为目标程序,所以需要电脑端安装 SDK 环境,以便能够连接手机进行调试操作,还需在手机端准备一个 Frida-server,下载地址为:https://github.com/frida/frida/releases,下载匹配手机 CPU 架构和本地 Frida 版本的包。下载之后解压文件,使用 adb push 命令将文件推送到手机端,建议放置在/data/local/tmp 文件夹中,并修改该文件的权限为 755,以便之后进行启动。确认环境运行正常通过 Frida 提供的一些小工具,对 Frida 的安装运行环境做简单的确认。首先准备一个 Android 模拟器或者真机,将上一步中提到的 Frida-server 推送到手机端中,在本示例中将放置在手机的/data/local/tmp 文件夹内,并将文件命名为 frida-server 。通过 adb shell 命令连接手机,运行/data/local/tmp/frida-server & ,将 Frida-server 放在系统后台自动运行。在本地电脑终端中运行 frida-ps -U ,结果如下展示手机中的进程信息,说明环境已经准备完毕。PID Name
1313 adbd
12621 android.process.acore
18037 android.process.media
14455 com.android.defcontainer
11656 com.android.deskclock
...示例目标应用介绍
因为 Hook 需要通过分析源码中的逻辑来实现,所以先展示一下目标应用的源码部分,方便分析其中的逻辑,找到 Hook 时要修改的方法和变量。代码是简单的猜黑白游戏,通过按下黑或白按钮,与电脑结果进行对比,结果相同加 1 分,结果不同分数清零,当满 100 分时打出胜利提示语。具体代码如下:package com.example.target_frida;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
}Hook 需求分析
由于正常情况下,连赢 100 次的概率几乎为零,如果想要达到胜利条件,Hook 就是一个比较好的方式。首先分析一下源码,想要达到连赢 100 次的情况,可以有两种解决办法:一种是通过修改用来记录连赢次数的变量 winCount ,将连赢记录改成 99,这样只需要再赢一次就可以获得胜利;还有一种是通过修改 getCPUResult 方法的返回值,让其固定返回一种可能性,这样只需要选择对应的颜色就可以连续获胜。接下来通过实现第一个方案,看看使用 Frida 如何达到想要的效果。第一种实现:修改结果变量中保存的值首先展示修改代码,然后再进行逐步讲解:import time
import frida, sys
date_str = time.strftime('%m-%d %H:%M:%S')
def on_message(message, data):
def run_all():
Java.perform 方法:当 js 附加到目标的进程中时被执行,运行其中定义的函数
Java.choose 方法:通过完整类名,获取它的实例,从而对实例中的数据进行修改
通过 key:value 结构定义了两个函数:
onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例
onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作
if name == 'main':
代码中的 python 语句已经添加了注释,Hook 的核心逻辑,JS 语句作为字符串保存在 jscode 变量中。梳理一下整个 JS 语句的流程:通过 Java.choose 函数获取 com.example.target_frida.MainActivity 类的实例。在获取到实例时,首先使用 console.log 语句将当前实例中的 winCount 变量值(使用 winCount.value)打印到日志中,之后直接通过赋值语句把变量值改为 99,再次输出日志确认修改无误,修改逻辑就完成了。在手机端启动 Frida-server 和被测 App,电脑端运行脚本,可以看到在命令行中输出如下内容:[04-15 18:19:57] Start Frida on com.example.target_frida
winCount value is 0
winCount value is 99
Complete!!!这时在 App 中选择一个颜色点击,只要选中正确的颜色,就可以成功达到预期的 100 次连胜目标,如果没能选中正确的颜色导致清零,可以再重复运行脚本修改一次数值,在这种情况下要达到预期的场景就很容易。总结第二个方案以及其他更多的可能性,就留给读者自行探索,在这里送上 Frida 官方 JavaScript API 链接:JavaScript API | Frida • A world-class dynamic instrumentation framework ,可以通过这个链接找到你所需要的 JS 函数。
通过示例可以看到 Frida 实现 Hook 功能的强大能力,它可以定位到类的实例,并且对实例中的数据进行直接的修改,达到场景构建的目的。
免费领取:性能测试+接口测试+自动化测试+测试开发+测试用例+简历模板+测试文档
http://qrcode.testing-studio.com/f?from=infoQ&url=https://ceshiren.com/t/topic/16565
评论