尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【安卓逆向】Frida配置和简单hook

【安卓逆向】Frida配置和简单hook
📅 发布时间:2026/7/3 2:25:00

1. Frida 安装

  • 机型:小米6
  • frida-server版本:16.2.1
  • 下载列表:https://github.com/frida/frida/releases?page=13#release-16.2.1
  • 版本链接:https://github.com/frida/frida/releases/download/16.2.1/frida-server-16.2.1-android-arm64.xz

2. Python包安装

# 要与frida版本一致pipinstallfrida==16.2.1 frida-tools==12.0.0

3. Frida配置和启动服务

3.1 配置和启动服务

# 1. 将本地的 frida-server 文件推送到手机的 /data/local/tmp/ 目录adb push frida-server-16.2.1-android-arm64 /data/local/tmp/# 2. 进入手机的交互式命令行界面(shell)adb shell# 3. 切换到 root 用户(获取最高权限)su# 4. 进入存放 frida-server 的目录cd/data/local/tmp# 5. 修改文件权限为 755(即属主可读写执行,同组和其他人只可读执行)chmod755frida-server-16.2.1-android-arm64# 6. 在后台启动 frida-server./frida-server-16.2.1-android-arm64&

3.2 关闭服务

# 查看所有 frida 进程ps-A|grepfrida# 输出:root 26472 ... frida-server-16.2.1-android-arm64# 方式1:用完整名杀掉killallfrida-server-16.2.1-android-arm64# 方式2:用 pkill 模糊匹配pkill-ffrida-server# 方式3:用 PID 杀掉kill-926472# 验证是否已关闭ps-A|grepfrida# 没有输出 = 已关闭

[1] + Done表示后台进程已经正常结束。

4. hook模板

4.1 py部分

importfridaimportsysdefon_message(message,data):""" 消息处理回调函数 当 JavaScript 脚本调用 send() 时,会触发此函数 Args: message: 包含消息类型的字典 data: 附加数据 """# 如果是 send 发送的消息ifmessage["type"]=="send":print("[*] {0}".format(message["payload"]))# 如果是错误消息elifmessage["type"]=="error":print("[!] Error: {0}".format(message.get("stack",message)))# 读取 JavaScript Hook 脚本文件# mode="r": 只读模式# encoding="utf-8": 指定编码格式,支持中文withopen("lession2_test_hook_rps.js",mode="r",encoding="utf-8")asf:test_js=f.read()# ============================================# 方式一:启动应用之后附加(Attach 模式)# ============================================# 适用场景:应用已经在运行,需要动态注入try:# 获取通过 USB 连接的设备device=frida.get_usb_device()print("[*] Device: {0}".format(device))# 方法1:通过 PID 附加(推荐,更稳定)# windows下查看PID(adb shell "ps -A | grep rock_paper_scissors")PID=24201print("[*] Attaching to PID: {0}".format(PID))session=device.attach(PID)# 方法2:通过包名附加(需要应用在前台,注释掉了,因为我是用这种方法会失败)# session = device.attach("com.example.seccon2015.rock_paper_scissors")print("[✓] Attached!")# 创建脚本对象(将 JavaScript 代码加载到 Frida 中)script=session.create_script(test_js)# 注册消息回调script.on("message",on_message)# 注入并执行脚本script.load()print("[*] Script loaded! Click buttons on phone")print("[*] Press Ctrl+C to exit")# 阻塞主线程,保持脚本运行# 等待用户输入,按任意键退出sys.stdin.read()exceptExceptionase:print("[!] Error: {0}".format(e))# ============================================# 方式二:启动阶段注入(Spawn 模式)- 注释掉的代码# ============================================# 适用场景:应用未启动,需要在启动时就注入## device = frida.get_usb_device(-1) # -1 表示默认设备## # 启动应用(暂停在启动状态)# pid = device.spawn(["com.example.seccon2015.rock_paper_scissors"])## # 附加到新启动的进程# process = device.attach(pid)## # 创建并加载脚本# script = process.create_script(test_js)# script.on("message", on_message)# print("[*] Script loaded!")# script.load()## # 恢复应用执行(spawn 后应用是暂停状态)# device.resume(pid)## # 阻塞,使 hook 脚本不退出# sys.stdin.read()

4.2 js模板

/** * Frida Hook 脚本模板 * 用于 Hook Android Java 方法 */// Java.perform 是 Frida 的入口函数,确保代码在 Java 虚拟机上下文中执行Java.perform(function(){console.log('start hook...');// ============================================// 1. 获取目标类// ============================================// Java.use() 获取 Java 类的引用varMainActivity=Java.use("com.example.seccon2015.rock_paper_scissors.MainActivity");// ============================================// 2. Hook 方法// ============================================// 重写 onClick 方法// v: 方法参数MainActivity.onClick.implementation=function(v){// 调用原始方法(Frida 会自动保留原始方法引用,不会递归)this.onClick(v);// TODO: 在这里添加 Hook 逻辑// 例如:打印参数、修改返回值等};// ============================================// 3. Hook 内部类// ============================================// 内部类使用 $ 连接,如 MainActivity$1varMainActivity1=Java.use("com.example.seccon2015.rock_paper_scissors.MainActivity$1");// 重写 run 方法MainActivity1.run.implementation=function(){// TODO: 在这里添加 Hook 逻辑// 调用原始方法this.run();};});

4.3 js示例

/** * Frida Hook 脚本 - 剪刀石头布游戏 * 目标:通过修改 CPU 的出拳逻辑,让玩家总是获胜 * 包名:com.example.seccon2015.rock_paper_scissors */// Java.perform 是 Frida 的入口函数// 确保所有 Java 相关操作在 Java 虚拟机环境中执行Java.perform(function(){console.log('start hook...');// ============================================================// 1. Hook MainActivity 的 onClick 方法(玩家点击按钮时触发)// ============================================================// Java.use() 获取 Java 类的引用,返回一个包装对象varMainActivity=Java.use("com.example.seccon2015.rock_paper_scissors.MainActivity");/** * 重写 onClick 方法 * @param {View} v - 被点击的按钮视图(P/R/S 按钮) * * 注意:这里不会发生递归! * this.onClick(v) 调用的是 Frida 内部保留的原始方法 * 而不是当前重写的 implementation,这是 Frida 的设计机制 */MainActivity.onClick.implementation=function(v){// 1. 调用原始 onClick 方法,保证游戏正常运行// 包括:记录玩家选择、生成 CPU 选择、触发延迟显示等this.onClick(v);// 2. 打印玩家的选择// m: 玩家的出拳 (0=布 Paper, 1=石头 Rock, 2=剪刀 Scissors)console.log('[Hook] m',this.m.value);// 3. 打印 CPU 的选择// n: CPU 的出拳 (0=布 Paper, 1=石头 Rock, 2=剪刀 Scissors)console.log('[Hook] n real',this.n.value);// ============================================================// 4. 胜负判定(与原始代码逻辑一致)// 规则:布(0) > 石头(1) > 剪刀(2) > 布(0)// ============================================================// 情况1:CPU 出拳数值 - 玩家出拳数值 == 1// 例如:玩家出布(0),CPU出石头(1) → 玩家赢// 玩家出石头(1),CPU出剪刀(2) → 玩家赢// 玩家出剪刀(2),CPU出布(0) → 此时差值为 -2,不满足此条件if(this.n.value-this.m.value==1){console.log('[Hook] You win!');}// 情况2:玩家出拳数值 - CPU 出拳数值 == 1// 例如:玩家出石头(1),CPU出布(0) → CPU赢// 玩家出剪刀(2),CPU出石头(1) → CPU赢elseif(this.m.value-this.n.value==1){console.log('[Hook] You lose!');}// 情况3:玩家和 CPU 出拳相同 → 平局elseif(this.m.value==this.n.value){console.log('[Hook] Draw!');}// 情况4:玩家出拳数值小于 CPU 出拳数值// 例如:玩家出布(0),CPU出剪刀(2) → CPU赢elseif(this.m.value<this.n.value){console.log('[Hook] You lose!');}// 情况5:其他情况 → 玩家赢// 例如:玩家出剪刀(2),CPU出布(0) → 玩家赢else{console.log('[Hook] You win!');}};// ============================================================// 2. Hook 内部类 MainActivity$1 的 run 方法// MainActivity$1 是 MainActivity 中的匿名内部类// 实现了 Runnable 接口,用于延迟 1 秒后显示游戏结果// ============================================================varMainActivity1=Java.use("com.example.seccon2015.rock_paper_scissors.MainActivity$1");/** * 重写 run 方法 * 核心破解逻辑:修改 CPU 的出拳,让玩家总是赢 * * 注意:这里同样不会发生递归! * this.run() 调用的是原始 run 方法,不是重写后的 implementation */MainActivity1.run.implementation=function(){console.log('[Hook] run');// ============================================================// 关键破解逻辑:修改 CPU 的出拳// ============================================================// this.this$0 是内部类持有的外部类 MainActivity 的引用// 通过 this.this$0 可以访问外部类的成员变量//// 将 CPU 的出拳(n) 设置为 玩家的出拳(m) + 1// 使得 CPU 总是出会被玩家打败的选项:// 玩家出布(0) → CPU出石头(1) → 布包裹石头 → 玩家赢// 玩家出石头(1) → CPU出剪刀(2) → 石头砸剪刀 → 玩家赢// 玩家出剪刀(2) → CPU出布(0) → 剪刀剪布 → 玩家赢// 注意:当 m=2 时,m+1=3,但数组索引只有 0-2// 实际游戏中,3 会被映射为剪刀 vs 布的逻辑,需要看原始代码如何处理this.this$0.value.n.value=this.this$0.value.m.value+1;console.log('[Hook] n change',this.this$0.value.n.value);// 调用原始的 run 方法,显示游戏结果// 此时 n 已经被修改,所以显示的结果是玩家赢this.run();};});

感谢关注【遇事不決洛必達】!欢迎点赞收藏和交流指正,我会持续分享我的学习经验和心得。

相关新闻

  • Vite 包体分析:构建快之后,还要看用户下载了什么
  • 星舰“新大陆号”曲率引擎与动力系统技术白皮书(V3.0 FINAL)
  • 2026手机抠图工具实操指南:人像物品背景去除,安卓苹果免费软件整理

最新新闻

  • MuleSoft实现企业级AI编排:LLM与ERP/CRM/SAP的可靠集成
  • utshell核心功能解析:如何实现Bash、Korn和C shell的完美整合
  • 5个大模型写Todo List实测:前端代码生成能力深度拆解
  • Kimi K2.5:可调度AI协作者系统如何驱动工作模式变革
  • AI数据采集实战:从爬虫基础到分布式架构
  • PyTorch 训练稳定性:梯度爆炸前通常有征兆

日新闻

  • JMeter接口测试实战:从核心元件到复杂场景构建
  • Java Applet版刽子手游戏源码:含完整项目结构、吊杆绘图与胜负逻辑
  • 使用Apache JMeter对RoadRunner PHP应用进行性能测试与调优指南

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号