├── .gitignore ├── .vscode └── launch.json ├── CHANGELOG ├── LICENSE ├── Makefile ├── README.md ├── autoinstall.sh ├── docs ├── android.md ├── install.md ├── ios.md └── patch-tools.md ├── fridare.sh ├── hexreplace ├── Makefile ├── go.mod ├── go.sum └── main.go ├── screenshots ├── 1.png ├── 2.png ├── 3.png ├── 555354813.jpg └── md5.png ├── toolkit ├── generate_frida_modules.py ├── manifest.txt └── merge.py └── win ├── README.md ├── hexreplace_windows_amd64.exe ├── patch-frida-tools.cmd └── patch-frida.cmd /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,macos 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | frida-server 14 | [Tt]est?/ 15 | [Bb]uild/ 16 | [Dd]ist/ 17 | [Pp]atched/ 18 | # [Tt]oolkit/ 19 | 20 | # Thumbnails 21 | ._* 22 | 23 | # Files that might appear in the root of a volume 24 | .DocumentRevisions-V100 25 | .fseventsd 26 | .Spotlight-V100 27 | .TemporaryItems 28 | .Trashes 29 | .VolumeIcon.icns 30 | .com.apple.timemachine.donotpresent 31 | 32 | # Directories potentially created on remote AFP share 33 | .AppleDB 34 | .AppleDesktop 35 | Network Trash Folder 36 | Temporary Items 37 | .apdisk 38 | 39 | ### macOS Patch ### 40 | # iCloud generated files 41 | *.icloud 42 | 43 | ### VisualStudioCode ### 44 | .vscode/* 45 | !.vscode/settings.json 46 | !.vscode/tasks.json 47 | !.vscode/launch.json 48 | !.vscode/extensions.json 49 | !.vscode/*.code-snippets 50 | 51 | # Local History for Visual Studio Code 52 | .history/ 53 | 54 | # Built Visual Studio Code Extensions 55 | *.vsix 56 | 57 | ### VisualStudioCode Patch ### 58 | # Ignore all local history of files 59 | .history 60 | .ionide 61 | 62 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,macos 63 | 64 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 65 | 66 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}/hexreplace/main.go", 13 | "cwd": "${workspaceFolder}/hexreplace", 14 | "args": [ 15 | "patched/16.4.3/android/arm64/frida-server-16.4.3-android-arm64", 16 | "abcde", 17 | "test-server-android-arm64" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 所有值得注意的更改都将记录在此文件中。 3 | 格式基于 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。 4 | 5 | ## v3.1.2 - 2024-07-17 6 | 7 | ### Added 8 | - 增加对多平台的支持:现在支持 `macOS`、`iOS`、`Android`、`Linux` 和 `Windows` 9 | - 新增 `upgrade` 命令:用于自动更新 Fridare 脚本 10 | - 新增一键安装功能: 11 | ```shell 12 | curl -s https://raw.githubusercontent.com/suifei/fridare/main/fridare.sh | bash -s install 13 | ``` 14 | 15 | ### Changed 16 | - 优化版本检查和更新流程 17 | 18 | ### Fixed 19 | - 修复了在 Windows 系统上无法正确识别和安装 Frida 工具的问题 20 | - 修复了在 macOS 系统上无法正确下载 Frida 工具的问题 21 | 22 | ### Other Changes 23 | - 更新版本号至 3.1.2 24 | - 代码重构和优化,提高整体性能和稳定性 25 | 26 | ## [3.1.0] - 2024-07-16 27 | ### Added 28 | - 增加了 `patch` 命令,用于修补指定的 Frida 模块 29 | - 增加了对 `patch` 命令的帮助信息 30 | - 增加对 ELF 和 PE 文件格式的支持(支持 Windows,Linux,MacOS,Android,IOS) 31 | 32 | ### Changed 33 | - 更新了 `build`、`download` 等命令的用法说明 34 | 35 | ### Fixed 36 | - 修复了一些小的 Bug 并改进了脚本的稳定性 37 | 38 | 39 | ## [3.0.1] - 2024-07-11 40 | ### Added 41 | - 新增 `is_conda_env()` 函数用于检测 Conda 环境 42 | - 新增 `get_python_cmd()` 函数用于选择正确的 Python 解释器 43 | - 新增 `log_environment_info()` 函数,详细输出运行环境信息 44 | 45 | ### Changed 46 | - 重构 `modify_frida_tools()` 函数,以支持 Conda 环境 47 | - 优化 Golang 环境检查,利用现有的 `check_and_install_tool` 函数 48 | - 更新 `build_frida` 函数,简化 Golang 环境检查 49 | - 改进环境检测逻辑,优先使用 Conda 环境中的 Python 50 | 51 | ### Fixed 52 | - 修复在 Conda 环境中无法正确识别和修改 Frida 工具的问题 53 | - 解决多个 Python 环境共存时的兼容性问题 54 | 55 | ### Improved 56 | - 提升脚本对不同 Python 环境的适应性 57 | - 增强环境信息输出,便于调试和问题排查 58 | - 简化用户使用流程,无需手动指定 Frida 工具路径 59 | 60 | ## [3.0.0] - 2024-07-11 61 | ### Added 62 | - 新增 `fridare.sh` 脚本,整合所有功能,提供更完整的命令行界面 63 | - 新增 `build`, `ls`, `download`, `lm`, `setup`, `config`, 和 `help` 命令 64 | - 新增配置文件支持,可以保存和加载用户设置 65 | - 新增颜色输出,提升用户体验 66 | - 新增自动检查和安装依赖功能 67 | - 新增下载特定 Frida 模块的功能 68 | - 新增列出可用 Frida 版本和模块的功能 69 | 70 | ### Changed 71 | - 重构了整个项目结构,提高代码可维护性 72 | - 改进了错误处理和日志输出 73 | - 优化了 Frida 构建过程,提高效率 74 | - 更新了二进制修改逻辑,提高兼容性 75 | 76 | ### Removed 77 | - 移除了旧的 `build.sh` 脚本 78 | 79 | ## [2.2.0] - 2024-07-04 80 | ### Added 81 | - 新增加 frida-tools 补丁,适配 `frida:rpc` 特征魔改 82 | - 解决 Android 内存扫描该字符串问题 83 | - 自动扫描本地 pip 安装 frida-tools 的位置,对 `core.py` 文件进行魔改,对 `_frida.abi3.so` 文件进行魔改 84 | - 新增加 frida-agent.dylib 魔改,从文件名称,加载位置进行隐藏 85 | - 解决 agent 加载未隐藏问题 86 | 87 | ## [2.1.1] - 2024-06-26 88 | ### Changed 89 | - 修正了二进制替换可能失败的问题。 90 | 91 | ## [2.1] - 2024-06-26 92 | ### Added 93 | - 新增 `autoinstall.sh` 脚本,结合 `issh` 命令自动部署最新 Frida 插件版本。 94 | - 新增 `Makefile`,提供帮助、清理、构建和部署项目的便捷命令。 95 | 96 | ### Changed 97 | - 更新 `build.sh` 脚本,以支持新脚本和 Makefile 的集成。 98 | - 增强了错误处理和日志记录,改善用户体验。 99 | 100 | ### Fixed 101 | - 修正了在特定情况下二进制替换可能失败的问题。 102 | 103 | ## [2.0] - 2024-06-25 104 | ### Added 105 | - 支持多种架构,增加更多的 ARM 和 ARM64 子类型。 106 | - 增加了更多的替换项。 107 | - `macho.File.Section()` 现在返回一个指向 `macho.Section` 的指针。 108 | - 增加了更多的错误处理。 109 | 110 | ## 1.0 - 初始版本 111 | - 初始发布,提供了修改和定制 Frida 服务器的基本功能。 112 | 113 | # Change Log 114 | All notable changes to this project will be documented in this file. 115 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 116 | 117 | ## [3.1.0] - 2024-07-16 118 | ### Added 119 | - Added `patch` command to patch specified Frida modules 120 | - Added help information for `patch` command 121 | - Added support for ELF and PE file formats 122 | 123 | ### Changed 124 | - Updated usage instructions for `build`, `download`, and other commands 125 | 126 | ### Fixed 127 | - Fixed minor bugs and improved script stability 128 | 129 | ## [3.0.1] - 2024-07-11 130 | ### Added 131 | - Added the `is_conda_env()` function for detecting Conda environments 132 | - Added the `get_python_cmd()` function for selecting the correct Python interpreter 133 | - Added the `log_environment_info()` function to output detailed information about the running environment 134 | 135 | ### Changed 136 | - Refactored the `modify_frida_tools()` function to support Conda environments 137 | - Optimized the Golang environment check by utilizing the existing `check_and_install_tool` function 138 | - Updated the `build_frida` function to simplify the Golang environment check 139 | - Improved the environment detection logic to prioritize the use of Python in the Conda environment 140 | 141 | ### Fixed 142 | - Fixed the issue where Frida tools could not be correctly identified and modified in Conda environments 143 | - Resolved compatibility issues when multiple Python environments coexist 144 | 145 | ### Improved 146 | - Enhanced the script's adaptability to different Python environments 147 | - Enhanced the output of environment information for easier debugging and troubleshooting 148 | - Simplified the user process, eliminating the need to manually specify the path to Frida tools 149 | 150 | ## [3.0.0] - 2024-07-11 151 | ### Added 152 | - add `fridare.sh` script, integrate all functions, provide a more complete command line interface 153 | - add `build`, `ls`, `download`, `lm`, `setup`, `config`, and `help` commands 154 | - add configuration file support, can save and load user settings 155 | - add color output, improve user experience 156 | - add automatic dependency check and installation 157 | - add download specific Frida module 158 | - add list available Frida versions and modules 159 | 160 | ### Changed 161 | - refactor the entire project structure, improve code maintainability 162 | - improve error handling and log output 163 | - optimize Frida build process, improve efficiency 164 | - update binary modification logic, improve compatibility 165 | 166 | ### Removed 167 | - remove old `build.sh` script 168 | 169 | ### Changed 170 | 171 | ## [2.2.0] - 2024-07-04 172 | ### Added 173 | - add frida-tools patch, adapt to `frida:rpc` feature modification 174 | - solve the problem of scanning this string in Android memory 175 | - automatically scan the location of the locally installed pip frida-tools, modify the `core.py` file, and modify the `_frida.abi3.so` file 176 | - add frida-agent.dylib modification, hide from file name and loading location 177 | - solve the problem of agent loading not hidden 178 | 179 | ## [2.1.1] - 2024-06-26 180 | ### Changed 181 | - fix the issue that binary replacement may fail in specific cases. 182 | 183 | ## [2.1] - 2024-06-26 184 | ### Added 185 | - add `autoinstall.sh` script, auto deploy the latest Frida plugin version with `issh` command 186 | - add `Makefile`, provide convenient commands for help, clean, build and deploy the project 187 | 188 | ### Changed 189 | - update `build.sh` script to support the integration of new scripts and Makefile 190 | - enhance error handling and log recording, improve user experience 191 | 192 | ### Fixed 193 | - fix the issue that binary replacement may fail in specific cases 194 | ## [2.0] - 2024-06-25 195 | 196 | ### Added 197 | - support multiple architectures, add more ARM and ARM64 subtypes 198 | - add more replacements 199 | - `macho.File.Section()` returns a pointer to `macho.Section` 200 | - add more error handling 201 | 202 | ## 1.0 - Initial Version 203 | - initial release, provide basic functions to modify and customize Frida server 204 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 SuiFei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help clean build deploy 2 | 3 | help: 4 | @echo "make help - Show this help" 5 | @echo "make clean - Clean the project" 6 | @echo "make deploy - Deploy the project" 7 | @echo "make build - Build the project" 8 | 9 | clean: 10 | @rm -rf dist 11 | 12 | build: 13 | @./fridare.sh build -latest -y 14 | 15 | deploy: 16 | ./autoinstall.sh 17 | @echo "Please run 'frida -H :8899 -F' to connect to the device" 18 | 19 | all: clean build deploy -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fridare 2 | 3 | [English](#Features) | [中文](#特性) 4 | 5 | [![GitHub Streak](https://streak-stats.demolab.com?user=suifei&theme=dark&locale=zh_Hans&date_format=%5BY.%5Dn.j)](https://git.io/streak-stats) 6 | QQ群二维码 7 | 8 | ![Github stars](https://img.shields.io/github/stars/suifei/fridare?style=social) 9 | ![Github forks](https://img.shields.io/github/forks/suifei/fridare?style=social) 10 | ![Github watchers](https://img.shields.io/github/watchers/suifei/fridare?style=social) 11 | ![Github license](https://img.shields.io/github/license/suifei/fridare) 12 | ![Github issues](https://img.shields.io/github/issues/suifei/fridare) 13 | ![Github pull requests](https://img.shields.io/github/issues-pr/suifei/fridare) 14 | ![Github contributors](https://img.shields.io/github/contributors/suifei/fridare) 15 | ![Github last commit](https://img.shields.io/github/last-commit/suifei/fridare) 16 | ![Github repo size](https://img.shields.io/github/repo-size/suifei/fridare) 17 | ![Github code size](https://img.shields.io/github/languages/code-size/suifei/fridare) 18 | ![Github language count](https://img.shields.io/github/languages/count/suifei/fridare) 19 | ![Github top language](https://img.shields.io/github/languages/top/suifei/fridare) 20 | ![Github tag](https://img.shields.io/github/v/tag/suifei/fridare) 21 | [![GitHub followers](https://img.shields.io/github/followers/suifei.svg?style=social&label=Follow&maxAge=2592000)](https://github.com/suifei?tab=followers) 22 | [![Twitter Follow](https://img.shields.io/twitter/follow/csuifei?style=social)](https://twitter.com/csuifei) 23 | 24 | Fridare 是一个用于 iOS frida 插件、Android,linux,Windows 等平台 frida-server 的自动化魔改工具。它允许用户更改名称和端口,以增强安全性和灵活性。免除了很多越狱检测frida的情况。 25 | 26 | **[Windows 下使用](win/README.md)|[Android 文档](docs/android.md)|[iOS 文档](docs/ios.md)|[frida-tools 文档](docs/patch-tools.md)|[安装指北](docs/install.md)|[CHANGELOG](CHANGELOG)** 27 | 28 | 欢迎大家入QQ群讨论:[QQ 555354813](screenshots/555354813.jpg) ,如本项目对你有所帮助,记得给作者加星鼓励哦! 29 | 30 | ## 特性 31 | 32 | - 自动下载并修改指定版本的 frida-server 33 | - 随机生成新的 frida-server 名称 34 | - 自定义 frida-server 端口 35 | - 支持 arm 和 arm64 架构 36 | - 二进制替换修改 37 | - frida-server 38 | - frida-agent.dylib 39 | - frida-tools 40 | - 生成可直接安装的修改版 .deb 包 41 | - 一体化命令行界面,提供多种功能 42 | - 配置文件支持,可保存用户设置 43 | - 自动检查和安装依赖 44 | - 下载特定 Frida 模块 45 | - 列出可用 Frida 版本和模块 46 | - 支持 Conda 环境 47 | - 支持 macho, elf, pe 文件格式 48 | - 支持 Windows,Linux,MacOS,Android,IOS 的patch 49 | - 支持自更新 50 | 51 | 欢迎使用新的一键安装功能快速开始使用 Fridare! 52 | 53 | ```shell 54 | curl -s https://raw.githubusercontent.com/suifei/fridare/main/fridare.sh | bash -s install 55 | ``` 56 | 57 | ## [v3.1.5] - 2024-07-29 Windows 支持 58 | 59 | ### Added 60 | - 新增 `patch-frida.cmd` 脚本,用于在 Windows 环境下修改 frida-server 61 | - 新增 `patch-frida-tools.cmd` 脚本,用于在 Windows 环境下修改 frida-tools 62 | - 增加对 Windows 平台的全面支持 63 | - 更新了使用说明,增加了 Windows 平台的详细教程 64 | 65 | ## [v3.1.4] - 2024-07-18 66 | 67 | ### Added 68 | - 增加 `patch-tools` 命令,用于修补 frida-tools 模块 69 | - 新增 `render_markdown` 函数,用于在终端中渲染简单的 Markdown 格式 70 | - 添加 `generate_random_name` 函数,用于生成随机的 Frida 魔改名 71 | - 实现 `move_file` 函数,用于处理文件移动时的 "are identical" 错误 72 | 73 | ### Improved 74 | - 优化 `list_frida_versions` 函数,现在能够渲染 Markdown 格式的版本说明 75 | - 改进 `build_frida` 函数,支持使用本地 deb 文件进行构建 76 | - 增强 `patch_frida_tools` 和 `restore_frida_tools` 函数的功能和错误处理 77 | - 优化 `modify_frida_tools` 函数,提高修改 frida-tools 的可靠性 78 | - 改进 `download_frida_module` 函数,增加对特定操作系统和架构的支持 79 | 80 | ### Fixed 81 | - 修复了在某些情况下无法正确获取 Frida 路径的问题 82 | - 解决了移动文件时可能遇到的 "are identical" 错误 83 | 84 | ### Changed 85 | - 更新 `show_main_usage` 和其他使用说明函数,以反映新增的功能 86 | - 调整 `parse_arguments` 函数,支持新增的 `patch-tools` 命令 87 | - 修改配置文件的处理方式,增加了对 `FRIDA_NAME` 的支持 88 | 89 | ### Other Changes 90 | - 代码结构优化,提高了整体可读性和可维护性 91 | - 增加了更多的日志输出,提供更详细的执行信息 92 | - 更新了版本号至 3.1.4 93 | 94 | ## v3.1.2 - 2024-07-17 95 | 96 | ### Added 97 | - 增加对多平台的支持:现在支持 `macOS`、`iOS`、`Android`、`Linux` 和 `Windows` 98 | - 新增 `upgrade` 命令:用于自动更新 Fridare 脚本 99 | - 新增一键安装功能 100 | 101 | ### Changed 102 | - 优化版本检查和更新流程 103 | 104 | ### Fixed 105 | - 修复了在 Windows 系统上无法正确识别和安装 Frida 工具的问题 106 | - 修复了在 macOS 系统上无法正确下载 Frida 工具的问题 107 | 108 | ### Other Changes 109 | - 更新版本号至 3.1.2 110 | - 代码重构和优化,提高整体性能和稳定性 111 | 112 | ### v3.1.1 113 | - 增加了 `upgrade` 命令,用于自动更新 Fridare 脚本 114 | 115 | ### v3.1.0 116 | - 增加了 `patch` 命令,用于修补指定的 Frida 模块 117 | - 例如:`安卓 frida-server` `./fridare.sh p -m frida-server -latest -os android -arch arm64 -o ./patched` 118 | - 增加了对 `patch` 命令的帮助信息 119 | - 增加对 ELF 和 PE 文件格式的支持(支持 Windows,Linux,MacOS,Android,IOS) 120 | - 更新了 `build`、`download` 等命令的用法说明 121 | - 修复了一些小的 Bug 并改进了脚本的稳定性 122 | 123 | ![v3.1.0](screenshots/3.png) 124 | 125 | ### v3.0.1 Fixed 126 | - 修复在 Conda 环境中无法正确识别和修改 Frida 工具的问题 127 | - 解决多个 Python 环境共存时的兼容性问题 128 | 129 | ### 新增特性 v3.0.0 130 | - 新增 `fridare.sh` 脚本,整合所有功能,提供更完整的命令行界面 131 | - 新增 `build`, `ls`, `download`, `lm`, `setup`, `config`, 和 `help` 命令 132 | - 新增配置文件支持,可以保存和加载用户设置 133 | - 新增颜色输出,提升用户体验 134 | - 新增自动检查和安装依赖功能 135 | - 新增下载特定 Frida 模块的功能 136 | - 新增列出可用 Frida 版本和模块的功能 137 | 138 | ### v2.2.0 (仅测试 macOS arm 架构,其它架构未测试) 139 | - 新增加 frida-tools 补丁,适配 `frida:rpc` 特征魔改 140 | - 解决 Android 内存扫描该字符串问题 141 | - 自动扫描本地 pip 安装 frida-tools 的位置,对 `core.py` 文件进行魔改,对 `_frida.abi3.so` 文件进行魔改 142 | - 新增加 frida-agent.dylib 魔改,从文件名称,加载位置进行隐藏 143 | - 解决 agent 加载未隐藏问题 144 | 145 | ### v2.1.1 146 | 147 | - 引入 `autoinstall.sh` 脚本,实现 Frida 插件的自动部署。 148 | - 引入 `Makefile`,简化项目的构建和部署流程。 149 | - 运行之前请确保本机已经安装了 [issh](https://github.com/4ch12dy/issh) 命令。并配置好了 ssh 的免密登录。 150 | > 配置 issh 的 ssh 免密登陆 151 | ```shell 152 | # 生成 keygen 密钥,如果已生成可以跳过 153 | ssh-keygen -t rsa -b 4096 -C "" 154 | # 配置手机IP,如果USB连接可以不配置 155 | issh ip set 156 | # 拷贝公钥到手机 /var/root ,需要 root 密码 alpine 157 | issh scp ~/.ssh/id_rsa.pub 158 | # 远程服务器添加公钥到 authorized_keys 文件 159 | issh run "mkdir -p ~/.ssh && cat /var/root/id_rsa.pub >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh" 160 | ``` 161 | 162 | ## Frida 魔改脚本的结构和功能 163 | ```shell 164 | fridare.sh - Frida 魔改脚本 165 | │ 166 | ├── 主要功能 167 | │ ├── 构建魔改版 Frida (build) 168 | │ │ ├── 支持指定版本或最新版本 169 | │ │ ├── 自动生成随机5字符名称 170 | │ │ ├── 自定义端口设置 171 | │ │ └── 支持 arm 和 arm64 架构 172 | │ ├── 列出可用 Frida 版本 (ls, list) 173 | │ │ └── 从 GitHub API 获取版本信息 174 | │ ├── 下载特定版本 Frida (download) 175 | │ │ ├── 支持下载单个或所有模块 176 | │ │ └── 可选的自动解压功能 177 | │ ├── 列出可用 Frida 模块 (lm, list-modules) 178 | │ ├── 检查并安装系统依赖 (setup) 179 | │ │ ├── 自动检测缺失依赖 180 | │ │ └── 使用包管理器安装依赖 181 | │ └── 配置选项设置 (config) 182 | │ ├── 设置 HTTP 代理 183 | │ ├── 设置 Frida 服务器端口 184 | │ └── 设置 Frida 魔改名称 185 | │ 186 | ├── 脚本结构 187 | │ ├── 初始化配置 (initialize_config) 188 | │ │ └── 读取和创建配置文件 189 | │ ├── 参数解析 (parse_arguments) 190 | │ │ └── 支持多种命令行选项 191 | │ ├── 命令处理 192 | │ │ ├── build: 构建魔改版 Frida 193 | │ │ ├── patch: 修补指定的 Frida 模块 194 | │ │ ├── setup: 设置环境 195 | │ │ ├── config: 管理配置 196 | │ │ ├── list: 列出版本 197 | │ │ ├── download: 下载模块 198 | │ │ └── list-modules: 列出模块 199 | │ └── 主函数 (main) 200 | │ └── 整合所有功能的入口点 201 | │ 202 | ├── 构建过程 (build_frida) 203 | │ ├── 版本检查 204 | │ │ └── 支持最新版本自动检测 205 | │ ├── 环境准备 206 | │ │ ├── 检查 Python 环境 (包括 Conda) 207 | │ │ └── 检查 Golang 环境 208 | │ ├── 下载 Frida (download_frida) 209 | │ ├── 解包 deb 文件 210 | │ ├── 修改文件 211 | │ │ ├── 修改启动守护程序 (modify_launch_daemon) 212 | │ │ │ └── 更新 plist 文件 213 | │ │ ├── 修改 Debian 文件 (modify_debian_files) 214 | │ │ │ ├── 更新 control 文件 215 | │ │ │ ├── 更新 extrainst_ 文件 216 | │ │ │ └── 更新 prerm 文件 217 | │ │ └── 修改二进制文件 (modify_binary) 218 | │ │ ├── 修改 frida-server 219 | │ │ ├── 修改 frida-agent.dylib 220 | │ │ └── 使用 hexreplace 工具 221 | │ ├── 重新打包 deb 文件 (repackage_deb) 222 | │ └── 修改 frida-tools (modify_frida_tools) 223 | │ ├── 修改 Python 库文件 224 | │ └── 更新 core.py 中的字符串 225 | │ 226 | ├── 辅助功能 227 | │ ├── 日志输出 (log_info, log_success, log_warning, log_error) 228 | │ │ └── 支持彩色输出 229 | │ ├── 用户确认 (confirm_execution) 230 | │ │ └── 可选的自动确认模式 231 | │ ├── 依赖检查 (check_dependencies) 232 | │ ├── 依赖安装 (install_dependencies) 233 | │ ├── 配置管理 (set_config, unset_config, list_config) 234 | │ └── Frida 版本和模块列表 (list_frida_versions, list_frida_modules) 235 | │ 236 | ├── 下载功能 (download_frida_module) 237 | │ ├── 版本选择 (最新版或指定版本) 238 | │ ├── 模块选择 (单个模块或全部模块) 239 | │ ├── 下载过程 240 | │ │ └── 支持 HTTP 代理 241 | │ └── 解压处理 242 | │ └── 可选的自动解压功能 243 | │ 244 | └── 安全和权限 245 | ├── sudo 权限保持 (sudo_keep_alive) 246 | └── 清理过程 (cleanup) 247 | ``` 248 | 249 | ## 前提条件 250 | 251 | - macOS 操作系统(用于运行构建脚本) 252 | - Homebrew 253 | - Python 3 254 | - Go (用于编译 hexreplace 工具) 255 | - 越狱的 iOS 设备 256 | - 在 iOS 设备上安装 OpenSSH 257 | 258 | ## 安装 259 | 260 | 1. 克隆此仓库: 261 | ```shell 262 | git clone https://github.com/suifei/fridare.git 263 | cd fridare 264 | ``` 265 | 266 | 2. 运行设置命令 267 | ```shell 268 | ./fridare.sh setup 269 | ``` 270 | 此命令将检查并安装所需的依赖项。 271 | 272 | 3. 查看帮助 273 | ```shell 274 | ./fridare.sh help 275 | ``` 276 | 277 | ## 使用方法 278 | Fridare 提供了多个命令来满足不同的需求: 279 | 280 | ### 命令清单 281 | 282 | 1. `build`: 重新打包 Frida 283 | 2. `ls` 或 `list`: 列出可用的 Frida 版本 284 | 3. `download`: 下载特定版本的 Frida 285 | 4. `lm` 或 `list-modules`: 列出可用的 Frida 模块 286 | 5. `setup`: 检查并安装系统依赖 287 | 6. `config`: 设置配置选项 288 | 7. `help`: 显示帮助信息 289 | 290 | ### 使用范例 291 | 292 | 1. 构建魔改版 Frida 293 | ```shell 294 | ./fridare.sh build -v 16.0.19 -p 8899 -y 295 | ``` 296 | 这个命令会构建版本 16.0.19 的 Frida,设置端口为 8899,并自动确认所有提示。 297 | 298 | 2. 列出可用的 Frida 版本 299 | ```shell 300 | ./fridare.sh ls 301 | ``` 302 | 303 | 3. 下载特定版本的 Frida 304 | ```shell 305 | ./fridare.sh download -v 16.0.19 -m frida-server ./output 306 | ``` 307 | 这个命令会下载版本 16.0.19 的 frida-server 模块到 ./output 目录。 308 | 309 | 4. 下载最新版本的所有 Frida 模块 310 | ```shell 311 | ./fridare.sh download -latest -all ./output 312 | ``` 313 | 314 | 5. 列出可用的 Frida 模块 315 | ```shell 316 | ./fridare.sh lm 317 | ``` 318 | 319 | 6. 设置环境 320 | ```shell 321 | ./fridare.sh setup 322 | ``` 323 | 这个命令会检查并安装所需的系统依赖。 324 | 325 | 7. 配置设置 326 | ```shell 327 | ./fridare.sh config set proxy http://127.0.0.1:7890 328 | ./fridare.sh config set port 9999 329 | ./fridare.sh config set frida-name abcde 330 | ``` 331 | 这些命令分别设置代理、端口和 Frida 魔改名。 332 | 333 | 8. 列出当前配置 334 | ```shell 335 | ./fridare.sh config ls 336 | ``` 337 | 338 | 9. 获取特定命令的帮助信息 339 | ```shell 340 | ./fridare.sh help build 341 | ``` 342 | 这个命令会显示 build 命令的详细用法。 343 | 344 | 10. 使用最新版本构建 Frida 345 | ```shell 346 | ./fridare.sh build -latest -p 9999 -y 347 | ``` 348 | 这个命令会使用最新版本的 Frida 进行构建,设置端口为 9999,并自动确认所有提示。 349 | 350 | 11. 下载但不解压 Frida 模块 351 | ```shell 352 | ./fridare.sh download -latest -m frida-gadget --no-extract ./output 353 | ``` 354 | 这个命令会下载最新版本的 frida-gadget 模块到 ./output 目录,但不会自动解压。 355 | 356 | 12. 安装 frida-tools 357 | ```shell 358 | ./fridare.sh config frida-tools 359 | ``` 360 | 这个命令会安装或更新 frida-tools。 361 | 362 | 13. 将生成的 .deb 包传输到您的 iOS 设备: 363 | ```shell 364 | scp ./dist/frida_16.3.3_iphoneos-arm_tcp.deb root@:/var/root/ 365 | ``` 366 | 367 | 14. SSH 进入您的 iOS 设备并安装修改后的包: 368 | ```shell 369 | ssh root@ 370 | dpkg -i /var/root/frida_16.3.3_iphoneos-arm_tcp.deb 371 | ``` 372 | 373 | 这些示例涵盖了脚本的主要功能和常见使用场景。可帮助您快速上手使用。 374 | 375 | ## 安装兼容版本的 Frida 工具 376 | 377 | 为确保兼容性,请安装与修改后的服务器版本相匹配的 Frida 工具: 378 | ```shell 379 | pip install frida-tools==12.4.3 380 | ``` 381 | 对于 Node.js 用户: 382 | ```shell 383 | npm install frida@16.3.3 384 | ``` 385 | 386 | ## 访问 frida-server 387 | 如果您的设备通过 USB 访问,您可以使用以下命令连接到本地 frida-server: 388 | ```shell 389 | frida -U -f 390 | ``` 391 | ## 使用远程 frida-server 392 | 如果不使用usb数据线时,可以使用以下命令连接到远程 frida-server : 393 | ```shell 394 | frida -H :8899 -U 395 | frida-trace -H :8899 ... 396 | frida-ps -H :8899 397 | frida-inject -H :8899 ... 398 | ``` 399 | 400 | ## 原理 401 | Fridare 项目的核心原理: 402 | 403 | ### 1. frida-server 修改原理 404 | 405 | Fridare 的核心思想是修改 frida-server ,使其更难被检测。这主要通过以下几个方面实现: 406 | 407 | - 重命名服务器文件: 408 | 将 `frida-server` 重命名为随机生成的名称(如 `abcde`),这样可以避免简单的名称检测。 409 | 410 | - 修改启动配置: 411 | 更新 LaunchDaemons plist 文件,使其使用新的服务器名称和自定义端口。这样可以改变服务器的启动方式和监听端口。 412 | 413 | - 二进制文件修改: 414 | 使用二进制替换技术,将服务器二进制文件中的 "frida" 相关字符串替换为自定义字符串。这可以避免通过扫描二进制文件来检测 Frida。 415 | 416 | ### 2. deb 包修改和重打包 417 | 418 | 项目使用 dpkg-deb 工具解包和重新打包 deb 文件。这允许我们修改包的内容,包括: 419 | 420 | - 更新 DEBIAN/control 文件中的包名 421 | - 修改 DEBIAN/extrainst_ 和 DEBIAN/prerm 脚本以使用新的服务器名称 422 | - 替换和重命名实际的服务器二进制文件 423 | 424 | ### 3. 自动化流程 425 | 426 | fridare.sh 脚本自动化了整个过程: 427 | 428 | - 下载指定版本的 frida-server 429 | - 生成随机名称 430 | - 修改所有必要的文件 431 | - 重新打包 deb 文件 432 | 433 | ### 4. 兼容性考虑 434 | 435 | 脚本同时处理 arm 和 arm64 架构的包,确保在不同的 iOS 设备上的兼容性。 436 | 437 | ### 5. 安全性增强 438 | 439 | 通过更改服务器名称、端口和内部字符串,这个项目使得通过常规方法检测 Frida 的存在变得更加困难。这对于在某些可能会主动检测和阻止 Frida 的应用中使用 Frida 非常有用。 440 | 441 | ### 6. 灵活性 442 | 443 | 通过允许用户指定 Frida 版本和端口,该工具提供了很大的灵活性,可以适应不同的需求和环境。 444 | 445 | ### 7. 二进制修改技术 446 | 447 | 使用 [hexreplace](hexreplace/main.go) 来执行二进制替换,在不重新编译 Frida 的情况下修改二进制文件。这种方法虽然有效,但也有局限性,因为它只能替换固定长度的字符串。 448 | 449 | ## 注意事项 450 | 451 | - 默认的 root 用户密码为 "alpine"。出于安全考虑,强烈建议更改此密码。 452 | - 请确保您的 iOS 设备已越狱并安装了 OpenSSH。 453 | - 此工具仅用于教育和研究目的。请遵守所有适用的法律和条款。 454 | 455 | ## 贡献 456 | 457 | 欢迎提交问题和拉取请求。对于重大更改,请先开issue讨论您想要更改的内容。 458 | 459 | ## 许可证 460 | 461 | [MIT LICENSE](LICENSE) 462 | 463 | --- 464 | 465 | # Fridare 466 | 467 | Fridare is a modification tool designed for customizing Frida-server, specifically for jailbroken iOS devices. It allows users to change names and ports, enhancing security and flexibility. It eliminates many jailbreak detection scenarios for Frida. 468 | [CHANGELOG](CHANGELOG) 469 | 470 | ## Features 471 | 472 | Here's the English version of the changelog: 473 | 474 | ## [v3.1.4] - 2024-07-18 475 | 476 | ### Added 477 | - Introduced new `patch-tools` command for modifying the frida-tools module 478 | - Implemented `render_markdown` function to display simple Markdown formatting in the terminal 479 | - Added `generate_random_name` function to create random Frida modification names 480 | - Created `move_file` function to handle "are identical" errors during file moves 481 | 482 | ### Improved 483 | - Enhanced `list_frida_versions` function to render Markdown-formatted version descriptions 484 | - Upgraded `build_frida` function to support building from local deb files 485 | - Expanded functionality and error handling in `patch_frida_tools` and `restore_frida_tools` functions 486 | - Optimized `modify_frida_tools` function for more reliable frida-tools modifications 487 | - Enhanced `download_frida_module` function with support for specific OS and architecture 488 | 489 | ### Fixed 490 | - Resolved issues with incorrect Frida path detection in certain scenarios 491 | - Addressed "are identical" errors that could occur during file moves 492 | 493 | ### Changed 494 | - Updated `show_main_usage` and other usage instruction functions to reflect new features 495 | - Adjusted `parse_arguments` function to accommodate the new `patch-tools` command 496 | - Modified configuration file handling to include support for `FRIDA_NAME` 497 | 498 | ### Other 499 | - Improved overall code structure for better readability and maintainability 500 | - Added more detailed log outputs for enhanced execution information 501 | - Updated version number to 3.1.4 502 | 503 | ### New Features v3.0.0 504 | - Added `fridare.sh` script, integrating all functionalities and providing a more complete command-line interface 505 | - Added `build`, `ls`, `download`, `lm`, `setup`, `config`, and `help` commands 506 | - Added configuration file support for saving and loading user settings 507 | - Added color output to enhance user experience 508 | - Added automatic dependency checking and installation 509 | - Added functionality to download specific Frida modules 510 | - Added listing of available Frida versions and modules 511 | 512 | ### New Features v2.2.0 (Tested only on macOS arm architecture, other architectures not tested) 513 | - Added frida-tools patch, adapting to `frida:rpc` feature modification 514 | - Resolves the issue of Android memory scanning for this string 515 | - Automatically scans the local pip installation location of frida-tools, modifies the `core.py` file, and modifies the `_frida.abi3.so` file 516 | - Added frida-agent.dylib modification, hiding from filename and load location 517 | - Resolves the issue of unhidden agent loading 518 | 519 | ### New Features v2.1.1 520 | 521 | - Introduced `autoinstall.sh` script for automatic deployment of Frida plugins. 522 | - Introduced `Makefile` to simplify the project build and deployment process. 523 | - Before running, please ensure that the [issh](https://github.com/4ch12dy/issh) command is installed on your machine. And configure password-free SSH login. 524 | > Configure password-free SSH login for issh 525 | ```shell 526 | # Generate keygen, skip if already generated 527 | ssh-keygen -t rsa -b 4096 -C "" 528 | # Configure iPhone IP, can be skipped if using USB connection 529 | issh ip set 530 | # Copy public key to /var/root on the phone, requires root password alpine 531 | issh scp ~/.ssh/id_rsa.pub 532 | # Add public key to authorized_keys file on remote server 533 | issh run "mkdir -p ~/.ssh && cat /var/root/id_rsa.pub >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh" 534 | ``` 535 | 536 | ## Features 537 | 538 | - Automatically download and modify specified versions of frida-server 539 | - Randomly generate new frida-server names 540 | - Customize frida-server ports 541 | - Support for arm and arm64 architectures 542 | - Binary replacement modification 543 | - frida-server 544 | - frida-agent.dylib 545 | - frida-tools 546 | - Generate modified .deb packages ready for direct installation 547 | - Integrated command-line interface providing multiple functionalities 548 | - Configuration file support for saving user settings 549 | - Automatic dependency checking and installation 550 | - Download specific Frida modules 551 | - List available Frida versions and modules 552 | 553 | ## Structure and Functionality of the Frida Modification Script 554 | ```shell 555 | fridare.sh - Frida Modification Script 556 | │ 557 | ├── Main Functions 558 | │ ├── Build Modified Frida (build) 559 | │ │ ├── Support for specified version or latest version 560 | │ │ ├── Auto-generate random 5-character name 561 | │ │ ├── Custom port setting 562 | │ │ └── Support for arm and arm64 architectures 563 | │ ├── List Available Frida Versions (ls, list) 564 | │ │ └── Fetch version info from GitHub API 565 | │ ├── Download Specific Frida Version (download) 566 | │ │ ├── Support for downloading single or all modules 567 | │ │ └── Optional auto-extraction feature 568 | │ ├── List Available Frida Modules (lm, list-modules) 569 | │ ├── Check and Install System Dependencies (setup) 570 | │ │ ├── Auto-detect missing dependencies 571 | │ │ └── Install dependencies using package manager 572 | │ └── Configure Options (config) 573 | │ ├── Set HTTP proxy 574 | │ ├── Set Frida server port 575 | │ └── Set Frida modification name 576 | │ 577 | ├── Script Structure 578 | │ ├── Initialize Configuration (initialize_config) 579 | │ │ └── Read and create configuration file 580 | │ ├── Parse Arguments (parse_arguments) 581 | │ │ └── Support various command-line options 582 | │ ├── Command Processing 583 | │ │ ├── build: Build modified Frida 584 | │ │ ├── setup: Set up environment 585 | │ │ ├── config: Manage configuration 586 | │ │ ├── list: List versions 587 | │ │ ├── download: Download modules 588 | │ │ └── list-modules: List modules 589 | │ └── Main Function (main) 590 | │ └── Entry point integrating all functionalities 591 | │ 592 | ├── Build Process (build_frida) 593 | │ ├── Version Check 594 | │ │ └── Support for latest version auto-detection 595 | │ ├── Environment Preparation 596 | │ │ ├── Check Python environment (including Conda) 597 | │ │ └── Check Golang environment 598 | │ ├── Download Frida (download_frida) 599 | │ ├── Unpack deb File 600 | │ ├── Modify Files 601 | │ │ ├── Modify Launch Daemon (modify_launch_daemon) 602 | │ │ │ └── Update plist file 603 | │ │ ├── Modify Debian Files (modify_debian_files) 604 | │ │ │ ├── Update control file 605 | │ │ │ ├── Update extrainst_ file 606 | │ │ │ └── Update prerm file 607 | │ │ └── Modify Binary Files (modify_binary) 608 | │ │ ├── Modify frida-server 609 | │ │ ├── Modify frida-agent.dylib 610 | │ │ └── Use hexreplace tool 611 | │ ├── Repackage deb File (repackage_deb) 612 | │ └── Modify frida-tools (modify_frida_tools) 613 | │ ├── Modify Python library files 614 | │ └── Update strings in core.py 615 | │ 616 | ├── Auxiliary Functions 617 | │ ├── Log Output (log_info, log_success, log_warning, log_error) 618 | │ │ └── Support for colored output 619 | │ ├── User Confirmation (confirm_execution) 620 | │ │ └── Optional auto-confirm mode 621 | │ ├── Dependency Check (check_dependencies) 622 | │ ├── Dependency Installation (install_dependencies) 623 | │ ├── Configuration Management (set_config, unset_config, list_config) 624 | │ └── Frida Version and Module Lists (list_frida_versions, list_frida_modules) 625 | │ 626 | ├── Download Functionality (download_frida_module) 627 | │ ├── Version Selection (latest or specified version) 628 | │ ├── Module Selection (single module or all modules) 629 | │ ├── Download Process 630 | │ │ └── Support for HTTP proxy 631 | │ └── Extraction Processing 632 | │ └── Optional auto-extraction feature 633 | │ 634 | └── Security and Permissions 635 | ├── Maintain sudo Privileges (sudo_keep_alive) 636 | └── Cleanup Process (cleanup) 637 | ``` 638 | 639 | ## Prerequisites 640 | 641 | - macOS operating system (for running build scripts) 642 | - Homebrew 643 | - Python 3 644 | - Go (for compiling the hexreplace tool) 645 | - Jailbroken iOS device 646 | - OpenSSH installed on iOS device 647 | 648 | ## Installation 649 | 650 | 1. Clone this repository: 651 | ```shell 652 | git clone https://github.com/suifei/fridare.git 653 | cd fridare 654 | ``` 655 | 656 | 2. Run the setup command: 657 | ```shell 658 | ./fridare.sh setup 659 | ``` 660 | This command will check and install the required dependencies. 661 | 662 | 3. View the help information: 663 | ```shell 664 | ./fridare.sh help 665 | ``` 666 | 667 | ## Usage 668 | Fridare provides multiple commands to meet different needs: 669 | 670 | ### Command List 671 | 672 | 1. `build`: Repackage Frida 673 | 2. `ls` or `list`: List available Frida versions 674 | 3. `download`: Download a specific version of Frida 675 | 4. `lm` or `list-modules`: List available Frida modules 676 | 5. `setup`: Check and install system dependencies 677 | 6. `config`: Set configuration options 678 | 7. `help`: Display help information 679 | 680 | ### Usage Examples 681 | 682 | 1. Build a modified version of Frida 683 | ```shell 684 | ./fridare.sh build -v 16.0.19 -p 8899 -y 685 | ``` 686 | This command will build Frida version 16.0.19, set the port to 8899, and automatically confirm all prompts. 687 | 688 | 2. List available Frida versions 689 | ```shell 690 | ./fridare.sh ls 691 | ``` 692 | 693 | 3. Download a specific version of Frida 694 | ```shell 695 | ./fridare.sh download -v 16.0.19 -m frida-server ./output 696 | ``` 697 | This command will download the frida-server module of version 16.0.19 to the ./output directory. 698 | 699 | 4. Download all Frida modules of the latest version 700 | ```shell 701 | ./fridare.sh download -latest -all ./output 702 | ``` 703 | 704 | 5. List available Frida modules 705 | ```shell 706 | ./fridare.sh lm 707 | ``` 708 | 709 | 6. Set up the environment 710 | ```shell 711 | ./fridare.sh setup 712 | ``` 713 | This command will check and install the required system dependencies. 714 | 715 | 7. Configure settings 716 | ```shell 717 | ./fridare.sh config set proxy http://127.0.0.1:7890 718 | ./fridare.sh config set port 9999 719 | ./fridare.sh config set frida-name abcde 720 | ``` 721 | These commands set the proxy, port, and Frida modification name respectively. 722 | 723 | 8. List current configuration 724 | ```shell 725 | ./fridare.sh config ls 726 | ``` 727 | 728 | 9. Get help information for a specific command 729 | ```shell 730 | ./fridare.sh help build 731 | ``` 732 | This command will display detailed usage for the build command. 733 | 734 | 10. Build Frida using the latest version 735 | ```shell 736 | ./fridare.sh build -latest -p 9999 -y 737 | ``` 738 | This command will build using the latest version of Frida, set the port to 9999, and automatically confirm all prompts. 739 | 740 | 11. Download but don't extract Frida module 741 | ```shell 742 | ./fridare.sh download -latest -m frida-gadget --no-extract ./output 743 | ``` 744 | This command will download the latest version of the frida-gadget module to the ./output directory but won't automatically extract it. 745 | 746 | 12. Install frida-tools 747 | ```shell 748 | ./fridare.sh config frida-tools 749 | ``` 750 | This command will install or update frida-tools. 751 | 752 | 13. Transfer the generated .deb package to your iOS device: 753 | ```shell 754 | scp ./dist/frida_16.3.3_iphoneos-arm_tcp.deb root@:/var/root/ 755 | ``` 756 | 757 | 14. SSH into your iOS device and install the modified package: 758 | ```shell 759 | ssh root@ 760 | dpkg -i /var/root/frida_16.3.3_iphoneos-arm_tcp.deb 761 | ``` 762 | 763 | These examples cover the main functionalities and common usage scenarios of the script. They can help you quickly get started with using it. 764 | 765 | ## Installing Compatible Frida Tools 766 | 767 | To ensure compatibility, please install Frida tools that match the modified server version: 768 | ```shell 769 | pip install frida-tools==12.4.3 770 | ``` 771 | For Node.js users: 772 | ```shell 773 | npm install frida@16.3.3 774 | ``` 775 | 776 | ## Accessing frida-server 777 | If your device is accessed via USB, you can use the following command to connect to the local frida-server: 778 | ```shell 779 | frida -U -f 780 | ``` 781 | ## Using Remote frida-server 782 | If not using a USB data cable, you can use the following commands to connect to the remote frida-server: 783 | ```shell 784 | frida -H :8899 -U 785 | frida-trace -H :8899 ... 786 | frida-ps -H :8899 787 | frida-inject -H :8899 ... 788 | ``` 789 | 790 | ## Principles 791 | Core principles of the Fridare project: 792 | 793 | ### 1. frida-server Modification Principle 794 | 795 | The core idea of Fridare is to modify frida-server to make it harder to detect. This is mainly achieved through the following aspects: 796 | 797 | - Renaming the server file: 798 | Rename `frida-server` to a randomly generated name (e.g., `abcde`), which avoids simple name detection. 799 | 800 | - Modifying startup configuration: 801 | Update the LaunchDaemons plist file to use the new server name and custom port. This changes the way the server starts and the port it listens on. 802 | 803 | - Binary file modification: 804 | Use binary replacement techniques to replace "frida" related strings in the server binary file with custom strings. This can avoid detection of Frida by scanning the binary file. 805 | 806 | ### 2. deb Package Modification and Repackaging 807 | 808 | The project uses the dpkg-deb tool to unpack and repack deb files. This allows us to modify the contents of the package, including: 809 | 810 | - Updating the package name in the DEBIAN/control file 811 | - Modifying DEBIAN/extrainst_ and DEBIAN/prerm scripts to use the new server name 812 | - Replacing and renaming the actual server binary file 813 | 814 | ### 3. Automated Process 815 | 816 | The fridare.sh script automates the entire process: 817 | 818 | - Downloading the specified version of frida-server 819 | - Generating random names 820 | - Modifying all necessary files 821 | - Repacking the deb file 822 | 823 | ### 4. Compatibility Considerations 824 | 825 | The script handles packages for both arm and arm64 architectures, ensuring compatibility on different iOS devices. 826 | 827 | ### 5. Enhanced Security 828 | 829 | By changing the server name, port, and internal strings, this project makes it more difficult to detect the presence of Frida through conventional methods. This is particularly useful for using Frida in applications that might actively detect and block Frida. 830 | 831 | ### 6. Flexibility 832 | 833 | By allowing users to specify the Frida version and port, the tool provides great flexibility to adapt to different needs and environments. 834 | 835 | ### 7. Binary Modification Technique 836 | 837 | Using [hexreplace](hexreplace/main.go) to perform binary replacements, modifying binary files without recompiling Frida. While effective, this method has limitations as it can only replace fixed-length strings. 838 | 839 | ## Notes 840 | 841 | - The default root user password is "alpine". For security reasons, it is strongly recommended to change this password. 842 | - Please ensure your iOS device is jailbroken and has OpenSSH installed. 843 | - This tool is for educational and research purposes only. Please comply with all applicable laws and terms. 844 | 845 | ## Contributing 846 | 847 | Issues and pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 848 | 849 | ## License 850 | 851 | [MIT LICENSE](LICENSE) 852 | -------------------------------------------------------------------------------- /autoinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | iSSH_ROOT_DIR=`cat ~/.issh/rootdir` 3 | if [ -z "$iSSH_ROOT_DIR" ]; then 4 | echo "issh not found in PATH" 5 | echo "Please install issh from https://github.com/4ch12dy/issh" 6 | exit 1 7 | fi 8 | 9 | DEB_NAME=$(cd dist && ls -lt *-arm_*.deb | head -n 1 | awk '{print $9}' && cd ..) 10 | INSTALL_NAME=$(echo $DEB_NAME | awk -F'_' '{print $4}') 11 | INSTANCE_NAME=$(source $iSSH_ROOT_DIR/issh.sh && issh run "apt install gawk -y --allow-unauthenticated" && issh run "ps -e | grep 0.0.0.0:8899 | grep /usr/sbin/ | grep -v grep | awk '{n=split(\$0,a,\"/\");n2=split(a[n],b,\" \"); print b[n2-2]}'") 12 | INSTANCE_NAME=$(echo $INSTANCE_NAME | awk '{print $NF}') 13 | echo "DEB File: $DEB_NAME" 14 | echo "Frida Instance: $INSTANCE_NAME" 15 | echo "Install Name: $INSTALL_NAME" 16 | 17 | source $iSSH_ROOT_DIR/issh.sh && issh scp dist/$DEB_NAME 18 | 19 | if [ -n "$INSTANCE_NAME" ]; then 20 | source $iSSH_ROOT_DIR/issh.sh && issh run "dpkg -r re.$INSTANCE_NAME.server" 21 | fi 22 | source $iSSH_ROOT_DIR/issh.sh && issh run "dpkg -i /var/root/$DEB_NAME" 23 | source $iSSH_ROOT_DIR/issh.sh && issh run "rm -rf /var/root/$DEB_NAME" 24 | source $iSSH_ROOT_DIR/issh.sh && issh run "ps -e|grep $INSTALL_NAME" -------------------------------------------------------------------------------- /docs/android.md: -------------------------------------------------------------------------------- 1 | # Android frida-server 魔改教程 2 | 3 | ## 前提条件 4 | 5 | - 安装 fridare.sh 脚本 6 | - 确保系统中已安装 Python 3 和 Golang 7 | - 确保已安装 Frida 8 | 9 | ## 步骤 10 | 11 | ### 1. 检查环境 12 | 13 | 首先,运行 `fridare.sh upgrade` 命令来检查环境并更新 FRIDA_MODULES: 14 | 15 | ```bash 16 | $ ./fridare.sh upgrade 17 | ``` 18 | 19 | 这将显示您的环境信息,包括 Python 版本、Frida 版本、Go 版本等。 20 | 21 | ### 2. 配置代理(可选) 22 | 23 | 如果需要使用代理,可以通过以下命令设置: 24 | 25 | ```bash 26 | $ ./fridare.sh conf edit 27 | ``` 28 | 29 | 选择选项 1 来编辑 HTTP 代理,输入代理地址(例如:socks5://localhost:1080)。 30 | 31 | ### 3. 查看可用的 Frida 模块 32 | 33 | 运行以下命令来查看所有可用的 Frida 模块: 34 | 35 | ```bash 36 | $ ./fridare.sh lm 37 | ``` 38 | 39 | 这将列出所有可用的 Frida 模块,包括它们支持的操作系统和架构。 40 | 41 | ### 4. 魔改 frida-server 42 | 43 | 使用以下命令来修补 frida-server: 44 | 45 | ```bash 46 | $ ./fridare.sh patch -m frida-server -latest -os android -arch arm64 -o ./patched 47 | ``` 48 | 49 | 参数说明: 50 | - `-m frida-server`: 指定要修补的模块 51 | - `-latest`: 使用最新版本的 Frida 52 | - `-os android`: 指定操作系统为 Android 53 | - `-arch arm64`: 指定架构为 arm64 54 | - `-o ./patched`: 指定输出目录 55 | 56 | ### 5. 输入魔改名称 57 | 58 | 在执行过程中,脚本会提示您输入一个魔改名称。这个名称应该是 5 个字母(a-z 或 A-Z)。例如: 59 | 60 | ``` 61 | 请输入本次所采用的 Frida 魔改名: axjdf 62 | ``` 63 | 64 | ### 6. 等待修补完成 65 | 66 | 脚本会自动下载指定的 frida-server,解压,然后进行修补。整个过程包括: 67 | 68 | - 下载 frida-server 69 | - 解压文件 70 | - 修补二进制文件 71 | - 替换字符串 72 | 73 | ### 7. 查看输出 74 | 75 | 修补完成后,您会看到类似以下的输出: 76 | 77 | ``` 78 | [SUCC] 模块修补完成: ./patched/frida-server_axjdf 79 | ``` 80 | 81 | 这表示魔改后的 frida-server 已经生成,文件名为 `frida-server_axjdf`。 82 | 83 | ## 使用魔改后的 frida-server 84 | 85 | 1. 将修补后的 `frida-server_axjdf` 文件传输到 Android 设备上。 86 | 2. 赋予文件执行权限:`chmod +x frida-server_axjdf` 87 | 3. 在 Android 设备上运行魔改后的 frida-server:`./frida-server_axjdf` 88 | 89 | 注意:使用魔改后的 frida-server 时,确保客户端代码中使用了相同的魔改名称(本例中为 "axjdf")。 90 | 91 | 通过这个教程,您可以成功地魔改 Android 版本的 frida-server,使其更难被检测到。记得每次使用时都更换魔改名称,以提高隐蔽性。 -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Fridare 安装说明 2 | 3 | Fridare 是一个用于魔改 Frida 的工具,可以帮助你绕过一些基本的检测机制。以下是安装和配置 Fridare 的步骤。 4 | 5 | ## 快速安装 6 | 7 | 使用以下命令可以快速安装 Fridare: 8 | 9 | ```bash 10 | curl -s https://raw.githubusercontent.com/suifei/fridare/main/fridare.sh | bash -s install 11 | ``` 12 | 13 | 这个命令会在当前目录下创建一个 `fridare` 文件夹,其中包含了安装好的 Fridare 工具。 14 | 15 | ## 配置环境变量 16 | 17 | 安装完成后,你需要将 Fridare 添加到系统的环境变量中,以便可以在任何位置使用 `fridare` 命令。 18 | 19 | ### 对于 Bash 用户 20 | 21 | 1. 编辑你的 `.bashrc` 文件: 22 | 23 | ```bash 24 | nano ~/.bashrc 25 | ``` 26 | 27 | 2. 在文件末尾添加以下行: 28 | 29 | ```bash 30 | export PATH=$PATH:/path/to/fridare 31 | ``` 32 | 33 | 请将 `/path/to/fridare` 替换为实际的 Fridare 安装路径。 34 | 35 | 3. 保存并关闭文件,然后运行: 36 | 37 | ```bash 38 | source ~/.bashrc 39 | ``` 40 | 41 | ### 对于 Zsh 用户 42 | 43 | 1. 编辑你的 `.zshrc` 文件: 44 | 45 | ```bash 46 | nano ~/.zshrc 47 | ``` 48 | 49 | 2. 在文件末尾添加以下行: 50 | 51 | ```bash 52 | export PATH=$PATH:/path/to/fridare 53 | ``` 54 | 55 | 请将 `/path/to/fridare` 替换为实际的 Fridare 安装路径。 56 | 57 | 3. 保存并关闭文件,然后运行: 58 | 59 | ```bash 60 | source ~/.zshrc 61 | ``` 62 | 63 | ## 验证安装 64 | 65 | 安装完成后,你可以通过运行以下命令来验证 Fridare 是否已正确安装: 66 | 67 | ```bash 68 | fridare.sh help 69 | ``` 70 | 71 | 如果安装成功,你应该能看到 Fridare 的版本信息。 72 | 73 | ## 使用 Fridare 74 | 75 | 现在你可以在终端的任何位置使用 `fridare.sh` 命令来运行 Fridare 工具。例如: 76 | 77 | ```bash 78 | fridare.sh build -latest 79 | ``` 80 | 81 | 这个命令会下载并魔改最新版本的 Frida。 82 | 83 | ## 注意事项 84 | 85 | - 确保你有足够的权限来修改系统环境变量。 86 | - 如果你使用的是其他 shell,请相应地修改相关的配置文件。 87 | - 定期检查 Fridare 的更新,以获得最新的功能和安全修复。 88 | 89 | 现在你已经成功安装了 Fridare,可以开始使用它来魔改 Frida 了。请确保在合法和授权的情况下使用此工具。 -------------------------------------------------------------------------------- /docs/ios.md: -------------------------------------------------------------------------------- 1 | # iOS frida-server 魔改教程 2 | 3 | ## 前提条件 4 | 5 | - 安装 fridare.sh 脚本 6 | - 确保系统中已安装 Python 3 和 Golang 7 | - 确保已安装 Frida 和相关依赖 8 | 9 | ## 步骤 10 | 11 | ### 1. 运行魔改脚本 12 | 13 | 使用以下命令开始魔改过程: 14 | 15 | ```bash 16 | $ ./fridare.sh build -latest 17 | ``` 18 | 19 | 这个命令会自动下载最新版本的 Frida,并开始魔改过程。 20 | 21 | ### 2. 确认免责声明 22 | 23 | 脚本会显示一个免责声明。仔细阅读并确认是否同意: 24 | 25 | ``` 26 | 您是否同意以上免责声明并允许使用sudo权限?(y/N) y 27 | ``` 28 | 29 | 输入 `y` 并按回车以继续。 30 | 31 | ### 3. 等待下载和修改过程 32 | 33 | 脚本会自动完成以下步骤: 34 | 35 | - 下载最新版本的 Frida deb 包(适用于 arm 和 arm64 架构) 36 | - 修改 plist 文件 37 | - 修改 DEBIAN 文件夹中的文件 38 | - 修改二进制文件 39 | - 重新打包 deb 文件 40 | 41 | ### 4. 查看输出信息 42 | 43 | 魔改完成后,脚本会显示重要信息: 44 | 45 | ``` 46 | [INFO] 新版本名:duquj 47 | [INFO] 请使用新版本名:duquj 进行调试 48 | [INFO] 请使用端口:8899 进行调试 49 | [INFO] 新版本 deb 文件:../dist/frida_16.4.4_iphoneos-arm64_duquj_tcp.deb 50 | ``` 51 | 52 | 记下新的版本名(本例中为 "duquj")和端口号,这些在之后的使用中会用到。 53 | 54 | ### 5. 安装到 iOS 设备 55 | 56 | 按照脚本提供的说明,将魔改后的 deb 文件安装到 iOS 设备上: 57 | 58 | ``` 59 | [INFO] iPhone 安装: 60 | [INFO] scp dist/frida_16.4.4_iphoneos-arm64_duquj_tcp.deb root@:/var/root 61 | [INFO] ssh root@ 62 | [INFO] dpkg -i /var/root/frida_16.4.4_iphoneos-arm64_duquj_tcp.deb 63 | ``` 64 | 65 | 替换 `` 为你的 iOS 设备实际 IP 地址。 66 | 67 | ### 6. 连接和使用 68 | 69 | 使用以下命令连接到魔改后的 frida-server: 70 | 71 | ``` 72 | [INFO] PC 连接: 73 | [INFO] frida -U -f com.xxx.xxx -l 74 | [INFO] frida -H :8899 -f com.xxx.xxx --no-pause 75 | ``` 76 | 77 | 将 `com.xxx.xxx` 替换为目标应用的包名,`` 替换为 iOS 设备的 IP 地址。 78 | 79 | ### 7. 修改 frida-tools(可选) 80 | 81 | 脚本会询问是否要修改本地的 frida-tools 以适配魔改版本: 82 | 83 | ``` 84 | 本脚本将自动修改本地 frida-tools,以适配魔改版本的 Frida。(跳过 frida-tools 魔改。某些功能可能无法使用,建议修改) 85 | 您是否同意?(y/N) 86 | ``` 87 | 88 | 如果需要完整功能,建议输入 `y` 同意修改。 89 | 90 | ## 注意事项 91 | 92 | 1. 每次运行脚本都会生成新的魔改名称,确保使用最新生成的名称和端口号。 93 | 2. 魔改后的 frida-server 可能会绕过一些基本的检测,但不保证能绕过所有检测机制。 94 | 3. 使用魔改版本可能会影响某些 Frida 功能,特别是如果没有修改 frida-tools。 95 | 4. 确保在合法和授权的情况下使用此工具。 96 | 97 | -------------------------------------------------------------------------------- /docs/patch-tools.md: -------------------------------------------------------------------------------- 1 | # Frida-tools 魔改指南 2 | 3 | fridare.sh 脚本提供了 `patch-tools` 命令,允许您修改 frida-tools 以适配魔改版本的 Frida。本指南将帮助您使用这个功能。 4 | 5 | ## 1. 修改 frida-tools 6 | 7 | ### 使用配置的魔改名 8 | 9 | 如果您已经在配置中设置了 `FRIDA_NAME`,可以直接使用: 10 | 11 | ```bash 12 | ./fridare.sh patch-tools name 13 | ``` 14 | 15 | 这将使用配置中的魔改名来修改 frida-tools。 16 | 17 | ### 指定新的魔改名 18 | 19 | 如果您想使用一个不同的魔改名,可以直接在命令中指定: 20 | 21 | ```bash 22 | ./fridare.sh patch-tools name abcde 23 | ``` 24 | 25 | 这里的 `abcde` 就是您指定的新魔改名。请确保使用恰好 5 个字母(a-z 或 A-Z)。 26 | 27 | ### 使用随机生成的魔改名 28 | 29 | 如果您既没有在配置中设置 `FRIDA_NAME`,也没有在命令中指定,脚本会随机生成一个魔改名: 30 | 31 | ```bash 32 | ./fridare.sh patch-tools name 33 | ``` 34 | 35 | ## 2. 确认操作 36 | 37 | 执行命令后,脚本会显示找到的 frida-tools 路径,并询问您是否确认使用此路径。输入 'y' 确认,或 'n' 取消操作。 38 | 39 | ## 3. 查看结果 40 | 41 | 脚本会显示修改过程的详细信息,包括: 42 | 43 | - 创建备份文件 44 | - 修改 Python 库文件 45 | - 更新 core.py 文件中的相关字符串 46 | 47 | ## 4. 恢复原版 48 | 49 | 如果您需要恢复 frida-tools 到原版,可以使用以下命令: 50 | 51 | ```bash 52 | ./fridare.sh patch-tools restore 53 | ``` 54 | 55 | 这将使用之前创建的备份文件来恢复原始的 frida-tools 文件。 56 | 57 | ## 注意事项 58 | 59 | 1. 请确保在修改 frida-tools 之前已经成功构建了魔改版本的 Frida。 60 | 2. 修改操作会创建备份文件,以便于日后恢复。 61 | 3. 如果遇到权限问题,可能需要使用 sudo 运行脚本。 62 | 4. 修改后,建议测试 frida-tools 的功能,确保一切正常工作。 63 | 64 | 通过使用 `patch-tools` 命令,您可以轻松地将 frida-tools 与您的魔改版 Frida 保持同步,确保整个工具链的兼容性。 -------------------------------------------------------------------------------- /fridare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Frida 魔改脚本,用于修改 frida-server 的名称和端口 4 | # 作者:suifei@gmail.com 5 | 6 | set -e # 遇到错误立即退出 7 | 8 | VERSION="3.1.7" 9 | # 默认值设置 10 | DEF_FRIDA_SERVER_PORT=8899 11 | DEF_AUTO_CONFIRM="false" 12 | 13 | readonly COLOR_YELLOW='\033[33m' 14 | readonly COLOR_RED='\033[31m' 15 | readonly COLOR_PINK='\033[95m' 16 | readonly COLOR_MAGENTA='\033[95m' 17 | readonly COLOR_ORANGE='\033[33m' 18 | readonly COLOR_PURPLE='\033[35m' 19 | readonly COLOR_GREEN='\033[32m' 20 | readonly COLOR_BLUE='\033[34m' 21 | readonly COLOR_SKYBLUE='\033[36m' 22 | readonly COLOR_WHITE='\033[37m' 23 | readonly COLOR_BLACK='\033[30m' 24 | readonly COLOR_GRAY='\033[90m' 25 | readonly COLOR_CYAN='\033[96m' 26 | readonly COLOR_BOLD='\033[1m' 27 | readonly COLOR_DIM='\033[2m' 28 | readonly COLOR_ITALIC='\033[3m' 29 | readonly COLOR_UNDERLINE='\033[4m' 30 | readonly COLOR_BLINK='\033[5m' 31 | readonly COLOR_REVERSE='\033[7m' 32 | readonly COLOR_STRIKETHROUGH='\033[9m' 33 | 34 | readonly COLOR_RESET='\033[0m' 35 | readonly COLOR_BG_WHITE='\033[47m' 36 | readonly COLOR_BG_BLACK='\033[40m' 37 | readonly COLOR_BG_RED='\033[41m' 38 | readonly COLOR_BG_GREEN='\033[42m' 39 | readonly COLOR_BG_YELLOW='\033[43m' 40 | readonly COLOR_BG_BLUE='\033[44m' 41 | readonly COLOR_BG_PURPLE='\033[45m' 42 | readonly COLOR_BG_SKYBLUE='\033[46m' 43 | 44 | # 初始化变量 45 | FRIDA_VERSION="" 46 | FRIDA_SERVER_PORT="" 47 | CURL_PROXY="" 48 | AUTO_CONFIRM="" 49 | CONFIG_FILE="${HOME}/.fridare.conf" 50 | 51 | # 免责声明 52 | DISCLAIMER="${COLOR_BG_WHITE}${COLOR_BLACK}${COLOR_BLINK} 本脚本仅供${COLOR_BLUE}学习使用,${COLOR_RED}请勿用于非法用途。${COLOR_RESET} 53 | 免责声明: 54 | 1. 本脚本仅供学习和研究使用,不得用于商业或非法目的。 55 | 2. 使用本脚本修改Frida可能违反Frida的使用条款或版权规定。 56 | 3. 用户应自行承担使用本脚本的所有风险和法律责任。 57 | 4. 脚本作者不对因使用本脚本而导致的任何损失或法律问题负责。 58 | 5. 使用本脚本即表示您已阅读并同意以上声明。 59 | 60 | Disclaimer: 61 | 1. This script is for learning and research purposes only and may not be used 62 | for commercial or illegal purposes. 63 | 2. Using this script to modify Frida may violate Frida's terms of use or 64 | copyright regulations. 65 | 3. Users should bear all risks and legal responsibilities of using this script. 66 | 4. The script author is not responsible for any losses or legal issues caused 67 | by the use of this script. 68 | 5. Using this script means that you have read and agree to the above statement. 69 | " 70 | 71 | # 日志函数 72 | log_info() { 73 | echo -e "${COLOR_WHITE}[INFO] $1${COLOR_RESET}" 74 | } 75 | 76 | log_success() { 77 | echo -e "${COLOR_GREEN}[SUCC] $1${COLOR_RESET}" 78 | } 79 | 80 | log_warning() { 81 | echo -e "${COLOR_YELLOW}[WARN] $1${COLOR_RESET}" 82 | } 83 | 84 | log_error() { 85 | echo -e "${COLOR_BG_WHITE}${COLOR_RED}[ERRO] $1${COLOR_RESET}" 86 | } 87 | 88 | log_cinfo() { 89 | echo -e "$1[INFO] $2${COLOR_RESET}" 90 | } 91 | 92 | log_color() { 93 | echo -e "$1$2${COLOR_RESET}" 94 | } 95 | 96 | log_skyblue() { 97 | echo -e "${COLOR_SKYBLUE}$1${COLOR_RESET}" 98 | } 99 | download_with_progress() { 100 | local url="$1" 101 | local output_file="$2" 102 | local description="$3" 103 | local retry_count=3 104 | local temp_file="${output_file}.tmp" 105 | 106 | local curl_cmd="curl -L --progress-bar --fail --show-error" 107 | if [ -n "$CURL_PROXY" ]; then 108 | case "$CURL_PROXY" in 109 | socks4://*) 110 | local proxy=${CURL_PROXY#socks4://} 111 | curl_cmd+=" --socks4 $proxy" 112 | ;; 113 | socks4a://*) 114 | local proxy=${CURL_PROXY#socks4a://} 115 | curl_cmd+=" --socks4a $proxy" 116 | ;; 117 | socks5://*) 118 | local proxy=${CURL_PROXY#socks5://} 119 | curl_cmd+=" --socks5 $proxy" 120 | ;; 121 | socks5h://*) 122 | local proxy=${CURL_PROXY#socks5h://} 123 | curl_cmd+=" --socks5-hostname $proxy" 124 | ;; 125 | http://*) 126 | curl_cmd+=" --proxy $CURL_PROXY" 127 | ;; 128 | https://*) 129 | curl_cmd+=" --proxy $CURL_PROXY" 130 | ;; 131 | *) 132 | log_warning "未知的代理协议,将作为 HTTP 代理使用: $CURL_PROXY" 133 | curl_cmd+=" --proxy $CURL_PROXY" 134 | ;; 135 | esac 136 | fi 137 | 138 | while [ $retry_count -gt 0 ]; do 139 | echo -e "${COLOR_SKYBLUE}正在下载 $description...${COLOR_RESET}" 140 | 141 | if $curl_cmd "$url" -o "$temp_file" 2>&1 | tee /dev/stderr | 142 | sed -u 's/^[# ]*\([0-9]*\.[0-9]%\).*\([ 0-9.]*\(KiB\|MiB\|GiB\)\/s\).*$/\1\n速度: \2/' | 143 | while IFS= read -r line; do 144 | if [[ $line =~ ^[0-9]+\.[0-9]% ]]; then 145 | percent=${line%\%*} 146 | completed=$(printf "%.0f" $percent) 147 | printf "\r进度: [%-50s] %d%%" $(printf "=%.0s" $(seq 1 $((completed / 2)))) "$completed" 148 | elif [[ $line =~ ^速度: ]]; then 149 | printf " %s" "$line" 150 | fi 151 | done; then 152 | echo # 换行 153 | mv "$temp_file" "$output_file" 154 | local file_size=$(wc -c <"$output_file") 155 | echo -e "${COLOR_GREEN}下载完成: $output_file (大小: $file_size 字节)${COLOR_RESET}" 156 | return 0 157 | else 158 | echo # 换行 159 | local curl_exit_code=$? 160 | log_error "下载失败: $output_file (curl exit code: $curl_exit_code)" 161 | if [ -f "$temp_file" ]; then 162 | log_error "临时文件大小: $(wc -c <"$temp_file") 字节" 163 | rm -f "$temp_file" 164 | fi 165 | retry_count=$((retry_count - 1)) 166 | if [ $retry_count -gt 0 ]; then 167 | log_warning "检查网络连接..." 168 | if ! ping -c 1 github.com &>/dev/null; then 169 | log_error "无法连接到 github.com,请检查网络连接" 170 | return 1 171 | fi 172 | log_warning "网络连接正常,5秒后重试..." 173 | sleep 5 174 | fi 175 | fi 176 | done 177 | 178 | if [ $retry_count -eq 0 ]; then 179 | log_error "达到最大重试次数,下载失败" 180 | return 1 181 | fi 182 | } 183 | show_main_usage() { 184 | echo -e "${COLOR_SKYBLUE}Frida 重打包工具 v${VERSION}${COLOR_RESET}" 185 | # 计算并显示当前脚本的 MD5 值 186 | local script_path="$0" 187 | local script_md5=$(md5 -q "$script_path" 2>/dev/null || md5sum "$script_path" | cut -d ' ' -f 1) 188 | echo -e "${COLOR_GREEN}脚本 MD5: ${COLOR_YELLOW}${script_md5}${COLOR_RESET}" 189 | echo -e "${COLOR_WHITE}用法: $0 <命令> [选项]${COLOR_RESET}" 190 | echo 191 | echo -e "${COLOR_YELLOW}命令:${COLOR_RESET}" 192 | echo -e " ${COLOR_GREEN}q, quickstart${COLOR_RESET} 显示快速开始指南" 193 | echo -e " ${COLOR_GREEN}b, build${COLOR_RESET} 重新打包 Frida" 194 | echo -e " ${COLOR_GREEN}p, patch${COLOR_RESET} 修补指定的 Frida 模块" 195 | echo -e " ${COLOR_GREEN}pt, patch-tools${COLOR_RESET} 修补 frida-tools 模块" 196 | echo -e " ${COLOR_GREEN}pwt, patch-wintools${COLOR_RESET} 修补 Windows frida-tools 模块" 197 | echo -e " ${COLOR_GREEN}ls, list${COLOR_RESET} 列出可用的 Frida 版本" 198 | echo -e " ${COLOR_GREEN}dl, download${COLOR_RESET} 下载特定版本的 Frida" 199 | echo -e " ${COLOR_GREEN}lm, list-modules${COLOR_RESET} 列出可用的 Frida 模块" 200 | echo -e " ${COLOR_GREEN}s, setup${COLOR_RESET} 检查并安装系统依赖" 201 | echo -e " ${COLOR_GREEN}conf, config${COLOR_RESET} 设置配置选项" 202 | echo -e " ${COLOR_GREEN}u, upgrade${COLOR_RESET} 更新配置,检查新版本" 203 | echo -e " ${COLOR_GREEN}h, help${COLOR_RESET} 显示帮助信息" 204 | echo 205 | echo -e "${COLOR_WHITE}运行 '$0 help <命令>' 以获取特定命令的更多信息。${COLOR_RESET}" 206 | echo -e "${COLOR_WHITE}新用户? 运行 '$0 quickstart' 获取快速入门指南。${COLOR_RESET}" 207 | echo -e "${COLOR_GRAY} suifei@gmail.com${COLOR_RESET}" 208 | echo -e "${COLOR_GRAY} https://github.com/suifei/fridare${COLOR_RESET}" 209 | } 210 | 211 | show_build_usage() { 212 | echo -e "${COLOR_SKYBLUE}用法: $0 b|build [选项]${COLOR_RESET}" 213 | echo 214 | echo -e "${COLOR_YELLOW}选项:${COLOR_RESET}" 215 | echo -e " ${COLOR_GREEN}-c clean${COLOR_RESET} 清理构建目录" 216 | echo -e " ${COLOR_GREEN}-v VERSION${COLOR_RESET} 指定 Frida 版本" 217 | echo -e " ${COLOR_GREEN}-latest${COLOR_RESET} 使用最新的 Frida 版本" 218 | echo -e " ${COLOR_GREEN}-p, --port PORT${COLOR_RESET} 指定 Frida 服务器端口 (默认: $DEF_FRIDA_SERVER_PORT)" 219 | echo -e " ${COLOR_GREEN}-y, --yes${COLOR_RESET} 自动回答是以确认提示" 220 | echo -e " ${COLOR_GREEN}-l, --local archs[arm,arm64,arm64e] FILENAME${COLOR_RESET} 使用本地 deb 文件,指定构建架构" 221 | echo 222 | echo -e "${COLOR_BG_WHITE}${COLOR_RED}注意: -v, -latest 和 -l 不能同时使用${COLOR_RESET}" 223 | echo -e "${COLOR_BG_WHITE}${COLOR_RED}注意: -l 使用本地 deb 文件时,请使用全路径,或者不要把原始包放到 build 目录,会导致路径冲突。${COLOR_RESET}" 224 | echo -e "${COLOR_WHITE}示例:${COLOR_RESET}" 225 | echo -e " $0 build -v 16.4.2" 226 | echo -e " $0 build -latest" 227 | echo -e " $0 build -l arm64 frida-server_16.4.2_amd64.deb" 228 | echo -e " $0 build -c -l arm64 frida-server_16.4.2_amd64.deb " 229 | echo -e " $0 build -c -l arm64 frida-server_16.4.2_amd64.deb" -p 8000" 230 | echo -e " $0 build -c -l arm64 frida-server_16.4.2_amd64.deb" -p 8000 -y" 231 | } 232 | 233 | show_patch_usage() { 234 | echo -e "${COLOR_SKYBLUE}用法: $0 patch [选项]${COLOR_RESET}" 235 | echo 236 | echo -e "${COLOR_YELLOW}选项:${COLOR_RESET}" 237 | echo -e " ${COLOR_GREEN}-m, --module NAME${COLOR_RESET} 指定要修补的 Frida 模块名称" 238 | echo -e " ${COLOR_GREEN}-v, --version VERSION${COLOR_RESET} 指定 Frida 版本" 239 | echo -e " ${COLOR_GREEN}-latest${COLOR_RESET} 使用最新的 Frida 版本" 240 | echo -e " ${COLOR_GREEN}-os OS${COLOR_RESET} 指定操作系统 (可选)" 241 | echo -e " ${COLOR_GREEN}-arch ARCH${COLOR_RESET} 指定处理器架构 (可选)" 242 | echo -e " ${COLOR_GREEN}-o, --output DIR${COLOR_RESET} 指定输出目录 (默认: ./patched_output)" 243 | echo -e " ${COLOR_GREEN}-n, --no-backup${COLOR_RESET} 不保留源文件 (默认保留)" 244 | echo -e " ${COLOR_GREEN}-a, --auto-package${COLOR_RESET} 自动打包修补后的模块 (默认不打包)" 245 | echo -e " ${COLOR_GREEN}-f, --force${COLOR_RESET} 覆盖已存在的文件 (默认跳过)" 246 | echo 247 | echo -e "${COLOR_WHITE}示例:${COLOR_RESET}" 248 | echo -e " $0 patch -m frida-server -v 14.2.18 -os android -arch arm64 -o ./patched -a" 249 | echo -e " $0 patch -m frida-gadget -latest -os ios -arch arm64 -k -a -f" 250 | } 251 | show_patch_tools_usage() { 252 | echo -e "${COLOR_SKYBLUE}用法: $0 patch-tools <操作> [选项]${COLOR_RESET}" 253 | echo 254 | echo -e "${COLOR_YELLOW}操作:${COLOR_RESET}" 255 | echo -e " ${COLOR_GREEN}name${COLOR_RESET} 配置 frida-tools 魔改名,5个(a-zA-Z)字符,留空则读取配置的名称\"${COLOR_GREEN}${FRIDA_NAME}${COLOR_RESET}\",否则随机生成" 256 | echo -e " ${COLOR_GREEN}restore${COLOR_RESET} 恢复 frida-tools 到原版" 257 | echo 258 | echo -e "${COLOR_WHITE}示例:${COLOR_RESET}" 259 | echo -e " $0 patch-tools name abcde" 260 | echo -e " $0 patch-tools restore" 261 | } 262 | show_patch_wintools_usage(){ 263 | echo -e "${COLOR_SKYBLUE}用法: $0 需要到windows系统下,使用win子目录内的工具进行处理${COLOR_RESET}" 264 | } 265 | show_config_usage() { 266 | echo -e "${COLOR_SKYBLUE}用法: $0 config <操作> <选项> [<值>]${COLOR_RESET}" 267 | echo 268 | echo -e "${COLOR_YELLOW}操作:${COLOR_RESET}" 269 | echo -e " ${COLOR_GREEN}set <选项> <值>${COLOR_RESET} 设置配置" 270 | echo -e " ${COLOR_GREEN}unset <选项>${COLOR_RESET} 取消设置" 271 | echo -e " ${COLOR_GREEN}ls, list${COLOR_RESET} 列出所有配置" 272 | echo -e " ${COLOR_GREEN}edit${COLOR_RESET} 启动交互式配置编辑器" 273 | echo -e " ${COLOR_GREEN}frida-tools${COLOR_RESET} 安装 frida-tools" 274 | echo 275 | echo -e "${COLOR_YELLOW}选项:${COLOR_RESET}" 276 | echo -e " ${COLOR_GREEN}proxy${COLOR_RESET} HTTP 代理" 277 | echo -e " ${COLOR_GREEN}port${COLOR_RESET} Frida 服务器端口" 278 | echo -e " ${COLOR_GREEN}frida-name${COLOR_RESET} Frida 魔改名" 279 | } 280 | 281 | show_download_usage() { 282 | echo -e "${COLOR_SKYBLUE}用法: $0 dl|download [选项] <输出目录>${COLOR_RESET}" 283 | echo 284 | echo -e "${COLOR_YELLOW}选项:${COLOR_RESET}" 285 | echo -e " ${COLOR_GREEN}-v, --version VERSION${COLOR_RESET} 指定要下载的 Frida 版本" 286 | echo -e " ${COLOR_GREEN}-latest${COLOR_RESET} 下载最新的 Frida 版本" 287 | echo -e " ${COLOR_GREEN}-m, --module MODULE${COLOR_RESET} 指定要下载的模块名称" 288 | echo -e " ${COLOR_GREEN}-all${COLOR_RESET} 下载所有模块" 289 | echo -e " ${COLOR_GREEN}--no-extract${COLOR_RESET} 不自动解压文件" 290 | echo -e " ${COLOR_GREEN}-f, --force${COLOR_RESET} 覆盖已存在的文件 (默认跳过)" 291 | echo -e " ${COLOR_GREEN}lm, list-modules${COLOR_RESET} 列出所有可用的模块" 292 | echo 293 | echo -e "${COLOR_WHITE}示例:${COLOR_RESET}" 294 | echo -e " $0 download -v 16.4.2 -m frida-server ./output" 295 | echo -e " $0 download -latest -m frida-gadget ./output" 296 | echo -e " $0 download -latest -all ./output -f" 297 | echo -e " $0 download -latest -all --no-extract ./output" 298 | } 299 | 300 | show_setup_usage() { 301 | echo -e "${COLOR_SKYBLUE}用法: $0 s|setup${COLOR_RESET}" 302 | echo 303 | echo -e "${COLOR_WHITE}检查并安装系统依赖。这个命令将:${COLOR_RESET}" 304 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 检查所有必要的依赖是否已安装" 305 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 如果缺少任何依赖,尝试安装它们" 306 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 创建必要的目录结构(如 build 和 dist 目录)" 307 | echo 308 | echo -e "${COLOR_YELLOW}此命令不需要任何额外的参数。${COLOR_RESET}" 309 | } 310 | 311 | show_upgrade_usage() { 312 | echo -e "${COLOR_SKYBLUE}用法: $0 u|upgrade${COLOR_RESET}" 313 | echo 314 | echo -e "${COLOR_WHITE}更新配置并检查新版本。这个命令将:${COLOR_RESET}" 315 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 更新 FRIDA_MODULES 配置" 316 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 检查 fridare.sh 脚本的新版本" 317 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 如果有新版本可用,提示用户是否要更新" 318 | echo 319 | echo -e "${COLOR_YELLOW}此命令不需要任何额外的参数。${COLOR_RESET}" 320 | } 321 | 322 | show_list_usage() { 323 | echo -e "${COLOR_SKYBLUE}用法: $0 ls|list${COLOR_RESET}" 324 | echo 325 | echo -e "${COLOR_WHITE}列出可用的 Frida 版本。这个命令将:${COLOR_RESET}" 326 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 从 GitHub 获取最新的 Frida 发布版本信息" 327 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 显示最近的 10 个版本,包括版本号、发布日期和下载次数" 328 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 为每个版本显示简短的更新说明" 329 | echo 330 | echo -e "${COLOR_YELLOW}此命令不需要任何额外的参数。${COLOR_RESET}" 331 | } 332 | 333 | show_list_modules_usage() { 334 | echo -e "${COLOR_SKYBLUE}用法: $0 lm|list-modules${COLOR_RESET}" 335 | echo 336 | echo -e "${COLOR_WHITE}列出可用的 Frida 模块。这个命令将:${COLOR_RESET}" 337 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 显示所有可用的 Frida 模块" 338 | echo -e " ${COLOR_GREEN}•${COLOR_RESET} 包括模块名称、支持的操作系统和架构" 339 | echo 340 | echo -e "${COLOR_YELLOW}此命令不需要任何额外的参数。${COLOR_RESET}" 341 | } 342 | 343 | quick_start_guide() { 344 | echo -e "${COLOR_SKYBLUE}快速开始指南${COLOR_RESET}" 345 | echo -e "${COLOR_GREEN}1.${COLOR_RESET} 设置环境: $0 setup" 346 | echo -e "${COLOR_GREEN}2.${COLOR_RESET} 查看可用的 Frida 版本: $0 list" 347 | echo -e "${COLOR_GREEN}3.${COLOR_RESET} 构建 Frida: $0 build -v <版本> 或 $0 build -latest" 348 | echo -e "${COLOR_GREEN}4.${COLOR_RESET} 下载 Frida 模块: $0 download -latest -m frida-server ./output" 349 | echo -e "${COLOR_GREEN}5.${COLOR_RESET} 修补 Frida 模块: $0 patch -m frida-server -latest" 350 | echo -e "${COLOR_GREEN}6.${COLOR_RESET} 配置设置: $0 config edit" 351 | echo -e "\n${COLOR_YELLOW}详细使用说明请运行: $0 help <命令>${COLOR_RESET}" 352 | } 353 | # 函数:解析命令行参数 354 | parse_arguments() { 355 | if [ $# -eq 0 ]; then 356 | show_main_usage 357 | exit 0 358 | fi 359 | 360 | command="$1" 361 | shift 362 | 363 | case "$command" in 364 | b | build) 365 | parse_build_args "$@" 366 | ;; 367 | p | patch) 368 | parse_patch_args "$@" 369 | ;; 370 | s | setup) 371 | setup_environment 372 | ;; 373 | conf | config) 374 | parse_config_args "$@" 375 | ;; 376 | ls | list) 377 | list_frida_versions 378 | ;; 379 | dl | download) 380 | parse_download_args "$@" 381 | ;; 382 | lm | list-modules) 383 | list_frida_modules 384 | ;; 385 | u | upgrade) 386 | update_frida_modules 387 | check_version "false" 388 | ;; 389 | q | quickstart) 390 | quick_start_guide 391 | ;; 392 | h | help) 393 | if [ $# -eq 0 ]; then 394 | show_main_usage 395 | else 396 | case "$1" in 397 | b | build) show_build_usage ;; 398 | p | patch) show_patch_usage ;; 399 | conf | config) show_config_usage ;; 400 | dl | download) show_download_usage ;; 401 | s | setup) show_setup_usage ;; 402 | u | upgrade) show_upgrade_usage ;; 403 | ls | list) show_list_usage ;; 404 | lm | list-modules) show_list_modules_usage ;; 405 | *) 406 | log_error "未知命令: $1" 407 | show_main_usage 408 | ;; 409 | esac 410 | fi 411 | ;; 412 | install) 413 | update_frida_modules 414 | is_install="true" 415 | check_version $is_install 416 | ;; 417 | pt | patch-tools) 418 | parse_patch_tools_args "$@" 419 | ;; 420 | pwt | patch-wintools) 421 | parse_patch_wintools_args "$@" 422 | ;; 423 | *) 424 | log_error "未知命令: $command" 425 | show_main_usage 426 | exit 1 427 | ;; 428 | esac 429 | } 430 | parse_patch_wintools_args(){ 431 | show_patch_wintools_usage 432 | } 433 | parse_patch_tools_args() { 434 | local action="" 435 | local new_name="" 436 | 437 | while [[ $# -gt 0 ]]; do 438 | case $1 in 439 | name) 440 | action="name" 441 | if [[ -n "$2" && ! "$2" =~ ^- ]]; then 442 | new_name="$2" 443 | shift 444 | fi 445 | shift 446 | ;; 447 | restore) 448 | action="restore" 449 | shift 450 | ;; 451 | *) 452 | log_error "无效的参数: $1" 453 | show_patch_tools_usage 454 | exit 1 455 | ;; 456 | esac 457 | done 458 | 459 | if [ -z "$action" ]; then 460 | log_error "必须指定 name 或 restore 操作" 461 | show_patch_tools_usage 462 | exit 1 463 | fi 464 | 465 | local python_cmd=$(get_python_cmd) 466 | if [ -z "$python_cmd" ]; then 467 | log_error "未找到 Python 解释器" 468 | return 1 469 | fi 470 | 471 | local pylib_path=$($python_cmd -c "import os, frida; print(os.path.dirname(frida.__file__))" 2>/dev/null) 472 | if [ $? -ne 0 ]; then 473 | log_error "执行 Python 命令失败,请确保 frida 已正确安装" 474 | return 1 475 | fi 476 | 477 | log_success "找到 frida-tools 路径: $pylib_path" 478 | log_skyblue "是否确认使用此路径?" 479 | read -p "请输入 (y/n)" -n 1 -r 480 | echo 481 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 482 | log_info "操作已取消" 483 | exit 0 484 | fi 485 | 486 | if [ "$action" = "name" ]; then 487 | patch_frida_tools "$new_name" 488 | elif [ "$action" = "restore" ]; then 489 | restore_frida_tools "$pylib_path" 490 | fi 491 | } 492 | get_latest_frida_version() { 493 | local latest_version=$(curl -s "https://api.github.com/repos/frida/frida/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') 494 | if [ -z "$latest_version" ]; then 495 | log_error "无法获取最新的 Frida 版本" 496 | exit 1 497 | fi 498 | echo "$latest_version" 499 | } 500 | parse_build_args() { 501 | FRIDA_SERVER_PORT="$DEF_FRIDA_SERVER_PORT" 502 | AUTO_CONFIRM="false" 503 | USE_LATEST="false" 504 | FRIDA_VERSION="" 505 | clean="false" 506 | LOCAL_DEB="" 507 | LOCAL_ARCH="" 508 | 509 | while [ "$#" -gt 0 ]; do 510 | case "$1" in 511 | -v) 512 | if [ "$USE_LATEST" = "true" ] || [ -n "$LOCAL_DEB" ]; then 513 | log_error "错误: -v 和 -latest 或 -l 不能同时使用" >&2 514 | show_build_usage 515 | exit 1 516 | fi 517 | FRIDA_VERSION="$2" 518 | shift 2 519 | ;; 520 | -latest) 521 | if [ -n "$FRIDA_VERSION" ] || [ -n "$LOCAL_DEB" ]; then 522 | log_error "错误: -latest 和 -v 或 -l 不能同时使用" >&2 523 | show_build_usage 524 | exit 1 525 | fi 526 | USE_LATEST="true" 527 | shift 528 | ;; 529 | -p | --port) 530 | FRIDA_SERVER_PORT="$2" 531 | shift 2 532 | ;; 533 | -y | --yes) 534 | AUTO_CONFIRM="true" 535 | shift 536 | ;; 537 | -c | --clean) 538 | clean="true" 539 | shift 540 | ;; 541 | -l | --local) 542 | if [ -n "$FRIDA_VERSION" ] || [ "$USE_LATEST" = "true" ]; then 543 | log_error "错误: -l 和 -v 或 -latest 不能同时使用" >&2 544 | show_build_usage 545 | exit 1 546 | fi 547 | if [ -z "$2" ] || [ -z "$3" ]; then 548 | log_error "错误: 使用本地文件时必须指定处理器架构 arm, arm64 或 arm64e" >&2 549 | show_build_usage 550 | exit 1 551 | fi 552 | LOCAL_ARCH="$2" 553 | LOCAL_DEB="$3" 554 | shift 3 555 | ;; 556 | *) 557 | log_error "无效选项: $1" >&2 558 | show_build_usage 559 | exit 1 560 | ;; 561 | esac 562 | done 563 | 564 | if [ "$USE_LATEST" = "true" ]; then 565 | FRIDA_VERSION=$(get_latest_frida_version) 566 | log_info "使用最新的 Frida 版本: $FRIDA_VERSION" 567 | elif [ -z "$FRIDA_VERSION" ] && [ -z "$LOCAL_DEB" ]; then 568 | log_error "错误: 必须指定 Frida 版本 (-v) 或使用最新版本 (-latest) 或使用本地文件 (-l)" >&2 569 | show_build_usage 570 | exit 1 571 | else 572 | log_info "使用指定的 Frida 版本: $FRIDA_VERSION" 573 | fi 574 | 575 | # 执行构建逻辑 576 | build_frida "$clean" "$LOCAL_DEB" "$LOCAL_ARCH" 577 | } 578 | parse_config_args() { 579 | if [ $# -eq 0 ]; then 580 | show_config_usage 581 | exit 1 582 | fi 583 | 584 | action="$1" 585 | shift 586 | 587 | case "$action" in 588 | set) 589 | if [ $# -lt 2 ]; then 590 | log_error "set 命令需要一个选项和一个值" 591 | show_config_usage 592 | exit 1 593 | fi 594 | option="$1" 595 | value="$2" 596 | set_config "$option" "$value" 597 | list_config 598 | ;; 599 | unset) 600 | if [ $# -lt 1 ]; then 601 | log_error "unset 命令需要一个选项" 602 | show_config_usage 603 | exit 1 604 | fi 605 | option="$1" 606 | unset_config "$option" 607 | list_config 608 | ;; 609 | ls | list) 610 | list_config 611 | ;; 612 | edit) 613 | interactive_config_editor 614 | ;; 615 | frida-tools) 616 | install_frida_tools 617 | ;; 618 | *) 619 | log_error "未知的配置操作: $action" 620 | show_config_usage 621 | exit 1 622 | ;; 623 | esac 624 | } 625 | 626 | set_config() { 627 | local option="$1" 628 | local value="$2" 629 | case "$option" in 630 | proxy) 631 | CURL_PROXY="$value" 632 | log_success "代理已设置为: $CURL_PROXY" 633 | ;; 634 | port) 635 | FRIDA_SERVER_PORT="$value" 636 | log_success "Frida 服务器端口已设置为: $FRIDA_SERVER_PORT" 637 | ;; 638 | frida-name) 639 | FRIDA_NAME="$value" 640 | log_success "Frida 魔改名已设置为: $FRIDA_NAME" 641 | ;; 642 | *) 643 | log_error "未知的配置选项: $option" 644 | show_config_usage 645 | return 646 | ;; 647 | esac 648 | update_config_file 649 | } 650 | 651 | unset_config() { 652 | local option="$1" 653 | case "$option" in 654 | proxy) 655 | CURL_PROXY="" 656 | log_success "HTTP 代理设置已取消" 657 | ;; 658 | port) 659 | FRIDA_SERVER_PORT="$DEF_FRIDA_SERVER_PORT" 660 | log_success "Frida 服务器端口已重置为默认值: $FRIDA_SERVER_PORT" 661 | ;; 662 | frida-name) 663 | FRIDA_NAME="" 664 | log_success "Frida 魔改名设置已取消" 665 | ;; 666 | *) 667 | log_error "未知的配置选项: $option" 668 | show_config_usage 669 | return 670 | ;; 671 | esac 672 | update_config_file 673 | } 674 | list_config() { 675 | log_info "当前配置 (存储在 $CONFIG_FILE):" 676 | [ -n "$CURL_PROXY" ] && log_info "HTTP 代理: $CURL_PROXY" 677 | log_info "Frida 服务器端口: ${FRIDA_SERVER_PORT:-$DEF_FRIDA_SERVER_PORT}" 678 | [ -n "$FRIDA_NAME" ] && log_info "Frida 魔改名: $FRIDA_NAME" 679 | } 680 | update_config_file() { 681 | echo "#Fridare.sh config" >"$CONFIG_FILE" 682 | echo "FRIDA_SERVER_PORT=${FRIDA_SERVER_PORT}" >>"$CONFIG_FILE" 683 | echo "CURL_PROXY=${CURL_PROXY}" >>"$CONFIG_FILE" 684 | echo "AUTO_CONFIRM=${AUTO_CONFIRM}" >>"$CONFIG_FILE" 685 | echo "FRIDA_NAME=${FRIDA_NAME}" >>"$CONFIG_FILE" 686 | echo "FRIDA_MODULES=(" >>"$CONFIG_FILE" 687 | for module in "${FRIDA_MODULES[@]}"; do 688 | echo "$module" >>"$CONFIG_FILE" 689 | done 690 | echo ")" >>"$CONFIG_FILE" 691 | log_success "配置已更新: $CONFIG_FILE" 692 | } 693 | 694 | interactive_config_editor() { 695 | while true; do 696 | echo -e "${COLOR_SKYBLUE}交互式配置编辑器${COLOR_RESET}" 697 | echo -e "${COLOR_GREEN}1.${COLOR_RESET} 编辑 WEB 代理 ${COLOR_GRAY}(当前: ${CURL_PROXY:-未设置})${COLOR_RESET}" 698 | echo -e "${COLOR_GREEN}2.${COLOR_RESET} 编辑 Frida 服务器端口 ${COLOR_GRAY}(当前: ${FRIDA_SERVER_PORT:-$DEF_FRIDA_SERVER_PORT})${COLOR_RESET}" 699 | echo -e "${COLOR_GREEN}3.${COLOR_RESET} 编辑 Frida 魔改名 ${COLOR_GRAY}(当前: ${FRIDA_NAME:-未设置})${COLOR_RESET}" 700 | echo -e "${COLOR_GREEN}4.${COLOR_RESET} 退出" 701 | read -p "请选择要编辑的项目 (1-4): " choice 702 | case $choice in 703 | 1) 704 | read -p "输入新的 HTTP 代理 (当前: ${CURL_PROXY:-未设置}): " new_proxy 705 | if [ -n "$new_proxy" ]; then 706 | set_config proxy "$new_proxy" 707 | else 708 | echo -e "${COLOR_YELLOW}保持原值不变${COLOR_RESET}" 709 | fi 710 | ;; 711 | 2) 712 | read -p "输入新的 Frida 服务器端口 (当前: ${FRIDA_SERVER_PORT:-$DEF_FRIDA_SERVER_PORT}): " new_port 713 | if [ -n "$new_port" ]; then 714 | set_config port "$new_port" 715 | else 716 | echo -e "${COLOR_YELLOW}保持原值不变${COLOR_RESET}" 717 | fi 718 | ;; 719 | 3) 720 | read -p "输入新的 Frida 魔改名 (当前: ${FRIDA_NAME:-未设置}): " new_name 721 | if [ -n "$new_name" ]; then 722 | # 检查新名称是否有效 723 | if [[ ! "$new_name" =~ ^[a-zA-Z]{5}$ ]]; then 724 | log_error "无效的魔改名: $new_name" 725 | log_info "魔改名必须是恰好 5 个字母(a-z 或 A-Z)" 726 | else 727 | set_config frida-name "$new_name" 728 | fi 729 | else 730 | echo -e "${COLOR_YELLOW}保持原值不变${COLOR_RESET}" 731 | fi 732 | ;; 733 | 4) 734 | return 735 | ;; 736 | *) 737 | echo -e "${COLOR_BG_WHITE}${COLOR_RED}无效的选择${COLOR_RESET}" 738 | ;; 739 | esac 740 | echo 741 | done 742 | } 743 | render_markdown() { 744 | echo "$1" | sed -E ' 745 | # 标题 746 | s/^# (.+)$/\n\\033[1;4;31m\1\\033[0m\n/g; 747 | s/^## (.+)$/\n\\033[1;4;32m\1\\033[0m\n/g; 748 | s/^### (.+)$/\n\\033[1;4;33m\1\\033[0m\n/g; 749 | s/^#### (.+)$/\n\\033[1;4;34m\1\\033[0m\n/g; 750 | s/^##### (.+)$/\n\\033[1;4;35m\1\\033[0m\n/g; 751 | s/^###### (.+)$/\n\\033[1;4;36m\1\\033[0m\n/g; 752 | 753 | # 粗体和斜体 754 | s/\*\*\*([^*]+)\*\*\*/\\033[1;3m\1\\033[0m/g; 755 | s/\*\*([^*]+)\*\*/\\033[1m\1\\033[0m/g; 756 | s/\*([^*]+)\*/\\033[3m\1\\033[0m/g; 757 | s/_([^_]+)_/\\033[3m\1\\033[0m/g; 758 | 759 | # 删除线 760 | s/~~([^~]+)~~/\\033[9m\1\\033[0m/g; 761 | 762 | # 代码块 763 | s/`([^`]+)`/\\033[7m\1\\033[0m/g; 764 | 765 | # 链接 766 | s/\[([^\]]+)\]\(([^\)]+)\)/\\033[4;34m\1\\033[0m (\\033[34m\2\\033[0m)/g; 767 | 768 | # 无序列表 769 | s/^[*+-] (.+)$/ • \1/g; 770 | 771 | # 有序列表 (仅支持前9个项目) 772 | s/^([1-9])\. (.+)$/ \1. \2/g; 773 | 774 | # 水平线 775 | s/^([-*_]{3,})$/\\033[37m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\033[0m/g; 776 | 777 | # 引用 778 | s/^> (.+)$/ ┃ \\033[36m\1\\033[0m/g; 779 | ' 780 | } 781 | list_frida_versions() { 782 | log_info "获取 Frida 最新版本列表..." 783 | 784 | # 使用 GitHub API 获取最新的 10 个发布版本 785 | releases=$(curl -s "https://api.github.com/repos/frida/frida/releases?per_page=10") 786 | 787 | if [ $? -ne 0 ]; then 788 | log_error "无法从 GitHub 获取 Frida 版本信息" 789 | exit 1 790 | fi 791 | 792 | log_success "最新的 Frida 版本:" 793 | log_color ${COLOR_BG_WHITE}${COLOR_BLUE} "序号\t版本\t\t发布日期\t\t下载次数" 794 | echo -e "$(render_markdown "---")" 795 | 796 | echo "$releases" | jq -r '.[] | "\(.tag_name)\t\(.published_at)\t\(.assets | length)"' | 797 | while IFS=$'\t' read -r version date asset_count; do 798 | # 格式化日期 (适用于 macOS) 799 | formatted_date=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$date" "+%Y-%m-%d" 2>/dev/null || echo "$date") 800 | description=$(echo "$releases" | jq -r ".[] | select(.tag_name == \"$version\") | .body" | sed 's/\r//' | sed 's/\n\n/\n/g' | head -n 10) 801 | # 输出格式化的版本信息 802 | rendered_description=$(render_markdown "$description") 803 | printf "${COLOR_GREEN}%2d${COLOR_RESET}\t${COLOR_YELLOW}%-10s${COLOR_RESET}\t%s\t\t%s\n" "$((++i))" "$version" "$formatted_date" "$asset_count" 804 | echo -e "${rendered_description}" 805 | echo -e "$(render_markdown "---")" 806 | done 807 | 808 | echo -e "\n${COLOR_SKYBLUE}提示: 使用 'fridare.sh build -v <版本号>' 来构建特定版本${COLOR_RESET}" 809 | } 810 | FRIDA_MODULES=() 811 | 812 | get_proxy_settings() { 813 | curl_proxy=$(echo $CURL_PROXY) 814 | if [[ -n $curl_proxy ]]; then 815 | echo "$curl_proxy" 816 | else 817 | echo "" 818 | fi 819 | } 820 | 821 | get_latest_release() { 822 | url="https://api.github.com/repos/frida/frida/releases/latest" 823 | proxies=$(get_proxy_settings) 824 | 825 | if [[ -n $proxies ]]; then 826 | response=$(curl -s -H "Accept: application/json" -x "$proxies" "$url") 827 | else 828 | response=$(curl -s -H "Accept: application/json" "$url") 829 | fi 830 | 831 | echo "$response" 832 | } 833 | 834 | parse_filename() { 835 | filename=$1 836 | if [[ $filename =~ (frida[-_]?[a-zA-Z0-9\-]+)?[-_](v?[0-9]+\.[0-9]+\.[0-9]+)[-_]([a-zA-Z0-9\-]+)[-_]([a-zA-Z0-9_]+) ]]; then 837 | module_type=${BASH_REMATCH[1]} 838 | version=${BASH_REMATCH[2]} 839 | os=${BASH_REMATCH[3]} 840 | arch=${BASH_REMATCH[4]} 841 | 842 | [[ $filename == *"."* ]] && ext=${filename##*.} || ext="N/A" 843 | 844 | [[ $arch == "64" ]] && arch="x86_64" 845 | [[ $arch == *"_"* ]] && arch=${arch##*_} 846 | 847 | if [[ $os == "cp"* && $os == *"-"* ]] || [[ $os == *"node-"* ]] || [[ $os == *"electron-"* ]]; then 848 | IFS='-' read -ra os_info <<<"$os" 849 | os_count=${#os_info[@]} 850 | if [ $os_count -gt 0 ]; then 851 | new_os=${os_info[$os_count - 1]} 852 | if [ $os_count -gt 2 ]; then 853 | if [[ $os == "cp"* ]]; then 854 | new_module_type="frida-python-${os_info[0]}-${os_info[1]}" 855 | else 856 | new_module_type="frida-${os_info[0]}-${os_info[1]}" 857 | fi 858 | module_type=$new_module_type 859 | fi 860 | os=$new_os 861 | fi 862 | elif [[ $os == *"-"* ]]; then 863 | os=${os%%-*} 864 | fi 865 | 866 | [[ -z $module_type && $filename == *"deb"* ]] && module_type="frida-${os}-deb" 867 | [[ -z $module_type && $filename == *"gum-graft"* ]] && module_type="gum-graft" && os=${filename##*-} && arch=${filename##*-}.${ext} 868 | 869 | echo "$module_type:$version:$os:$arch:$ext" 870 | else 871 | echo "null" 872 | fi 873 | } 874 | 875 | generate_frida_modules() { 876 | release=$(get_latest_release) 877 | assets=$(echo "$release" | awk -F'"' '/"browser_download_url":/{print $4}') 878 | 879 | frida_modules=() 880 | for asset in $assets; do 881 | filename=$(basename "$asset") 882 | parsed=$(parse_filename "$filename") 883 | if [[ $parsed != "null" ]]; then 884 | IFS=':' read -r module_type version os arch ext <<<"$parsed" 885 | [[ $version == v* ]] && version=${version#v} 886 | asset_name=${filename//$version/"{VERSION}"} 887 | frida_modules+=("$module_type:$os:$arch:$asset_name") 888 | fi 889 | done 890 | 891 | printf '%s\n' "${frida_modules[@]}" 892 | } 893 | 894 | update_frida_modules() { 895 | log_info "正在更新 FRIDA_MODULES..." 896 | 897 | # 确保 CURL_PROXY 环境变量可用于 Python 脚本 898 | local new_modules=$(generate_frida_modules) 899 | 900 | if [ $? -ne 0 ]; then 901 | log_error "更新 FRIDA_MODULES 失败" 902 | return 1 903 | fi 904 | 905 | FRIDA_MODULES=() 906 | FRIDA_MODULES=("$new_modules") 907 | # 更新配置文件中的 FRIDA_MODULES 908 | update_config_file 909 | log_success "FRIDA_MODULES 更新完成" 910 | return 0 911 | } 912 | list_frida_modules() { 913 | # 检查 FRIDA_MODULES 是否为空 914 | if [ ${#FRIDA_MODULES[@]} -eq 0 ]; then 915 | log_info "FRIDA_MODULES 为空,正在更新..." 916 | update_frida_modules 917 | # 重新加载配置文件以获取更新后的 FRIDA_MODULES 918 | source "$CONFIG_FILE" 919 | fi 920 | 921 | log_info "可用的 Frida 模块:" 922 | # 使用临时文件来存储和排序唯一的模块 923 | temp_file=$(mktemp) 924 | 925 | # 添加表头 926 | echo -e "模块名称\t操作系统\t架构" >"$temp_file" 927 | echo -e "-------\t-------\t----" >>"$temp_file" 928 | 929 | for item in "${FRIDA_MODULES[@]}"; do 930 | IFS=':' read -r mod os arch filename <<<"$item" 931 | echo -e "$mod\t$os\t$arch" >>"$temp_file" 932 | done 933 | 934 | # 使用 column 命令对齐输出,并删除临时文件 935 | column -t -s $'\t' <"$temp_file" 936 | rm -f "$temp_file" 937 | } 938 | 939 | parse_download_args() { 940 | local version="" 941 | local module="" 942 | local output_dir="" 943 | local use_latest=false 944 | local download_all=false 945 | local no_extract=false 946 | local os="" 947 | local arch="" 948 | local force=false 949 | 950 | while [[ $# -gt 0 ]]; do 951 | case $1 in 952 | ls | list-modules) 953 | list_frida_modules 954 | exit 0 955 | ;; 956 | -v | --version) 957 | version="$2" 958 | shift 2 959 | ;; 960 | -latest) 961 | use_latest=true 962 | shift 963 | ;; 964 | -m | --module) 965 | module="$2" 966 | shift 2 967 | ;; 968 | -all) 969 | download_all=true 970 | shift 971 | ;; 972 | --no-extract) 973 | no_extract=true 974 | shift 975 | ;; 976 | -os) 977 | os="$2" 978 | shift 2 979 | ;; 980 | -arch) 981 | arch="$2" 982 | shift 2 983 | ;; 984 | -f | --force) 985 | force=true 986 | shift 987 | ;; 988 | *) 989 | if [[ -z "$output_dir" ]]; then 990 | output_dir="$1" 991 | shift 992 | else 993 | log_error "无效的参数: $1" 994 | show_download_usage 995 | exit 1 996 | fi 997 | ;; 998 | esac 999 | done 1000 | 1001 | if [[ -z "$output_dir" ]]; then 1002 | log_error "必须指定输出目录" 1003 | show_download_usage 1004 | exit 1 1005 | fi 1006 | 1007 | if [[ "$use_latest" == true && -n "$version" ]]; then 1008 | log_error "不能同时指定版本和使用最新版本" 1009 | show_download_usage 1010 | exit 1 1011 | fi 1012 | 1013 | if [[ "$download_all" == true && -n "$module" ]]; then 1014 | log_error "不能同时指定模块和下载所有模块" 1015 | show_download_usage 1016 | exit 1 1017 | fi 1018 | 1019 | # 执行下载逻辑 1020 | download_frida_module "$version" "$use_latest" "$module" "$download_all" "$output_dir" "$no_extract" "$os" "$arch" "$force" 1021 | } 1022 | download_frida_module() { 1023 | local version="$1" 1024 | local use_latest="$2" 1025 | local module="$3" 1026 | local download_all="$4" 1027 | local output_dir="$5" 1028 | local no_extract="$6" 1029 | local os="$7" 1030 | local arch="$8" 1031 | local force="$9" 1032 | 1033 | # 如果使用最新版本,获取最新版本号 1034 | if [[ "$use_latest" == true ]]; then 1035 | version=$(get_latest_frida_version) 1036 | log_info "使用最新版本: $version" 1037 | fi 1038 | # 如果指定了模块,检查模块是否存在 1039 | if [[ -n "$module" ]]; then 1040 | local module_found=false 1041 | for item in "${FRIDA_MODULES[@]}"; do 1042 | IFS=':' read -r item_mod item_os item_arch filename <<<"$item" 1043 | if [[ "$item_mod" == "$module" ]]; then 1044 | module_found=true 1045 | break 1046 | fi 1047 | done 1048 | if [[ "$module_found" == false ]]; then 1049 | log_error "指定的模块 '$module' 不存在。使用 'download list-modules' 查看可用模块。" 1050 | exit 1 1051 | fi 1052 | fi 1053 | # 检查 7z 是否安装 1054 | if ! command -v 7z &>/dev/null; then 1055 | log_warning "7z 未安装,将使用系统默认解压工具" 1056 | fi 1057 | 1058 | # 创建基础输出目录 1059 | mkdir -p "$output_dir" 1060 | 1061 | local found_match=false 1062 | # 遍历模块列表 1063 | for item in "${FRIDA_MODULES[@]}"; do 1064 | IFS=':' read -r item_mod item_os item_arch filename <<<"$item" 1065 | # 如果指定了模块且不匹配,则跳过 1066 | if [ "$item_mod" != "$module" ]; then 1067 | # 如果不是下载全部,找到匹配项后就退出循环 1068 | if [[ "$download_all" != true ]]; then 1069 | continue 1070 | fi 1071 | fi 1072 | found_match=true 1073 | 1074 | # 替换文件名中的版本占位符 1075 | filename="${filename/\{VERSION\}/$version}" 1076 | 1077 | # 创建目录结构 1078 | local dir="${output_dir}/${version}/${item_mod}/${item_os}/${item_arch}" 1079 | mkdir -p "$dir" 1080 | 1081 | local url="https://github.com/frida/frida/releases/download/${version}/${filename}" 1082 | local output_file="${dir}/${filename}" 1083 | 1084 | if [[ -f "$output_file" && "$force" != true ]]; then 1085 | log_info "文件 $filename 已存在,跳过下载" 1086 | else 1087 | log_info "正在下载 $filename 到 $dir" 1088 | download_with_progress "$url" "$output_file" "$filename" 1089 | 1090 | log_success "下载 $filename 完成" 1091 | fi 1092 | # 解压逻辑 1093 | if [[ "$no_extract" != true ]]; then 1094 | if [[ "$filename" != *.deb && "$filename" != *.whl ]]; then # 排除 deb 和 whl 文件 1095 | if command -v 7z &>/dev/null; then 1096 | log_info "使用 7z 解压 $filename..." 1097 | 7z x "$output_file" -o"$dir" -y || { 1098 | log_error "解压 $filename 失败" 1099 | continue 1100 | } 1101 | rm -rf $output_file 1102 | else 1103 | case "$filename" in 1104 | *.tar.xz) 1105 | log_info "解压 $filename..." 1106 | tar -xJf "$output_file" -C "$dir" || { 1107 | log_error "解压 $filename 失败" 1108 | continue 1109 | } 1110 | rm -rf $output_file 1111 | ;; 1112 | *.xz) 1113 | log_info "解压 $filename..." 1114 | xz -d "$output_file" || { 1115 | log_error "解压 $filename 失败" 1116 | continue 1117 | } 1118 | rm -rf $output_file 1119 | ;; 1120 | *.gz) 1121 | log_info "解压 $filename..." 1122 | gzip -d "$output_file" || { 1123 | log_error "解压 $filename 失败" 1124 | continue 1125 | } 1126 | rm -rf $output_file 1127 | ;; 1128 | *) 1129 | log_warning "无法识别的压缩格式: $filename,跳过解压" 1130 | ;; 1131 | esac 1132 | fi 1133 | log_success "解压 $filename 完成" 1134 | else 1135 | log_info "跳过解压 $filename (deb 或 whl 文件)" 1136 | fi 1137 | fi 1138 | 1139 | done 1140 | if [[ "$found_match" == false ]]; then 1141 | log_error "没有找到匹配的模块: $module (OS: $item_os, Arch: $item_arch)" 1142 | return 1 1143 | fi 1144 | log_success "所有下载和解压操作完成" 1145 | } 1146 | parse_patch_args() { 1147 | local module="" 1148 | local version="" 1149 | local use_latest=false 1150 | local os="" 1151 | local arch="" 1152 | local output_dir="${SCRIPT_WORK_DIR}/patched" 1153 | local no_backup=false 1154 | local auto_package=false 1155 | local force=false 1156 | 1157 | while [[ $# -gt 0 ]]; do 1158 | case $1 in 1159 | -m | --module) 1160 | module="$2" 1161 | shift 2 1162 | ;; 1163 | -v | --version) 1164 | version="$2" 1165 | shift 2 1166 | ;; 1167 | -latest) 1168 | use_latest=true 1169 | shift 1170 | ;; 1171 | -os) 1172 | os="$2" 1173 | shift 2 1174 | ;; 1175 | -arch) 1176 | arch="$2" 1177 | shift 2 1178 | ;; 1179 | -o | --output) 1180 | output_dir="$2" 1181 | shift 2 1182 | ;; 1183 | -n | --no-backup) 1184 | no_backup=true 1185 | shift 1186 | ;; 1187 | -a | --auto-package) 1188 | auto_package=true 1189 | shift 1190 | ;; 1191 | -f | --force) 1192 | force=true 1193 | shift 1194 | ;; 1195 | *) 1196 | log_error "无效的参数: $1" 1197 | show_patch_usage 1198 | exit 1 1199 | ;; 1200 | esac 1201 | done 1202 | 1203 | if [ -z "$module" ]; then 1204 | log_error "必须指定模块名称" 1205 | show_patch_usage 1206 | exit 1 1207 | fi 1208 | 1209 | if [ "$use_latest" = true ] && [ -n "$version" ]; then 1210 | log_error "不能同时指定版本和使用最新版本" 1211 | show_patch_usage 1212 | exit 1 1213 | fi 1214 | 1215 | if [ "$use_latest" = false ] && [ -z "$version" ]; then 1216 | log_error "必须指定版本或使用 -latest 选项" 1217 | show_patch_usage 1218 | exit 1 1219 | fi 1220 | 1221 | # 如果使用最新版本,获取最新版本号 1222 | if [ "$use_latest" = true ]; then 1223 | version=$(get_latest_frida_version) 1224 | log_info "使用最新版本: $version" 1225 | fi 1226 | 1227 | # 执行修补逻辑 1228 | patch_frida_module "$module" "$version" "$os" "$arch" "$output_dir" "$keep_source" "$auto_package" "$force" 1229 | } 1230 | 1231 | patch_frida_module() { 1232 | local module="$1" 1233 | local version="$2" 1234 | local os="$3" 1235 | local arch="$4" 1236 | local output_dir="$5" 1237 | local keep_source="$6" 1238 | local auto_package="$7" 1239 | local force="$8" 1240 | 1241 | log_info "准备下载模块: $module, 版本: $version, OS: $os, 架构: $arch, 输出目录: $output_dir, 保留源码: $keep_source, 自动打包: $auto_package, 强制下载: $force" 1242 | 1243 | # 首先下载模块 1244 | download_frida_module "$version" false "$module" false "$output_dir" false "$os" "$arch" "$force" 1245 | 1246 | # 获取下载的文件路径 1247 | local downloaded_file=$(find "$output_dir" -name "${module}*-${os}*-${arch}*" -type f | head -n 1) 1248 | if [ -z "$downloaded_file" ]; then 1249 | log_error "无法找到下载的模块文件" 1250 | return 1 1251 | fi 1252 | 1253 | log_info "正在修补文件: $downloaded_file" 1254 | 1255 | # 编译hexreplace工具 1256 | (cd $SCRIPT_WORK_DIR/hexreplace && go build -o $SCRIPT_WORK_DIR/build/hexreplace && cd ..) || { 1257 | log_error "编译 hexreplace 工具失败" 1258 | return 1 1259 | } 1260 | chmod +x $SCRIPT_WORK_DIR/build/hexreplace 1261 | 1262 | # 生成新的Frida名称(如果未指定则提示进行配置: config set frida-name ) 1263 | if [ -z "$FRIDA_NAME" ]; then 1264 | log_error "未指定 Frida 魔改名,请使用 config set frida-name 命令指定" 1265 | read -p "请输入本次所采用的 Frida 魔改名: " value 1266 | if [[ "$value" =~ ^[a-zA-Z]{5}$ ]]; then 1267 | FRIDA_NAME="$value" 1268 | log_success "Frida 魔改名已设置为: $FRIDA_NAME" 1269 | else 1270 | log_error "无效的 Frida 魔改名: $value" 1271 | log_info "Frida 魔改名必须是恰好 5 个字母(a-z 或 A-Z)" 1272 | return 1 1273 | fi 1274 | else 1275 | log_info "使用指定的 Frida 魔改名: $FRIDA_NAME" 1276 | fi 1277 | 1278 | # 修补二进制文件 1279 | local patched_file="${output_dir}/${module}_${FRIDA_NAME}" 1280 | ($SCRIPT_WORK_DIR/build/hexreplace "$downloaded_file" "$FRIDA_NAME" "$patched_file") || { 1281 | log_error "修改 ${module} 二进制失败" 1282 | return 1 1283 | } 1284 | 1285 | # 设置权限 1286 | sudo chmod +x "$patched_file" 1287 | sudo chown root:wheel "$patched_file" 1288 | 1289 | log_success "模块修补完成: $patched_file" 1290 | 1291 | # 处理源文件 1292 | if [ "$no_backup" = true ]; then 1293 | rm -f "$downloaded_file" 1294 | log_info "已删除源文件" 1295 | fi 1296 | 1297 | # 自动打包 1298 | if [ "$auto_package" = true ]; then 1299 | log_info "正在自动打包修补后的模块..." 1300 | 1301 | # 获取原始文件的扩展名 1302 | local original_extension="${downloaded_file##*.}" 1303 | local packed_file="${patched_file}.${original_extension}" 1304 | 1305 | # 使用7z进行压缩 1306 | if command -v 7z &>/dev/null; then 1307 | case "$original_extension" in 1308 | xz | gz | zip | tar | bz2 | 7z) 1309 | 7z a -t"$original_extension" "$packed_file" "$patched_file" >/dev/null || { 1310 | log_error "使用 7z 压缩失败" 1311 | return 1 1312 | } 1313 | ;; 1314 | *) 1315 | # 对于未知格式,使用gzip压缩 1316 | gzip -c "$patched_file" >"${patched_file}.gz" || { 1317 | log_error "使用 gzip 压缩失败" 1318 | return 1 1319 | } 1320 | packed_file="${patched_file}.gz" 1321 | log_warning "未知的压缩格式: ${original_extension}, 使用 gzip 压缩" 1322 | ;; 1323 | esac 1324 | else 1325 | # 如果7z不可用,退回到使用gzip 1326 | gzip -c "$patched_file" >"${patched_file}.gz" || { 1327 | log_error "使用 gzip 压缩失败" 1328 | return 1 1329 | } 1330 | packed_file="${patched_file}.gz" 1331 | log_warning "7z 不可用,使用 gzip 压缩" 1332 | fi 1333 | 1334 | if [ "$packed_file" != "$patched_file" ]; then 1335 | log_success "模块已打包: $packed_file" 1336 | # 如果不保留源文件,删除未压缩的修补文件 1337 | if [ "$no_backup" = true ]; then 1338 | rm -f "$patched_file" 1339 | log_info "已删除未压缩的修补文件" 1340 | fi 1341 | fi 1342 | fi 1343 | 1344 | return 0 1345 | } 1346 | # 用户确认函数 1347 | confirm_execution() { 1348 | if [ "$AUTO_CONFIRM" = "true" ]; then 1349 | log_warning "自动确认模式:用户已同意免责声明和sudo权限使用。" 1350 | return 0 1351 | fi 1352 | 1353 | log_color $COLOR_PURPLE "$DISCLAIMER" 1354 | log_warning "本脚本将会要求使用sudo权限以修改文件权限。" 1355 | 1356 | read -p "您是否同意以上免责声明并允许使用sudo权限?(y/N) " response 1357 | case "$response" in 1358 | [yY][eE][sS] | [yY]) 1359 | return 0 1360 | ;; 1361 | *) 1362 | log_info "用户不同意,操作已取消" 1363 | exit 0 1364 | ;; 1365 | esac 1366 | } 1367 | confirm_modify_frida_tools() { 1368 | if [ "$AUTO_CONFIRM" = "true" ]; then 1369 | log_warning "自动确认模式:用户已同意自动修改本地 frida-tools。" 1370 | return 0 1371 | fi 1372 | log_color $COLOR_PURPLE "本脚本将自动修改本地 frida-tools,以适配魔改版本的 Frida。(跳过 frida-tools 魔改。某些功能可能无法使用,建议修改)" 1373 | read -p "您是否同意?(y/N) " response 1374 | case "$response" in 1375 | [yY][eE][sS] | [yY]) 1376 | return 0 1377 | ;; 1378 | *) 1379 | log_info "用户不同意,操作已取消" 1380 | return 1 1381 | ;; 1382 | esac 1383 | } 1384 | check_dependencies() { 1385 | local missing_tools=() 1386 | local tools=("xcode-select" "brew" "git" "jq" "dpkg-deb" "go" "python3" "7z" "curl" "xz" "gzip") 1387 | 1388 | for tool in "${tools[@]}"; do 1389 | if ! command -v $tool &>/dev/null; then 1390 | missing_tools+=("$tool") 1391 | log_warning "$COLOR_YELLOW$tool$COLOR_RESET ${COLOR_PURPLE}未找到" 1392 | else 1393 | log_success "$COLOR_YELLOW$tool$COLOR_RESET ${COLOR_SKYBLUE}已安装" 1394 | fi 1395 | done 1396 | 1397 | # 检查 Frida 工具 1398 | if ! check_frida_tool; then 1399 | missing_tools+=("frida-tools") 1400 | log_warning "${COLOR_YELLOW}frida-tools${COLOR_RESET} ${COLOR_PURPLE}未找到" 1401 | else 1402 | log_success "${COLOR_YELLOW}frida-tools$COLOR_RESET ${COLOR_SKYBLUE}已安装" 1403 | fi 1404 | 1405 | if [ ${#missing_tools[@]} -eq 0 ]; then 1406 | log_success "所有依赖已安装" 1407 | return 0 1408 | else 1409 | log_warning "以下工具未安装: ${missing_tools[*]}" 1410 | return 1 1411 | fi 1412 | 1413 | } 1414 | 1415 | install_dependencies() { 1416 | log_warning "正在安装缺失的依赖..." 1417 | confirm_execution 1418 | 1419 | check_and_install_tool "xcode-select" "xcode-select --install" 1420 | check_and_install_tool "brew" "curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash" 1421 | check_and_install_tool "git" "brew install git" 1422 | check_and_install_tool "jq" "brew install jq" 1423 | check_and_install_tool "dpkg-deb" "brew install dpkg" 1424 | check_and_install_tool "go" "brew install go" 1425 | check_and_install_tool "python3" "brew install python3" 1426 | check_and_install_tool "7z" "brew install p7zip" 1427 | check_and_install_tool "curl" "brew install curl" 1428 | check_and_install_tool "xz" "brew install xz" 1429 | check_and_install_tool "gzip" "brew install gzip" 1430 | 1431 | install_frida_tools 1432 | 1433 | log_success "依赖安装完成" 1434 | } 1435 | 1436 | setup_environment() { 1437 | log_info "检查系统依赖..." 1438 | if ! check_dependencies; then 1439 | install_dependencies 1440 | fi 1441 | 1442 | log_success "环境设置完成" 1443 | } 1444 | check_frida_tool() { 1445 | if command -v frida-ps >/dev/null 2>&1; then 1446 | return 0 1447 | else 1448 | return 1 1449 | fi 1450 | } 1451 | install_frida_tools() { 1452 | log_info "正在安装 frida-tools..." 1453 | 1454 | local pip_commands=("pip" "pip3") 1455 | for pip_cmd in "${pip_commands[@]}"; do 1456 | if command -v "$pip_cmd" >/dev/null 2>&1; then 1457 | if $pip_cmd install --user frida-tools --force-reinstall; then 1458 | log_success "frida-tools 安装成功" 1459 | return 0 1460 | else 1461 | log_error "使用 $pip_cmd 安装 frida-tools 失败" 1462 | fi 1463 | fi 1464 | done 1465 | 1466 | log_error "无法安装 frida-tools。请确保 pip 已正确安装并且网络连接正常。" 1467 | return 1 1468 | } 1469 | check_and_install_tool() { 1470 | local tool=$1 1471 | local install_cmd=$2 1472 | 1473 | if ! command -v $tool &>/dev/null; then 1474 | log_warning "$tool 未找到,正在安装..." 1475 | eval $install_cmd || { 1476 | log_error "安装 $tool 失败" 1477 | exit 1 1478 | } 1479 | else 1480 | log_success "$tool 已安装" 1481 | fi 1482 | } 1483 | # 函数:下载 Frida 1484 | download_frida() { 1485 | local arch=$1 1486 | local fridaver=$2 1487 | local clean=$3 1488 | local filename="frida_${fridaver}_iphoneos-${arch}.deb" 1489 | local output="${SCRIPT_WORK_DIR}/build/$filename" 1490 | # 如果本地文件存在 1491 | if [ -f "$output" ]; then 1492 | if [ "$clean" = "true" ]; then 1493 | log_warning "清理旧文件: $output" 1494 | rm -f $output 1495 | fi 1496 | fi 1497 | 1498 | if [ ! -f "$output" ]; then 1499 | local url="https://github.com/frida/frida/releases/download/${fridaver}/${filename}" 1500 | echo $url 1501 | download_with_progress "$url" "$output" 1502 | else 1503 | log_warning "本地存在 $filename" 1504 | fi 1505 | 1506 | log_success "下载 $filename 完成" 1507 | } 1508 | # 新增函数:删除目录内的所有 .DS_Store 文件 1509 | remove_ds_store() { 1510 | local dir=$1 1511 | log_success "正在删除 $dir 中的 .DS_Store 文件..." 1512 | find "$dir" -name ".DS_Store" -type f -delete 1513 | log_info ".DS_Store 文件删除完成" 1514 | } 1515 | 1516 | modify_launch_daemon() { 1517 | local build=$1 1518 | local arch=$2 1519 | local plist 1520 | 1521 | if [ "$arch" = "arm64" ]; then 1522 | plist="${build}/var/jb/Library/LaunchDaemons/re.frida.server.plist" 1523 | else 1524 | plist="${build}/Library/LaunchDaemons/re.frida.server.plist" 1525 | fi 1526 | 1527 | if [ ! -f "$plist" ]; then 1528 | log_error "错误: plist 文件不存在: $plist" 1529 | return 1 1530 | fi 1531 | 1532 | log_success "正在修改 plist 文件: $plist" 1533 | log_info "FRIDA_NAME: $FRIDA_NAME" 1534 | log_info "FRIDA_SERVER_PORT: $FRIDA_SERVER_PORT" 1535 | 1536 | # 检查变量是否为空 1537 | if [ -z "$FRIDA_NAME" ] || [ -z "$FRIDA_SERVER_PORT" ]; then 1538 | log_error "错误: FRIDA_NAME 或 FRIDA_SERVER_PORT 为空" 1539 | return 1 1540 | fi 1541 | 1542 | # 使用 -e 选项为每个替换操作创建单独的 sed 命令 1543 | sed -i '' \ 1544 | -e 's/re\.frida\.server/re.'"${FRIDA_NAME}"'.server/g' \ 1545 | -e 's/frida-server/'"${FRIDA_NAME}"'/g' \ 1546 | -e 's@@\t-l\n\t\t0.0.0.0:'"${FRIDA_SERVER_PORT}"'\n\t@g' \ 1547 | "$plist" 1548 | 1549 | if [ $? -ne 0 ]; then 1550 | log_error "错误: sed 命令执行失败" 1551 | return 1 1552 | fi 1553 | 1554 | log_success "plist 文件修改完成" 1555 | 1556 | # 收到一个 arm64e 的版本,对它做了适配: 1557 | # 检查 usr/sbin/frida-server-wrapper 和 usr/sbin/frida-server.ent 1558 | # 存在则更名 ${FRIDA_NAME}-server-wrapper 和 usr/sbin/${FRIDA_NAME}-server.ent 1559 | # 打开 ${FRIDA_NAME}-server-wrapper ,进行替换 1560 | # exec /usr/sbin/frida-server $@ 替换为 exec /usr/sbin/${FRIDA_NAME}-server $@ 1561 | # 打开 usr/sbin/${FRIDA_NAME}-server.ent,进行替换 1562 | # re.frida.Server 替换为 re.${FRIDA_NAME}.Server 1563 | # 修改2个文件权限 1564 | # local frida_server_wrapper_file="${build}/usr/sbin/frida-server-wrapper" 1565 | # local new_frida_server_wrapper_file="${build}/usr/sbin/${FRIDA_NAME}-server-wrapper" 1566 | # local frida_server_ent_file="${build}/usr/sbin/frida-server.ent" 1567 | # local new_frida_server_ent_file="${build}/usr/sbin/${FRIDA_NAME}-server.ent" 1568 | 1569 | # if [ -f "$frida_server_wrapper_file" ]; then 1570 | # log_success "正在修改 frida-server-wrapper 文件: $frida_server_wrapper_file" 1571 | # sed -i '' 's/exec \/usr\/sbin\/frida-server/exec \/usr\/sbin\/'"${FRIDA_NAME}"'-server/g' "$frida_server_wrapper_file" 1572 | # if [ $? -ne 0 ]; then 1573 | # log_error "错误: 修改 frida-server-wrapper 文件失败" 1574 | # return 1 1575 | # fi 1576 | # log_success "frida-server-wrapper 文件修改完成" 1577 | # mv "$frida_server_wrapper_file" "$new_frida_server_wrapper_file" 1578 | # if [ $? -ne 0 ]; then 1579 | # log_error "错误: 重命名 frida-server-wrapper 文件失败" 1580 | # return 1 1581 | # fi 1582 | # log_success "frida-server-wrapper 文件已重命名为: $new_frida_server_wrapper_file" 1583 | # sudo chown root:wheel $new_frida_server_wrapper_file 1584 | # if [ $? -ne 0 ]; then 1585 | # log_error "错误: 修改 frida-server-wrapper 文件权限失败" 1586 | # return 1 1587 | # fi 1588 | # log_success "frida-server-wrapper 文件权限修改完成" 1589 | # else 1590 | # log_warning "警告: frida-server-wrapper 文件不存在: $frida_server_wrapper_file" 1591 | # fi 1592 | 1593 | # if [ -f "$frida_server_ent_file" ]; then 1594 | # log_success "正在修改 frida-server.ent 文件: $frida_server_ent_file" 1595 | # sed -i '' 's/re\.frida\.Server/re.'"${FRIDA_NAME}"'.Server/g' "$frida_server_ent_file" 1596 | # if [ $? -ne 0 ]; then 1597 | # log_error "错误: 修改 frida-server.ent 文件失败" 1598 | # return 1 1599 | # fi 1600 | # log_success "frida-server.ent 文件修改完成" 1601 | # mv "$frida_server_ent_file" "$new_frida_server_ent_file" 1602 | # if [ $? -ne 0 ]; then 1603 | # log_error "错误: 重命名 frida-server.ent 文件失败" 1604 | # return 1 1605 | # fi 1606 | # log_success "frida-server.ent 文件已重命名为: $new_frida_server_ent_file" 1607 | # sudo chown root:wheel $new_frida_server_ent_file 1608 | # if [ $? -ne 0 ]; then 1609 | # log_error "错误: 修改 frida-server.ent 文件权限失败" 1610 | # return 1 1611 | # fi 1612 | # log_success "frida-server.ent 文件权限修改完成" 1613 | # else 1614 | # log_warning "警告: frida-server.ent 文件不存在: $frida_server_ent_file" 1615 | # fi 1616 | 1617 | # log_success "frida-server-wrapper 和 frida-server.ent 文件修改完成" 1618 | 1619 | # 重命名 plist 文件 1620 | local new_plist 1621 | if [ "$arch" = "arm64" ]; then 1622 | new_plist="${build}/var/jb/Library/LaunchDaemons/re.${FRIDA_NAME}.server.plist" 1623 | else 1624 | new_plist="${build}/Library/LaunchDaemons/re.${FRIDA_NAME}.server.plist" 1625 | fi 1626 | 1627 | mv "$plist" "$new_plist" 1628 | sudo chown root:wheel $new_plist 1629 | 1630 | if [ $? -ne 0 ]; then 1631 | log_error "错误: 重命名 plist 文件失败" 1632 | return 1 1633 | fi 1634 | 1635 | log_success "plist 文件已重命名为: $new_plist" 1636 | } 1637 | 1638 | modify_debian_files() { 1639 | local build=$1 1640 | local arch=$2 1641 | local debian_dir 1642 | 1643 | debian_dir="${build}/DEBIAN" 1644 | 1645 | log_success "正在修改 DEBIAN 文件夹中的文件: $debian_dir" 1646 | log_info "FRIDA_NAME: $FRIDA_NAME" 1647 | 1648 | # 检查变量是否为空 1649 | if [ -z "$FRIDA_NAME" ]; then 1650 | log_error "错误: FRIDA_NAME 为空" 1651 | return 1 1652 | fi 1653 | 1654 | # 修改 control 文件 1655 | local control_file="${debian_dir}/control" 1656 | if [ -f "$control_file" ]; then 1657 | log_info "修改 control 文件" 1658 | sed -i '' 's/Package: re\.frida\.server/Package: re.'"${FRIDA_NAME}"'.server/g' "$control_file" 1659 | if [ $? -ne 0 ]; then 1660 | log_error "错误: 修改 control 文件失败" 1661 | return 1 1662 | fi 1663 | else 1664 | log_warning "警告: control 文件不存在: $control_file" 1665 | fi 1666 | sudo chown root:wheel $control_file 1667 | 1668 | # 修改 extrainst_ 文件 1669 | local extrainst_file="${debian_dir}/extrainst_" 1670 | if [ -f "$extrainst_file" ]; then 1671 | log_info "修改 extrainst_ 文件" 1672 | if [ "$arch" = "arm64" ]; then 1673 | sed -i '' 's@launchcfg=/var/jb/Library/LaunchDaemons/re\.frida\.server\.plist@launchcfg=/var/jb/Library/LaunchDaemons/re.'"${FRIDA_NAME}"'.server.plist@g' "$extrainst_file" 1674 | else 1675 | sed -i '' 's@launchcfg=/Library/LaunchDaemons/re\.frida\.server\.plist@launchcfg=/Library/LaunchDaemons/re.'"${FRIDA_NAME}"'.server.plist@g' "$extrainst_file" 1676 | fi 1677 | if [ $? -ne 0 ]; then 1678 | log_error "错误: 修改 extrainst_ 文件失败" 1679 | return 1 1680 | fi 1681 | else 1682 | log_warning "警告: extrainst_ 文件不存在: $extrainst_file" 1683 | fi 1684 | sudo chown root:wheel $extrainst_file 1685 | 1686 | # 修改 prerm 文件 1687 | local prerm_file="${debian_dir}/prerm" 1688 | if [ -f "$prerm_file" ]; then 1689 | log_info "修改 prerm 文件" 1690 | if [ "$arch" = "arm64" ]; then 1691 | sed -i '' 's@launchctl unload /var/jb/Library/LaunchDaemons/re\.frida\.server\.plist@launchctl unload /var/jb/Library/LaunchDaemons/re.'"${FRIDA_NAME}"'.server.plist@g' "$prerm_file" 1692 | else 1693 | sed -i '' 's@launchctl unload /Library/LaunchDaemons/re\.frida\.server\.plist@launchctl unload /Library/LaunchDaemons/re.'"${FRIDA_NAME}"'.server.plist@g' "$prerm_file" 1694 | fi 1695 | if [ $? -ne 0 ]; then 1696 | log_error "错误: 修改 prerm 文件失败" 1697 | return 1 1698 | fi 1699 | else 1700 | log_warning "警告: prerm 文件不存在: $prerm_file" 1701 | fi 1702 | sudo chown root:wheel $prerm_file 1703 | 1704 | log_success "DEBIAN 文件夹中的文件修改完成" 1705 | } 1706 | 1707 | modify_binary() { 1708 | local build=$1 1709 | local arch=$2 1710 | local frida_server_path 1711 | local new_path 1712 | local frida_dylib_file 1713 | local new_dylib_file 1714 | local dylib_folder 1715 | local new_dylib_folder 1716 | 1717 | if [ "$arch" = "arm64" ]; then 1718 | frida_server_path="${build}/var/jb/usr/sbin/frida-server" 1719 | new_path="${build}/var/jb/usr/sbin/${FRIDA_NAME}" 1720 | frida_dylib_file="${build}/var/jb/usr/lib/frida/frida-agent.dylib" 1721 | new_dylib_file="${build}/var/jb/usr/lib/frida/${FRIDA_NAME}-agent.dylib" 1722 | dylib_folder="${build}/var/jb/usr/lib/frida" 1723 | new_dylib_folder="${build}/var/jb/usr/lib/${FRIDA_NAME}" 1724 | else 1725 | frida_server_path="${build}/usr/sbin/frida-server" 1726 | new_path="${build}/usr/sbin/${FRIDA_NAME}" 1727 | frida_dylib_file="${build}/usr/lib/frida/frida-agent.dylib" 1728 | new_dylib_file="${build}/usr/lib/frida/${FRIDA_NAME}-agent.dylib" 1729 | dylib_folder="${build}/usr/lib/frida" 1730 | new_dylib_folder="${build}/usr/lib/${FRIDA_NAME}" 1731 | fi 1732 | log_success "正在修改二进制文件: $frida_server_path" 1733 | if [ ! -f "$frida_server_path" ]; then 1734 | log_error "错误: frida-server 文件不存在于路径: $frida_server_path" 1735 | return 1 1736 | fi 1737 | 1738 | (cd $SCRIPT_WORK_DIR/hexreplace && go build -o $SCRIPT_WORK_DIR/build/hexreplace && cd ..) || { 1739 | log_error "编译 hexreplace 工具失败" 1740 | return 1 1741 | } 1742 | chmod +x $SCRIPT_WORK_DIR/build/hexreplace 1743 | ($SCRIPT_WORK_DIR/build/hexreplace "$frida_server_path" "$FRIDA_NAME" "$new_path") || { 1744 | log_error "修改 frida-server 二进制失败" 1745 | return 1 1746 | } 1747 | rm -rf $frida_server_path 1748 | # 确保新文件有执行权限 1749 | sudo chmod +x $new_path 1750 | sudo chown root:wheel $new_path 1751 | 1752 | ($SCRIPT_WORK_DIR/build/hexreplace $frida_dylib_file $FRIDA_NAME $new_dylib_file) || { 1753 | log_error "修改 frida-agent.dylib 失败" 1754 | return 1 1755 | } 1756 | rm -rf $frida_dylib_file 1757 | # 确保新文件有执行权限 1758 | sudo chmod +x $new_dylib_file 1759 | sudo chown root:wheel $new_dylib_file 1760 | 1761 | # 修改dylib目录 1762 | if ! mv "$dylib_folder" "$new_dylib_folder"; then 1763 | log_error "重命名 dylib 目录失败" 1764 | return 1 1765 | fi 1766 | log_success "二进制文件修改完成" 1767 | return 0 1768 | } 1769 | 1770 | # 函数:重新打包 deb 文件 1771 | repackage_deb() { 1772 | local build=$1 1773 | local output_filename=$2 1774 | # 在打包之前删除 .DS_Store 文件 1775 | remove_ds_store "$build" 1776 | # 打包 1777 | dpkg-deb -b "$build" "$output_filename" || { 1778 | log_error "打包 $output_filename 失败" 1779 | exit 1 1780 | } 1781 | 1782 | rm -rf "$build" 1783 | 1784 | log_success "重新打包 $output_filename 完成" 1785 | } 1786 | 1787 | find_frida_path() { 1788 | local pip_commands=("pip3" "pip") 1789 | local frida_path="" 1790 | 1791 | for pip_cmd in "${pip_commands[@]}"; do 1792 | if command -v "$pip_cmd" >/dev/null 2>&1; then 1793 | frida_path=$("$pip_cmd" show frida 2>/dev/null | grep "Location:" | cut -d " " -f 2-) 1794 | if [ -n "$frida_path" ]; then 1795 | frida_path="${frida_path}/frida" 1796 | if [ -d "$frida_path" ]; then 1797 | echo "$frida_path" 1798 | return 0 1799 | fi 1800 | fi 1801 | fi 1802 | done 1803 | 1804 | # 如果通过 pip 无法找到,尝试常见路径 1805 | local frida_paths=( 1806 | "/usr/local/lib/python*/site-packages/frida" 1807 | "/usr/lib/python*/site-packages/frida" 1808 | "$HOME/.local/lib/python*/site-packages/frida" 1809 | "$HOME/Library/Python/*/lib/python/site-packages/frida" 1810 | "$HOME/anaconda*/lib/python*/site-packages/frida" 1811 | "/opt/homebrew/lib/python*/site-packages/frida" 1812 | "/Library/Frameworks/Python.framework/Versions/*/lib/python*/site-packages/frida" 1813 | "/Applications/Frida.app/Contents/Resources/lib/python*/site-packages/frida" 1814 | ) 1815 | 1816 | for path_pattern in "${frida_paths[@]}"; do 1817 | for path in $path_pattern; do 1818 | if [ -d "$path" ]; then 1819 | echo "$path" 1820 | return 0 1821 | fi 1822 | done 1823 | done 1824 | 1825 | log_error "无法找到 frida-tools 路径。请确保 frida-tools 已正确安装。" 1826 | return 1 1827 | } 1828 | generate_random_name() { 1829 | cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-z' | fold -w 5 | head -n 1 1830 | } 1831 | patch_frida_tools() { 1832 | local local_frida_name="$1" 1833 | 1834 | log_info "开始给 frida-tools 打补丁..." 1835 | 1836 | # 如果未提供名称,尝试使用配置的名称或生成随机名称 1837 | if [ -z "$local_frida_name" ]; then 1838 | if [ -n "$FRIDA_NAME" ]; then 1839 | local_frida_name="$FRIDA_NAME" 1840 | log_info "使用配置的魔改名: $local_frida_name" 1841 | else 1842 | local_frida_name=$(generate_random_name) 1843 | log_info "生成随机魔改名: $local_frida_name" 1844 | fi 1845 | fi 1846 | 1847 | # 检查新名称是否有效 1848 | if [[ ! "$local_frida_name" =~ ^[a-zA-Z]{5}$ ]]; then 1849 | log_error "无效的魔改名: $local_frida_name" 1850 | log_info "魔改名必须是恰好 5 个字母(a-z 或 A-Z)" 1851 | return 1 1852 | fi 1853 | 1854 | modify_frida_tools "$local_frida_name" 1855 | } 1856 | 1857 | restore_frida_tools() { 1858 | log_info "开始恢复 frida-tools 到原版..." 1859 | local python_cmd=$(get_python_cmd) 1860 | if [ -z "$python_cmd" ]; then 1861 | log_error "未找到 Python 解释器" 1862 | return 1 1863 | fi 1864 | 1865 | local frida_tools_path=$($python_cmd -c "import os, frida; print(os.path.dirname(frida.__file__))" 2>/dev/null) 1866 | if [ $? -ne 0 ]; then 1867 | log_error "执行 Python 命令失败,请确保 frida 已正确安装" 1868 | return 1 1869 | fi 1870 | # 恢复 Python 库文件 1871 | local pylib_backup=$(ls $frida_tools_path/*.so.fridare 2>/dev/null) 1872 | local pylib=$(ls $frida_tools_path/*.so 2>/dev/null) 1873 | 1874 | if [ -z "$pylib_backup" ]; then 1875 | log_warning "未找到 Python 库文件的备份" 1876 | return 1 1877 | else 1878 | log_info "正在恢复 Python 库文件: $pylib" 1879 | mv "$pylib_backup" "$pylib" 1880 | fi 1881 | 1882 | # 恢复 core.py 文件 1883 | local core_py="$frida_tools_path/core.py" 1884 | if [ -f "$core_py.fridare" ]; then 1885 | log_info "正在恢复 core.py 文件: $core_py" 1886 | mv "$core_py.fridare" "$core_py" 1887 | else 1888 | log_warning "未找到 core.py 文件的备份" 1889 | fi 1890 | 1891 | rm -rf "$frida_tools_path/__pycache__" 1892 | log_success "frida-tools 已恢复到原版" 1893 | } 1894 | # 函数:修订frida-tools 1895 | modify_core_py() { 1896 | frida_name=$1 1897 | path=$2 1898 | p="${path}/core.py" 1899 | b="${p}.fridare" 1900 | if [ ! -f "$b" ]; then 1901 | echo "Creating backup: $b" 1902 | cp "$p" "$b" 1903 | else 1904 | echo "Backup already exists: $b" 1905 | fi 1906 | replaced=0 1907 | while IFS= read -r line; do 1908 | # echo "Processing line: $line" >&2 # Debug output 1909 | 1910 | if [[ $line =~ [\'\"](([^\'\"]+):rpc)[\'\"] ]]; then 1911 | old=${BASH_REMATCH[2]} 1912 | new=$(printf "%-5s" "${frida_name:0:5}") 1913 | new_line=${line//$old:rpc/$new:rpc} 1914 | if [ "$new_line" != "$line" ]; then 1915 | echo "Replaced \"$old:rpc\" with \"$new:rpc\"" >&2 1916 | line=$new_line 1917 | ((replaced++)) 1918 | fi 1919 | fi 1920 | 1921 | echo "$line" 1922 | done < "$p" > "${p}.tmp" 1923 | if [ $replaced -gt 0 ]; then 1924 | mv "${p}.tmp" "$p" 1925 | echo "Replacement complete. Made $replaced replacements." 1926 | else 1927 | echo "No matching pattern found, no changes made" 1928 | rm "${p}.tmp" 1929 | fi 1930 | } 1931 | modify_frida_tools() { 1932 | local local_frida_name="$1" 1933 | 1934 | local python_cmd=$(get_python_cmd) 1935 | if [ -z "$python_cmd" ]; then 1936 | log_error "未找到 Python 解释器" 1937 | return 1 1938 | fi 1939 | 1940 | local pylib_path=$($python_cmd -c "import os, frida; print(os.path.dirname(frida.__file__))" 2>/dev/null) 1941 | if [ $? -ne 0 ]; then 1942 | log_error "执行 Python 命令失败,请确保 frida 已正确安装" 1943 | return 1 1944 | fi 1945 | local pylib=$(ls $pylib_path/*.so 2>/dev/null) 1946 | if [ -z "$pylib" ]; then 1947 | log_error "未找到 frida Python 库" 1948 | return 1 1949 | fi 1950 | 1951 | if [ ! -f "$pylib.fridare" ]; then 1952 | cp "$pylib" "$pylib.fridare" 1953 | log_info "创建备份: $pylib.fridare" 1954 | else 1955 | log_info "备份已存在: $pylib.fridare" 1956 | fi 1957 | 1958 | log_info "Python 库文件: $pylib" 1959 | log_info "Frida 名称: $local_frida_name" 1960 | 1961 | $SCRIPT_WORK_DIR/build/hexreplace "$pylib" "$local_frida_name" "test.so" || { 1962 | log_error "修改 frida Python 库失败" 1963 | return 1 1964 | } 1965 | 1966 | rm -f "$pylib" 1967 | rm -rf "$pylib_path/__pycache__" 1968 | mv test.so "$pylib" 1969 | chmod 755 "$pylib" 1970 | 1971 | modify_core_py "$local_frida_name" "$pylib_path" 1972 | 1973 | log_success "frida-tools 修改完成" 1974 | return 0 1975 | } 1976 | get_absolute_path() { 1977 | local relative_path="$1" 1978 | local absolute_path="" 1979 | 1980 | # 如果是相对路径,添加当前目录 1981 | if [[ "$relative_path" != /* ]]; then 1982 | relative_path="$PWD/$relative_path" 1983 | fi 1984 | 1985 | # 规范化路径 1986 | local oldIFS="$IFS" 1987 | IFS='/' 1988 | local path_parts=($relative_path) 1989 | local new_path=() 1990 | 1991 | for part in "${path_parts[@]}"; do 1992 | case "$part" in 1993 | "" | ".") ;; 1994 | "..") 1995 | if [ ${#new_path[@]} -ne 0 ]; then 1996 | unset 'new_path[${#new_path[@]}-1]' 1997 | fi 1998 | ;; 1999 | *) 2000 | new_path+=("$part") 2001 | ;; 2002 | esac 2003 | done 2004 | 2005 | IFS="$oldIFS" 2006 | absolute_path="/${new_path[*]}" 2007 | absolute_path="${absolute_path// //}" 2008 | 2009 | echo "$absolute_path" 2010 | } 2011 | move_file() { 2012 | local source_file="$1" 2013 | local target_dir="$2" 2014 | mv "$OUTPUT_FIsource_fileLENAME" "$target_dir" 2>&1 | grep -v "are identical" || true 2015 | } 2016 | build_frida() { 2017 | local clean=$1 2018 | local local_deb=$2 2019 | local local_arch=$3 2020 | # 检查并设置 Frida 版本 2021 | local use_local=false 2022 | if [ -n "$local_deb" ]; then 2023 | # 首先检查文件是否存在 2024 | if [ ! -f "$local_deb" ]; then 2025 | log_error "本地文件不存在: $local_deb" 2026 | exit 1 2027 | fi 2028 | # 获取 local_deb 的绝对路径 2029 | if command -v realpath >/dev/null 2>&1; then 2030 | local_deb=$(realpath "$local_deb") 2031 | else 2032 | # 如果 realpath 不可用,使用自定义函数 2033 | local_deb=$(get_absolute_path "$local_deb") 2034 | fi 2035 | if [ ! -f "$local_deb" ]; then 2036 | log_error "本地文件不存在: $local_deb" 2037 | exit 1 2038 | fi 2039 | log_info "使用本地文件: $local_deb" 2040 | use_local=true 2041 | else 2042 | if [ -z "$FRIDA_VERSION" ]; then 2043 | log_error "未指定 Frida 版本" 2044 | show_build_usage 2045 | exit 1 2046 | fi 2047 | fi 2048 | 2049 | log_info "使用 Frida 服务器端口: $FRIDA_SERVER_PORT" 2050 | [ -n "$CURL_PROXY" ] && log_info "HTTP 代理:${CURL_PROXY}" 2051 | [ "$AUTO_CONFIRM" = "true" ] && log_info "自动确认:已启用" 2052 | 2053 | log_warning "期间可能会要求输入 sudo 密码,用于修改文件权限" 2054 | log_color "${COLOR_GREEN}构建目录:${COLOR_RESET} $SCRIPT_WORK_DIR/build" 2055 | log_color "${COLOR_GREEN}输出目录:${COLOR_RESET} $SCRIPT_WORK_DIR/dist" 2056 | 2057 | # 确认执行 2058 | if [ "$AUTO_CONFIRM" != "true" ]; then 2059 | confirm_execution 2060 | fi 2061 | 2062 | log_info "开始构建 Frida..." 2063 | # 检查并安装 dpkg 2064 | 2065 | if ! check_dependencies; then 2066 | log_error "依赖检查失败" 2067 | log_success "请使用 './$0 setup' 命令安装依赖" 2068 | exit 1 2069 | fi 2070 | 2071 | # 如果 FRIDA_NAME 为空,生成一个新的 2072 | if [ -z "$FRIDA_NAME" ]; then 2073 | FRIDA_NAME=$(generate_random_name) 2074 | if [[ ! "$FRIDA_NAME" =~ ^[a-z]{5}$ ]]; then 2075 | log_error "无法生成有效的 Frida 魔改名" 2076 | exit 1 2077 | fi 2078 | fi 2079 | 2080 | local architectures=("arm" "arm64") 2081 | for arch in "${architectures[@]}"; do 2082 | local input_file 2083 | if [ "$use_local" = "true" ]; then 2084 | input_file="$local_deb" 2085 | OUTPUT_FILENAME="${local_deb}_${FRIDA_NAME}_tcp.deb" 2086 | if [ "$local_arch" = "arm64e" ]; then 2087 | arch="arm" 2088 | fi 2089 | log_info "使用本地文件: $input_file" 2090 | else 2091 | input_file="${SCRIPT_WORK_DIR}/build/frida_${FRIDA_VERSION}_iphoneos-${arch}.deb" 2092 | OUTPUT_FILENAME="${SCRIPT_WORK_DIR}/build/frida_${FRIDA_VERSION}_iphoneos-${arch}_${FRIDA_NAME}_tcp.deb" 2093 | download_frida $arch $FRIDA_VERSION $clean 2094 | fi 2095 | 2096 | BUILD_DIR="${SCRIPT_WORK_DIR}/build/frida_build_${arch}" 2097 | rm -rf "$BUILD_DIR" 2098 | 2099 | dpkg-deb -R "${input_file}" "${BUILD_DIR}" 2100 | 2101 | log_cinfo $COLOR_GREEN "正在修改 Frida ${COLOR_PURPLE}${FRIDA_VERSION}${COLOR_RESET} 版本 (${COLOR_SKYBLUE}${arch}${COLOR_RESET})" 2102 | modify_launch_daemon "$BUILD_DIR" "$arch" 2103 | modify_debian_files "$BUILD_DIR" "$arch" 2104 | modify_binary "$BUILD_DIR" "$arch" 2105 | 2106 | repackage_deb "$BUILD_DIR" "$OUTPUT_FILENAME" 2107 | 2108 | mkdir -p $SCRIPT_WORK_DIR/dist 2109 | 2110 | mv "$OUTPUT_FILENAME" $SCRIPT_WORK_DIR/dist/ 2>&1 | grep -v "are identical" || true 2111 | 2112 | log_success "Frida ${FRIDA_VERSION} 版本 (${arch}) 修改完成" 2113 | 2114 | log_info "新版本名:${FRIDA_NAME}" 2115 | log_info "请使用新版本名:${FRIDA_NAME} 进行调试" 2116 | log_info "请使用端口:${FRIDA_SERVER_PORT} 进行调试" 2117 | log_info "新版本 deb 文件:$SCRIPT_WORK_DIR/dist/${OUTPUT_FILENAME}" 2118 | log_info "-------------------------------------------------" 2119 | log_info "iPhone 安装:" 2120 | log_info "scp dist/${OUTPUT_FILENAME} root@:/var/root" 2121 | log_info "ssh root@" 2122 | log_info "dpkg -i /var/root/${OUTPUT_FILENAME}" 2123 | log_info "PC 连接:" 2124 | log_info "frida -U -f com.xxx.xxx -l" 2125 | log_info "frida -H :${FRIDA_SERVER_PORT} -f com.xxx.xxx --no-pause" 2126 | log_info "-------------------------------------------------" 2127 | 2128 | if [ -n "$local_deb" ]; then 2129 | return 0 # 如果是本地文件,只处理一次 2130 | fi 2131 | done 2132 | 2133 | # 确认执行 2134 | if [ "$AUTO_CONFIRM" != "true" ]; then 2135 | # 不同意返回0 2136 | if ! confirm_modify_frida_tools; then 2137 | log_success "frida-tools 未修改。" 2138 | exit 0 2139 | fi 2140 | fi 2141 | modify_frida_tools "$FRIDA_NAME" 2142 | 2143 | } 2144 | initialize_config() { 2145 | SCRIPT_WORK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 2146 | log_color $COLOR_GREEN "工作目录:$SCRIPT_WORK_DIR" 2147 | if [ ! -f "$CONFIG_FILE" ]; then 2148 | echo "# Fridare Configuration File" >"$CONFIG_FILE" 2149 | echo "FRIDA_SERVER_PORT=$DEF_FRIDA_SERVER_PORT" >>"$CONFIG_FILE" 2150 | echo "CURL_PROXY=" >>"$CONFIG_FILE" 2151 | echo "AUTO_CONFIRM=$DEF_AUTO_CONFIRM" >>"$CONFIG_FILE" 2152 | echo "FRIDA_NAME=" >>"$CONFIG_FILE" 2153 | echo "FRIDA_MODULES=(" >>"$CONFIG_FILE" 2154 | echo ")" >>"$CONFIG_FILE" 2155 | fi 2156 | 2157 | # 检查并创建 build 和 dist 目录 2158 | if [ ! -d "${SCRIPT_WORK_DIR}/build" ]; then 2159 | mkdir -p ${SCRIPT_WORK_DIR}/build 2160 | fi 2161 | if [ ! -d "${SCRIPT_WORK_DIR}/dist" ]; then 2162 | mkdir -p ${SCRIPT_WORK_DIR}/dist 2163 | fi 2164 | 2165 | } 2166 | is_conda_env() { 2167 | # 检查 CONDA_PREFIX 环境变量是否存在 2168 | [ -n "$CONDA_PREFIX" ] 2169 | } 2170 | get_python_cmd() { 2171 | if is_conda_env; then 2172 | echo "$CONDA_PREFIX/bin/python" 2173 | else 2174 | for cmd in python3 python; do 2175 | if command -v $cmd >/dev/null 2>&1; then 2176 | echo $cmd 2177 | return 2178 | fi 2179 | done 2180 | fi 2181 | } 2182 | #创建了一个后台进程,其目的是保持 sudo 权限活跃 2183 | sudo_keep_alive() { 2184 | while true; do 2185 | sudo -n true 2186 | sleep 60 2187 | kill -0 "$$" || exit 2188 | done 2>/dev/null & 2189 | SUDO_KEEP_ALIVE_PID=$! 2190 | } 2191 | 2192 | # 在脚本结束时清理 2193 | cleanup() { 2194 | if [ -n "$SUDO_KEEP_ALIVE_PID" ]; then 2195 | kill $SUDO_KEEP_ALIVE_PID 2196 | fi 2197 | } 2198 | get_golang_info() { 2199 | if command -v go >/dev/null 2>&1; then 2200 | local go_version=$(go version 2>&1) 2201 | local go_path=$(go env GOPATH 2>/dev/null) 2202 | echo "$go_version:$go_path" 2203 | else 2204 | echo "Not installed" 2205 | fi 2206 | } 2207 | log_environment_info() { 2208 | log_skyblue "环境信息:" 2209 | 2210 | # Python 环境信息 2211 | if is_conda_env; then 2212 | log_skyblue " Conda 环境: $CONDA_PREFIX" 2213 | else 2214 | log_skyblue " 使用系统 Python 环境" 2215 | fi 2216 | local python_cmd=$(get_python_cmd) 2217 | log_skyblue " Python 路径: $python_cmd" 2218 | log_skyblue " Python 版本: $($python_cmd --version 2>&1)" 2219 | 2220 | # Frida 信息 2221 | local frida_version=$($python_cmd -c 'import frida; print(frida.__version__)' 2>/dev/null) 2222 | if [ -n "$frida_version" ]; then 2223 | log_skyblue " Frida 版本: $frida_version" 2224 | log_skyblue " Frida 路径: $($python_cmd -c 'import os; import frida; print(os.path.dirname(frida.__file__))' 2>/dev/null)" 2225 | else 2226 | log_warning " Frida 未安装或无法检测" 2227 | fi 2228 | 2229 | # Golang 环境信息 2230 | local golang_info=$(get_golang_info) 2231 | if [ "$golang_info" != "Not installed" ]; then 2232 | IFS=':' read -r go_version go_path <<<"$golang_info" 2233 | log_skyblue " Golang 版本: $go_version" 2234 | log_skyblue " GOPATH: $go_path" 2235 | else 2236 | log_warning " Golang 未安装或无法检测" 2237 | fi 2238 | 2239 | # 操作系统信息 2240 | log_skyblue " 操作系统: $(uname -s)" 2241 | log_skyblue " 系统版本: $(uname -r)" 2242 | 2243 | echo # 空行,为了更好的可读性 2244 | } 2245 | 2246 | log_config_info() { 2247 | log_skyblue "配置信息:" 2248 | log_skyblue " FRIDA_SERVER_PORT: $FRIDA_SERVER_PORT" 2249 | log_skyblue " CURL_PROXY: $CURL_PROXY" 2250 | log_skyblue " AUTO_CONFIRM: $AUTO_CONFIRM" 2251 | log_skyblue " FRIDA_NAME: $FRIDA_NAME" 2252 | echo # 空行,为了更好的可读性 2253 | } 2254 | 2255 | version_compare() { 2256 | local v1="$1" 2257 | local v2="$2" 2258 | 2259 | # Remove 'v' if present 2260 | v1="${v1#v}" 2261 | v2="${v2#v}" 2262 | 2263 | # Split the versions into arrays 2264 | IFS='.' read -r -a ver1 <<<"$v1" 2265 | IFS='.' read -r -a ver2 <<<"$v2" 2266 | 2267 | # Compare each part of the version 2268 | for ((i = 0; i < ${#ver1[@]} || i < ${#ver2[@]}; i++)); do 2269 | local num1=$((${ver1[i]:-0})) 2270 | local num2=$((${ver2[i]:-0})) 2271 | if ((num1 > num2)); then 2272 | echo ">" # v1 is greater 2273 | return 2274 | elif ((num1 < num2)); then 2275 | echo "<" # v2 is greater 2276 | return 2277 | fi 2278 | done 2279 | echo "=" # versions are equal 2280 | } 2281 | 2282 | check_version() { 2283 | local is_install=$1 2284 | local current_version="$VERSION" 2285 | local repo_owner="suifei" 2286 | local repo_name="fridare" 2287 | local next="false" 2288 | 2289 | log_info "检查版本更新..." 2290 | local releases_info=$(curl -s "https://api.github.com/repos/$repo_owner/$repo_name/releases") 2291 | 2292 | if [ -z "$releases_info" ]; then 2293 | log_error "无法获取版本信息" 2294 | return 1 2295 | fi 2296 | 2297 | # 获取所有非预发布版本,并按版本号排序 2298 | local versions=$(echo "$releases_info" | jq -r '.[] | select(.prerelease == false) | .tag_name' | sort -rV) 2299 | local latest_version=$(echo "$versions" | head -n1) 2300 | 2301 | if [ -z "$latest_version" ]; then 2302 | log_error "无法获取最新版本信息" 2303 | return 1 2304 | fi 2305 | 2306 | local download_url=$(echo "$releases_info" | jq -r ".[] | select(.tag_name == \"$latest_version\") | .zipball_url") 2307 | 2308 | if [ -z "$download_url" ]; then 2309 | log_error "无法获取下载链接" 2310 | return 1 2311 | fi 2312 | 2313 | current_version="${current_version#v}" 2314 | latest_version="${latest_version#v}" 2315 | 2316 | result=$(version_compare "$current_version" "$latest_version") 2317 | 2318 | if [ "$result" = "=" ]; then 2319 | log_success "当前版本 (${current_version}) 已是最新正式版本" 2320 | elif [ "$result" = ">" ]; then 2321 | log_success "当前版本 (${current_version}) 比最新正式版本 (${latest_version}) 更新" 2322 | elif [ "$result" = "<" ]; then 2323 | log_warning "发现新的正式版本:${latest_version}(当前版本:${current_version})" 2324 | echo "更新说明:" 2325 | echo "$releases_info" | jq -r ".[] | select(.tag_name == \"$latest_version\") | .body" | sed 's/^/ /' 2326 | 2327 | read -p "是否更新到最新正式版本?(y/n) " -n 1 -r 2328 | echo 2329 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 2330 | log_info "取消更新" 2331 | return 0 2332 | fi 2333 | next="true" 2334 | else 2335 | log_error "版本比较出错" 2336 | fi 2337 | if [ "$next" = "true" ] || [ "$is_install" = "true" ]; then 2338 | 2339 | # 下载和更新过程保持不变 2340 | log_info "开始下载最新正式版本..." 2341 | local temp_dir=$(mktemp -d) 2342 | local zip_file="$temp_dir/fridare-$latest_version.zip" 2343 | local extract_dir="$temp_dir/extracted_files" 2344 | 2345 | download_with_progress "$download_url" "$zip_file" "Fridare 版本 ${latest_version}" 2346 | 2347 | log_info "解压文件..." 2348 | if ! unzip -q "$zip_file" -d "$extract_dir"; then 2349 | log_error "解压失败" 2350 | rm -rf "$temp_dir" 2351 | return 1 2352 | fi 2353 | 2354 | log_info "更新本地文件..." 2355 | local script_dir="$(dirname "$0")" 2356 | local install_dir="${script_dir}/fridare" 2357 | 2358 | if [ "$is_install" = "true" ]; then 2359 | # 创建目录 2360 | mkdir -p "$install_dir" 2361 | script_dir="$install_dir" 2362 | log_success "文件夹 \"${script_dir}\" 已创建,请将此文件夹添加到 PATH 环境变量中" 2363 | log_skyblue " export PATH=\$PATH:\"${script_dir}\"" 2364 | # 加入 .bashrc 或者 .zshrc 的提示 2365 | if [ -f "$HOME/.bashrc" ]; then 2366 | log_skyblue " echo \"export PATH=\$PATH:\\\"${script_dir}\\\"\" >> ~/.bashrc" 2367 | fi 2368 | if [ -f "$HOME/.zshrc" ]; then 2369 | log_skyblue " echo \"export PATH=\$PATH:\\\"${script_dir}\\\"\" >> ~/.zshrc" 2370 | fi 2371 | fi 2372 | 2373 | # 找到解压后的目录(应该只有一个) 2374 | local update_dir=$(find "$extract_dir" -maxdepth 1 -type d | grep -v "^$extract_dir$" | head -n 1) 2375 | 2376 | if [ -z "$update_dir" ]; then 2377 | log_error "无法找到更新文件目录" 2378 | rm -rf "$temp_dir" 2379 | return 1 2380 | fi 2381 | 2382 | log_info "正在从 $update_dir 复制文件到 $script_dir" 2383 | 2384 | # 复制新文件到脚本目录 2385 | if ! cp -R "$update_dir/"* "$script_dir/"; then 2386 | log_error "复制新文件失败" 2387 | rm -rf "$temp_dir" 2388 | return 1 2389 | fi 2390 | 2391 | # 删除旧文件 2392 | find "$script_dir" -type f | while read file; do 2393 | if [ ! -e "$update_dir/${file#$script_dir/}" ]; then 2394 | rm "$file" 2395 | fi 2396 | done 2397 | 2398 | # 调整权限 2399 | chmod -R 755 "$script_dir" 2400 | # 删除.git 2401 | rm -rf "$script_dir/.git" 2402 | 2403 | # 清理临时文件 2404 | rm -rf "$temp_dir" 2405 | 2406 | log_success "更新完成,新版本:${latest_version}" 2407 | log_info "请重新运行脚本以使用新版本" 2408 | exit 0 2409 | fi 2410 | } 2411 | 2412 | # 主函数 2413 | main() { 2414 | initialize_config 2415 | log_environment_info 2416 | # 检查是否有 -y 参数 2417 | if [[ "$*" == *"-y"* || "$*" == *"--yes"* ]]; then 2418 | sudo -v || { 2419 | log_error "无法获取 sudo 权限" 2420 | exit 1 2421 | } 2422 | sudo_keep_alive 2423 | trap cleanup EXIT 2424 | fi 2425 | # 检查是否是首次运行 2426 | if [ ! -f "$CONFIG_FILE" ]; then 2427 | echo -e "${COLOR_YELLOW}欢迎使用 Fridare!这似乎是您第一次运行本工具。${COLOR_RESET}" 2428 | echo -e "${COLOR_YELLOW}以下是快速开始指南:${COLOR_RESET}\n" 2429 | quick_start_guide 2430 | echo -e "\n${COLOR_YELLOW}按回车键继续...${COLOR_RESET}" 2431 | read 2432 | fi 2433 | # 读取配置文件(如果存在) 2434 | if [ -f "$CONFIG_FILE" ]; then 2435 | FRIDA_MODULES=() 2436 | source "$CONFIG_FILE" 2437 | fi 2438 | 2439 | # 将配置文件中的值赋给脚本变量 2440 | FRIDA_SERVER_PORT=${FRIDA_SERVER_PORT:-$DEF_FRIDA_SERVER_PORT} 2441 | CURL_PROXY=${CURL_PROXY:-""} 2442 | AUTO_CONFIRM=${AUTO_CONFIRM:-$DEF_AUTO_CONFIRM} 2443 | FRIDA_NAME=${FRIDA_NAME:-""} 2444 | 2445 | log_config_info 2446 | 2447 | # 解析参数 2448 | parse_arguments "$@" 2449 | } 2450 | # 执行主函数 2451 | main "$@" 2452 | -------------------------------------------------------------------------------- /hexreplace/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test build 2 | 3 | help: 4 | @echo "make test - Run the tests" 5 | @echo "make build - Build the project" 6 | 7 | build: 8 | @go build 9 | 10 | test: 11 | @go run main.go ../build/test.so abcde _test.so -------------------------------------------------------------------------------- /hexreplace/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/suifei/fridare/hexreplace 2 | 3 | go 1.22.3 4 | -------------------------------------------------------------------------------- /hexreplace/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/hexreplace/go.sum -------------------------------------------------------------------------------- /hexreplace/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | hexreplace is a tool to patch binary file with hex string. 3 | Usage: hexreplace 4 | Example: hexreplace /Users/xxx/Desktop/frida-ios-dump/FridaGadget.dylib frida 5 | Author: suifei@gmail.com 6 | Github: https://github.com/suifei/fridare/tree/master/hexreplace 7 | Version: 2.2 8 | 9 | changelog: 10 | - 2.2: 11 | - Added support for ELF and PE file formats 12 | - Added functions for describing architectures: describeMachOArch, describeELFArch, describePEArch 13 | - Modified buildReplacements function to support different executable formats 14 | - Unified file detection and opening logic into detectAndOpenFile function 15 | - Refactored handleSignleArchitecture and handleMultipleArchitectures functions to handle different file formats 16 | 17 | - 2.1: 18 | - Refactored the Replacements structure to support multiple sections: 19 | - Added a new 'SectionName' field to the Replacements struct 20 | - Changed 'Replacements' to contain an 'Items' slice of Replacement structs 21 | - Modified the buildReplacements function to return a slice of Replacements, allowing for multiple section definitions 22 | - Updated handleSignleArchitecture and patchArchitecture functions to process multiple sections: 23 | - Now iterates through all defined sections in the Replacements slice 24 | - Applies replacements to each specified section individually 25 | - Adjusted the replaceInSection function to accept a slice of Replacement structs 26 | - Improved error handling and logging: 27 | - Added more detailed error messages for each section processing step 28 | - Included section names in log messages for better traceability 29 | - Enhanced code flexibility and extensibility: 30 | - Made it easier to add new sections for replacement in the future 31 | - Improved code organization by grouping replacement rules by section 32 | 33 | - 2.0: support multiple architectures, add more ARM and ARM64 subtypes, add more replacements, macho.File.Section() returns a pointer to macho.Section, add more error handling 34 | - 1.0: initial version 35 | */ 36 | package main 37 | 38 | import ( 39 | "debug/elf" 40 | "debug/macho" 41 | "debug/pe" 42 | "encoding/binary" 43 | "fmt" 44 | "io" 45 | "os" 46 | "strings" 47 | ) 48 | 49 | type ExecutableFormat int 50 | 51 | const ( 52 | PE ExecutableFormat = iota 53 | MachO 54 | ELF 55 | ) 56 | 57 | type Replacement struct { 58 | Old []byte 59 | New []byte 60 | } 61 | 62 | type Replacements struct { 63 | ExecutableFormat ExecutableFormat 64 | SectionName string 65 | Items []*Replacement 66 | } 67 | 68 | func describeArch(file interface{}, format ExecutableFormat) string { 69 | switch format { 70 | case MachO: 71 | switch f := file.(type) { 72 | case *macho.File: 73 | return describeMachOArch(f) 74 | case *macho.FatFile: 75 | return "MachO Fat Binary (Multiple Architectures)" 76 | } 77 | case ELF: 78 | if f, ok := file.(*elf.File); ok { 79 | return describeELFArch(f) 80 | } 81 | case PE: 82 | if f, ok := file.(*pe.File); ok { 83 | return describePEArch(f) 84 | } 85 | } 86 | return "Unknown Architecture" 87 | } 88 | 89 | func cpuTypeToString(cpu macho.Cpu) string { 90 | switch cpu { 91 | case macho.Cpu386: 92 | return "x86" 93 | case macho.CpuAmd64: 94 | return "x86_64" 95 | case macho.CpuArm: 96 | return "ARM" 97 | case macho.CpuArm64: 98 | return "ARM64" 99 | case macho.CpuPpc: 100 | return "PowerPC" 101 | case macho.CpuPpc64: 102 | return "PowerPC 64" 103 | default: 104 | return fmt.Sprintf("Unknown CPU type: %d", cpu) 105 | } 106 | } 107 | func describeMachOArch(f *macho.File) string { 108 | cpu := cpuTypeToString(f.Cpu) 109 | byteOrder := "Little Endian" 110 | if f.ByteOrder == binary.BigEndian { 111 | byteOrder = "Big Endian" 112 | } 113 | return fmt.Sprintf("MachO: CPU: %s, Byte Order: %s, File Type: %s", cpu, byteOrder, f.Type.String()) 114 | } 115 | 116 | func describeELFArch(f *elf.File) string { 117 | var details []string 118 | details = append(details, fmt.Sprintf("Machine: %s", f.Machine.String())) 119 | details = append(details, fmt.Sprintf("Class: %s", f.Class.String())) 120 | details = append(details, fmt.Sprintf("Data: %s", f.Data.String())) 121 | details = append(details, fmt.Sprintf("OSABI: %s", describeOSABI(f.OSABI))) 122 | details = append(details, fmt.Sprintf("ABI Version: %d", f.ABIVersion)) 123 | details = append(details, fmt.Sprintf("Type: %s", f.Type.String())) 124 | details = append(details, fmt.Sprintf("Entry: 0x%x", f.Entry)) 125 | if len(f.Progs) > 0 { 126 | details = append(details, fmt.Sprintf("Program Headers: %d", len(f.Progs))) 127 | for _, prog := range f.Progs { 128 | details = append(details, fmt.Sprintf(" Type: %s, Flags: %s, VAddr: 0x%x, Memsz: 0x%x", 129 | prog.Type.String(), describeProgramFlags(prog.Flags), prog.Vaddr, prog.Memsz)) 130 | } 131 | } 132 | if len(f.Sections) > 0 { 133 | details = append(details, fmt.Sprintf("Section Headers: %d", len(f.Sections))) 134 | for _, section := range f.Sections { 135 | details = append(details, fmt.Sprintf(" Name: %s, Type: %s, Flags: %s, Addr: 0x%x, Size: 0x%x", 136 | section.Name, section.Type.String(), describeSectionFlags(section.Flags), section.Addr, section.Size)) 137 | } 138 | } 139 | if syms, err := f.DynamicSymbols(); err == nil { 140 | details = append(details, fmt.Sprintf("Dynamic Symbols: %d", len(syms))) 141 | } 142 | if libs, err := f.ImportedLibraries(); err == nil && len(libs) > 0 { 143 | details = append(details, fmt.Sprintf("Imported Libraries: %s", strings.Join(libs, ", "))) 144 | } 145 | return strings.Join(details, "\n") 146 | } 147 | 148 | func describeOSABI(osabi elf.OSABI) string { 149 | switch osabi { 150 | case elf.ELFOSABI_NONE: 151 | return "UNIX System V ABI" 152 | case elf.ELFOSABI_HPUX: 153 | return "HP-UX" 154 | case elf.ELFOSABI_NETBSD: 155 | return "NetBSD" 156 | case elf.ELFOSABI_LINUX: 157 | return "Linux" 158 | case elf.ELFOSABI_SOLARIS: 159 | return "Sun Solaris" 160 | case elf.ELFOSABI_AIX: 161 | return "IBM AIX" 162 | case elf.ELFOSABI_IRIX: 163 | return "SGI Irix" 164 | case elf.ELFOSABI_FREEBSD: 165 | return "FreeBSD" 166 | case elf.ELFOSABI_TRU64: 167 | return "Compaq TRU64 UNIX" 168 | case elf.ELFOSABI_MODESTO: 169 | return "Novell Modesto" 170 | case elf.ELFOSABI_OPENBSD: 171 | return "OpenBSD" 172 | case elf.ELFOSABI_ARM: 173 | return "ARM" 174 | case elf.ELFOSABI_STANDALONE: 175 | return "Standalone (embedded) application" 176 | default: 177 | return fmt.Sprintf("Unknown OSABI (%d)", osabi) 178 | } 179 | } 180 | 181 | func describeProgramFlags(flags elf.ProgFlag) string { 182 | var s []string 183 | if flags&elf.PF_X != 0 { 184 | s = append(s, "X") 185 | } 186 | if flags&elf.PF_W != 0 { 187 | s = append(s, "W") 188 | } 189 | if flags&elf.PF_R != 0 { 190 | s = append(s, "R") 191 | } 192 | return strings.Join(s, "+") 193 | } 194 | 195 | func describeSectionFlags(flags elf.SectionFlag) string { 196 | var s []string 197 | if flags&elf.SHF_WRITE != 0 { 198 | s = append(s, "W") 199 | } 200 | if flags&elf.SHF_ALLOC != 0 { 201 | s = append(s, "A") 202 | } 203 | if flags&elf.SHF_EXECINSTR != 0 { 204 | s = append(s, "X") 205 | } 206 | return strings.Join(s, "+") 207 | } 208 | func describePEArch(f *pe.File) string { 209 | var details []string 210 | details = append(details, fmt.Sprintf("Machine: %d", f.Machine)) 211 | characteristics := describeCharacteristics(f.Characteristics) 212 | if len(characteristics) > 0 { 213 | details = append(details, fmt.Sprintf("Characteristics: %s", strings.Join(characteristics, "\n"))) 214 | } 215 | if f.OptionalHeader != nil { 216 | switch oh := f.OptionalHeader.(type) { 217 | case *pe.OptionalHeader32: 218 | details = append(details, "Format: PE32") 219 | details = append(details, fmt.Sprintf("Subsystem: %s", describeSubsystem(oh.Subsystem))) 220 | details = append(details, fmt.Sprintf("BaseOfCode: 0x%X", oh.BaseOfCode)) 221 | details = append(details, fmt.Sprintf("BaseOfData: 0x%X", oh.BaseOfData)) 222 | case *pe.OptionalHeader64: 223 | details = append(details, "Format: PE32+") 224 | details = append(details, fmt.Sprintf("Subsystem: %s", describeSubsystem(oh.Subsystem))) 225 | details = append(details, fmt.Sprintf("BaseOfCode: 0x%X", oh.BaseOfCode)) 226 | } 227 | } 228 | details = append(details, fmt.Sprintf("Number of Sections: %d", len(f.Sections))) 229 | 230 | for i, s := range f.Sections { 231 | details = append(details, fmt.Sprintf("\tSection %d: %s", i, describePESection(s))) 232 | } 233 | details = append(details, fmt.Sprintf("Number of Symbols: %d", len(f.Symbols))) 234 | 235 | return strings.Join(details, "\n") 236 | } 237 | 238 | func describePESection(s *pe.Section) string { 239 | return fmt.Sprintf("Name: %s, Address: 0x%X, Size: 0x%X", s.Name, s.VirtualAddress, s.Size) 240 | } 241 | 242 | func describeCharacteristics(characteristics uint16) []string { 243 | var chars []string 244 | if characteristics&pe.IMAGE_FILE_EXECUTABLE_IMAGE != 0 { 245 | chars = append(chars, "Executable") 246 | } 247 | if characteristics&pe.IMAGE_FILE_LARGE_ADDRESS_AWARE != 0 { 248 | chars = append(chars, "Large Address Aware") 249 | } 250 | if characteristics&pe.IMAGE_FILE_DLL != 0 { 251 | chars = append(chars, "DLL") 252 | } 253 | if characteristics&pe.IMAGE_FILE_32BIT_MACHINE != 0 { 254 | chars = append(chars, "32-bit") 255 | } 256 | if characteristics&pe.IMAGE_FILE_SYSTEM != 0 { 257 | chars = append(chars, "System") 258 | } 259 | if characteristics&pe.IMAGE_FILE_DEBUG_STRIPPED != 0 { 260 | chars = append(chars, "Debug Stripped") 261 | } 262 | return chars 263 | } 264 | 265 | func describeSubsystem(subsystem uint16) string { 266 | switch subsystem { 267 | case pe.IMAGE_SUBSYSTEM_WINDOWS_GUI: 268 | return "Windows GUI" 269 | case pe.IMAGE_SUBSYSTEM_WINDOWS_CUI: 270 | return "Windows Console" 271 | case pe.IMAGE_SUBSYSTEM_EFI_APPLICATION: 272 | return "EFI Application" 273 | case pe.IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: 274 | return "EFI Boot Service Driver" 275 | case pe.IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: 276 | return "EFI Runtime Driver" 277 | case pe.IMAGE_SUBSYSTEM_NATIVE: 278 | return "Native" 279 | case pe.IMAGE_SUBSYSTEM_POSIX_CUI: 280 | return "POSIX Console" 281 | default: 282 | return fmt.Sprintf("Unknown (%d)", subsystem) 283 | } 284 | } 285 | func main() { 286 | if len(os.Args) != 4 { 287 | fmt.Println("Usage: program ") 288 | os.Exit(1) 289 | } 290 | 291 | inputFilePath := os.Args[1] 292 | fridaNewName := os.Args[2] 293 | outputFilePath := os.Args[3] 294 | 295 | if len(fridaNewName) != 5 || !isStringAlpha(fridaNewName) { 296 | fmt.Println("Error: frida new name must be a 5-character alphabetic string") 297 | os.Exit(1) 298 | } 299 | 300 | // 首先复制输入文件到输出文件 301 | if err := copyFile(inputFilePath, outputFilePath); err != nil { 302 | fmt.Println("Error copying file:", err) 303 | os.Exit(1) 304 | } 305 | 306 | file, format, err := detectAndOpenFile(outputFilePath) 307 | if err != nil { 308 | fmt.Println("Error opening file:", err) 309 | os.Exit(1) 310 | } 311 | 312 | fmt.Println("Detected file format:", format) 313 | fmt.Println(describeArch(file, format)) 314 | 315 | switch f := file.(type) { 316 | case *macho.File: 317 | handleSignleArchitecture(f, outputFilePath, fridaNewName, format) 318 | case *macho.FatFile: 319 | handleMultipleArchitectures(f, outputFilePath, fridaNewName, format) 320 | case *elf.File: 321 | handleELFFile(f, outputFilePath, fridaNewName, format) 322 | case *pe.File: 323 | handlePEFile(f, outputFilePath, fridaNewName, format) 324 | default: 325 | fmt.Println("Unsupported file type") 326 | os.Exit(1) 327 | } 328 | 329 | fmt.Println("Patch success") 330 | } 331 | 332 | func detectAndOpenFile(filePath string) (interface{}, ExecutableFormat, error) { 333 | if machoFile, err := macho.Open(filePath); err == nil { 334 | return machoFile, MachO, nil 335 | } 336 | if fatFile, err := macho.OpenFat(filePath); err == nil { 337 | return fatFile, MachO, nil 338 | } 339 | if elfFile, err := elf.Open(filePath); err == nil { 340 | return elfFile, ELF, nil 341 | } 342 | if peFile, err := pe.Open(filePath); err == nil { 343 | return peFile, PE, nil 344 | } 345 | return nil, 0, fmt.Errorf("unsupported file format") 346 | } 347 | func copyFile(src, dst string) error { 348 | sourceFile, err := os.Open(src) 349 | if err != nil { 350 | return err 351 | } 352 | defer sourceFile.Close() 353 | 354 | destFile, err := os.Create(dst) 355 | if err != nil { 356 | return err 357 | } 358 | defer destFile.Close() 359 | 360 | _, err = io.Copy(destFile, sourceFile) 361 | 362 | os.Chmod(dst, 0755) 363 | return err 364 | } 365 | 366 | func handlePEFile(file *pe.File, outputFilePath, fridaNewName string, format ExecutableFormat) { 367 | replacementsList := buildReplacements(fridaNewName, format) 368 | for _, replacements := range replacementsList { 369 | section := file.Section(replacements.SectionName) 370 | if section == nil { 371 | fmt.Printf("Warning: %s section not found in file\n", replacements.SectionName) 372 | continue 373 | } 374 | data, err := section.Data() 375 | if err != nil { 376 | fmt.Printf("Error reading section data for %s: %v\n", replacements.SectionName, err) 377 | continue 378 | } 379 | modifiedData := replaceInSection(data, replacements.Items) 380 | if err := writeModifiedSection(outputFilePath, int64(section.Offset), modifiedData); err != nil { 381 | fmt.Printf("Error writing modified data for %s: %v\n", replacements.SectionName, err) 382 | continue 383 | } 384 | fmt.Printf("Successfully patched %s section\n", replacements.SectionName) 385 | } 386 | } 387 | 388 | func handleELFFile(file *elf.File, outputFilePath, fridaNewName string, format ExecutableFormat) { 389 | replacementsList := buildReplacements(fridaNewName, format) 390 | for _, replacements := range replacementsList { 391 | section := file.Section(replacements.SectionName) 392 | if section == nil { 393 | fmt.Printf("Warning: %s section not found in file\n", replacements.SectionName) 394 | continue 395 | } 396 | data, err := section.Data() 397 | if err != nil { 398 | fmt.Printf("Error reading section data for %s: %v\n", replacements.SectionName, err) 399 | continue 400 | } 401 | modifiedData := replaceInSection(data, replacements.Items) 402 | if err := writeModifiedSection(outputFilePath, int64(section.Offset), modifiedData); err != nil { 403 | fmt.Printf("Error writing modified data for %s: %v\n", replacements.SectionName, err) 404 | continue 405 | } 406 | fmt.Printf("Successfully patched %s section\n", replacements.SectionName) 407 | } 408 | } 409 | 410 | func handleSignleArchitecture(file *macho.File, outputFilePath, fridaNewName string, format ExecutableFormat) { 411 | replacementsList := buildReplacements(fridaNewName, format) 412 | for _, replacements := range replacementsList { 413 | section := file.Section(replacements.SectionName) 414 | if section == nil { 415 | fmt.Printf("Warning: %s section not found in file\n", replacements.SectionName) 416 | continue 417 | } 418 | data, err := section.Data() 419 | if err != nil { 420 | fmt.Printf("Error reading section data for %s: %v\n", replacements.SectionName, err) 421 | continue 422 | } 423 | modifiedData := replaceInSection(data, replacements.Items) 424 | if err := writeModifiedSection(outputFilePath, int64(section.Offset), modifiedData); err != nil { 425 | fmt.Printf("Error writing modified data for %s: %v\n", replacements.SectionName, err) 426 | continue 427 | } 428 | fmt.Printf("Successfully patched %s section\n", replacements.SectionName) 429 | } 430 | } 431 | 432 | func handleMultipleArchitectures(fatFile *macho.FatFile, filePath, fridaNewName string, format ExecutableFormat) { 433 | for _, arch := range fatFile.Arches { 434 | patchArchitecture(arch, filePath, fridaNewName, format) 435 | } 436 | } 437 | 438 | func patchArchitecture(arch macho.FatArch, filePath, fridaNewName string, format ExecutableFormat) { 439 | replacementsList := buildReplacements(fridaNewName, format) 440 | for _, replacements := range replacementsList { 441 | section := arch.Section(replacements.SectionName) 442 | if section == nil { 443 | fmt.Printf("Warning: %s section not found in architecture %s\n", replacements.SectionName, arch.Cpu.String()) 444 | continue 445 | } 446 | data, err := section.Data() 447 | if err != nil { 448 | fmt.Printf("Error reading section data for %s in architecture %s: %v\n", replacements.SectionName, arch.Cpu.String(), err) 449 | continue 450 | } 451 | modifiedData := replaceInSection(data, replacements.Items) 452 | if err := writeModifiedSection(filePath, int64(arch.Offset+section.Offset), modifiedData); err != nil { 453 | fmt.Printf("Error writing modified data for %s in architecture %s: %v\n", replacements.SectionName, arch.Cpu.String(), err) 454 | continue 455 | } 456 | fmt.Printf("Successfully patched %s section\n", replacements.SectionName) 457 | } 458 | } 459 | 460 | func isStringAlpha(s string) bool { 461 | for _, c := range s { 462 | if c < 'a' || c > 'z' { 463 | return false 464 | } 465 | } 466 | return true 467 | } 468 | 469 | func buildReplacements(fridaNewName string, format ExecutableFormat) []Replacements { 470 | switch format { 471 | case MachO: 472 | return []Replacements{ 473 | { 474 | ExecutableFormat: format, 475 | SectionName: "__cstring", 476 | Items: []*Replacement{ 477 | {Old: []byte("frida_server_"), New: []byte(fridaNewName + "_server_")}, 478 | {Old: []byte("frida-server-main-loop"), New: []byte(fridaNewName + "-server-main-loop")}, 479 | {Old: []byte("frida-main-loop"), New: []byte(fridaNewName + "-main-loop")}, 480 | {Old: []byte("frida:rpc"), New: []byte(fridaNewName + ":rpc")}, 481 | {Old: []byte("frida-agent.dylib"), New: []byte(fridaNewName + "-agent.dylib")}, 482 | {Old: []byte("/usr/lib/frida/"), New: []byte("/usr/lib/" + fridaNewName + "/")}, 483 | {Old: []byte("gum-"), New: []byte(fridaNewName[:3] + "-")}, 484 | }, 485 | }, 486 | { 487 | ExecutableFormat: format, 488 | SectionName: "__const", 489 | Items: []*Replacement{ 490 | {Old: []byte("frida:rpc"), New: []byte(fridaNewName + ":rpc")}, 491 | }, 492 | }, 493 | } 494 | case ELF: 495 | return []Replacements{ 496 | { 497 | ExecutableFormat: format, 498 | SectionName: ".rodata", 499 | Items: []*Replacement{ 500 | {Old: []byte("frida_server_"), New: []byte(fridaNewName + "_server_")}, 501 | {Old: []byte("frida-main-loop"), New: []byte(fridaNewName + "-main-loop")}, 502 | {Old: []byte("frida:rpc"), New: []byte(fridaNewName + ":rpc")}, 503 | {Old: []byte("frida-agent-.so"), New: []byte(fridaNewName + "-agent-.so")}, 504 | {Old: []byte("frida-agent-arm.so"), New: []byte(fridaNewName + "-agent-arm.so")}, 505 | {Old: []byte("frida-agent-arm64.so"), New: []byte(fridaNewName + "-agent-arm64.so")}, 506 | {Old: []byte("frida-agent-32.so"), New: []byte(fridaNewName + "-agent-32.so")}, 507 | {Old: []byte("frida-agent-64.so"), New: []byte(fridaNewName + "-agent-64.so")}, 508 | {Old: []byte("gum-"), New: []byte(fridaNewName[:3] + "-")}, 509 | }, 510 | }, 511 | { 512 | ExecutableFormat: format, 513 | SectionName: ".text", 514 | Items: []*Replacement{ 515 | {Old: []byte("frida:rpc"), New: []byte(fridaNewName + ":rpc")}, 516 | {Old: []byte("gum-"), New: []byte(fridaNewName[:3] + "-")}, 517 | }, 518 | }, 519 | } 520 | case PE: 521 | return []Replacements{ 522 | { 523 | ExecutableFormat: format, 524 | SectionName: ".rdata", 525 | Items: []*Replacement{ 526 | {Old: []byte("frida-"), New: []byte(fridaNewName + "-")}, 527 | {Old: []byte("frida_"), New: []byte(fridaNewName + "_")}, 528 | {Old: []byte("frida_server_"), New: []byte(fridaNewName + "_server_")}, 529 | {Old: []byte("frida-main-loop"), New: []byte(fridaNewName + "-main-loop")}, 530 | {Old: []byte("gum-"), New: []byte(fridaNewName[:3] + "-")}, 531 | {Old: []byte("frida-thread"), New: []byte(fridaNewName + "-thread")}, 532 | {Old: []byte("frida:rpc"), New: []byte(fridaNewName + ":rpc")}, 533 | {Old: []byte("frida-agent"), New: []byte(fridaNewName + "-agent")}, 534 | }, 535 | }, 536 | } 537 | } 538 | return nil 539 | } 540 | 541 | func replaceInSection(data []byte, replacements []*Replacement) []byte { 542 | modifiedData := make([]byte, len(data)) 543 | copy(modifiedData, data) 544 | 545 | counter := 0 546 | for _, replacement := range replacements { 547 | oldBytes := replacement.Old 548 | newBytes := replacement.New 549 | 550 | for i := 0; i <= len(modifiedData)-len(oldBytes); i++ { 551 | if bytesEqual(modifiedData[i:i+len(oldBytes)], oldBytes) { 552 | replacement := make([]byte, len(oldBytes)) 553 | copy(replacement, newBytes) 554 | for j := len(newBytes); j < len(oldBytes); j++ { 555 | replacement[j] = 0 556 | } 557 | copy(modifiedData[i:i+len(oldBytes)], replacement) 558 | counter++ 559 | } 560 | } 561 | } 562 | 563 | fmt.Printf("Replaced %d occurrences\n", counter) 564 | 565 | return modifiedData 566 | } 567 | 568 | func bytesEqual(a, b []byte) bool { 569 | if len(a) != len(b) { 570 | return false 571 | } 572 | for i := range a { 573 | if a[i] != b[i] { 574 | return false 575 | } 576 | } 577 | return true 578 | } 579 | 580 | func writeModifiedSection(filePath string, offset int64, data []byte) error { 581 | f, err := os.OpenFile(filePath, os.O_RDWR, 0) 582 | if err != nil { 583 | return err 584 | } 585 | defer f.Close() 586 | 587 | _, err = f.WriteAt(data, offset) 588 | return err 589 | } 590 | -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/555354813.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/screenshots/555354813.jpg -------------------------------------------------------------------------------- /screenshots/md5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/screenshots/md5.png -------------------------------------------------------------------------------- /toolkit/generate_frida_modules.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import requests 4 | 5 | def get_proxy_settings(): 6 | curl_proxy = os.environ.get('CURL_PROXY', '') 7 | if curl_proxy: 8 | return {"http": curl_proxy, "https": curl_proxy} 9 | return None 10 | 11 | def get_latest_release(): 12 | url = "https://api.github.com/repos/frida/frida/releases/latest" 13 | proxies = get_proxy_settings() 14 | try: 15 | response = requests.get(url, proxies=proxies) 16 | response.raise_for_status() 17 | return response.json() 18 | except requests.RequestException as e: 19 | print(f"Error fetching latest release: {str(e)}") 20 | return None 21 | 22 | def parse_filename(filename): 23 | pattern = re.compile(r'(?Pfrida[-_]?[a-zA-Z0-9\-]+)?[-_](?Pv?\d+\.\d+\.\d+)[-_](?P[a-zA-Z0-9\-]+)[-_](?P[a-zA-Z0-9_]+)') 24 | match = pattern.search(filename) 25 | if match: 26 | module_type = match.group('module_type') or 'N/A' 27 | version = match.group('version') 28 | os = match.group('os') 29 | arch = match.group('arch') 30 | if '.' in filename: 31 | ext = filename.split('.')[-1] 32 | else: 33 | ext = 'N/A' 34 | if '64' == arch: 35 | arch = 'x86_64' 36 | elif '_' in arch: 37 | arch = arch.split('_')[-1] 38 | if os.startswith('cp') and '-' in os: 39 | os_info = os.split('-') 40 | os = os_info[-1] 41 | module_type = 'frida-python-' + os_info[0] + '-' + os_info[1] 42 | elif 'node-' in os: 43 | os_info = os.split('-') 44 | os = os_info[-1] 45 | module_type = 'frida-' + os_info[0] + '-' + os_info[1] 46 | elif 'electron-' in os: 47 | os_info = os.split('-') 48 | os = os_info[-1] 49 | module_type = 'frida-' + os_info[0] + '-' + os_info[1] 50 | elif '-' in os: 51 | os = os.split('-')[0] 52 | 53 | if 'N/A' == module_type and 'deb' in filename: 54 | module_type = 'frida-' + os + '-deb' 55 | elif 'N/A' == module_type and 'gum-graft' in filename: 56 | module_type = 'gum-graft' 57 | os = filename.split('-')[-2] 58 | arch = filename.split('-')[-1].split('.')[0] 59 | return (module_type, version, os, arch, ext) 60 | return None 61 | 62 | def generate_frida_modules(): 63 | release = get_latest_release() 64 | if not release: 65 | return [] 66 | 67 | assets = release['assets'] 68 | frida_modules = [] 69 | 70 | for asset in assets: 71 | parsed = parse_filename(asset['name']) 72 | if parsed: 73 | module_type, version, os, arch, ext = parsed 74 | if 'v' == version[0]: 75 | version = version[1:] 76 | asset_name = asset['name'].replace(version, '{VERSION}') 77 | frida_modules.append(f'"{module_type}:{os}:{arch}:{asset_name}"') 78 | 79 | return frida_modules 80 | 81 | def main(): 82 | frida_modules = generate_frida_modules() 83 | print("FRIDA_MODULES=(") 84 | for module in frida_modules: 85 | print(f" {module}") 86 | print(")") 87 | 88 | if __name__ == "__main__": 89 | main() -------------------------------------------------------------------------------- /toolkit/manifest.txt: -------------------------------------------------------------------------------- 1 | hexreplace/main.go 2 | hexreplace/Makefile 3 | hexreplace/go.mod 4 | autoinstall.sh 5 | CHANGELOG 6 | fridare.sh 7 | README.md -------------------------------------------------------------------------------- /toolkit/merge.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | 4 | def get_language(file_extension): 5 | language_map = { 6 | '.py': 'python', 7 | '.js': 'javascript', 8 | '.html': 'html', 9 | '.css': 'css', 10 | '.java': 'java', 11 | '.c': 'c', 12 | '.cpp': 'cpp', 13 | '.go': 'golang', 14 | '.rs': 'rust', 15 | '.sh': 'shell', 16 | '.md': 'markdown', 17 | '.json': 'json', 18 | '.yaml': 'yaml', 19 | '.xml': 'xml', 20 | '.sql': 'sql', 21 | '.ts': 'typescript', 22 | } 23 | return language_map.get(file_extension.lower(), '') 24 | 25 | def escape_backticks(content): 26 | return content.replace("```", "\\`\\`\\`") 27 | 28 | def merge_files(manifest_file, base_directory, output_file): 29 | with open(output_file, 'w', encoding='utf-8') as outfile: 30 | with open(manifest_file, 'r', encoding='utf-8') as manifest: 31 | for line in manifest: 32 | file_path = line.strip() 33 | if not file_path or file_path.startswith('#'): 34 | continue # 跳过空行和注释 35 | 36 | full_path = os.path.join(base_directory, file_path) 37 | if not os.path.exists(full_path): 38 | print(f"Warning: File not found - {full_path}") 39 | continue 40 | 41 | _, file_extension = os.path.splitext(file_path) 42 | 43 | # 写入文件名作为Markdown标题 44 | outfile.write(f"# {file_path}\n\n") 45 | 46 | # 获取语言类型 47 | language = get_language(file_extension) 48 | 49 | # 读取并转义文件内容 50 | try: 51 | with open(full_path, 'r', encoding='utf-8') as infile: 52 | content = infile.read() 53 | escaped_content = escape_backticks(content) 54 | 55 | # 写入文件内容,包括语言类型 56 | outfile.write(f"```{language}\n{escaped_content}\n```\n\n") 57 | except Exception as e: 58 | print(f"Error reading file {full_path}: {e}") 59 | 60 | def main(): 61 | parser = argparse.ArgumentParser(description="Merge specified files into a single Markdown file.") 62 | parser.add_argument("manifest", help="Path to the manifest file listing files to merge") 63 | parser.add_argument("base_directory", help="Base directory for the files listed in the manifest") 64 | parser.add_argument("output", help="Output file name") 65 | 66 | args = parser.parse_args() 67 | 68 | merge_files(args.manifest, args.base_directory, args.output) 69 | print(f"Files merged successfully into {args.output}") 70 | 71 | if __name__ == "__main__": 72 | main() -------------------------------------------------------------------------------- /win/README.md: -------------------------------------------------------------------------------- 1 | # Fridare Windows 使用指南 2 | 3 | ## 最新更新 4 | 5 | ### v3.1.5 - Windows 支持 6 | 7 | - 新增 `patch-frida.cmd` 脚本,用于在 Windows 环境下修改 frida-server 8 | - 新增 `patch-frida-tools.cmd` 脚本,用于在 Windows 环境下修改 frida-tools 9 | - 增加对 Windows 平台的全面支持 10 | - 更新了使用说明,增加了 Windows 平台的详细教程 11 | 12 | ## Windows 下的使用教程 13 | 14 | ### 准备工作 15 | 16 | 1. 确保你的系统已经安装了 Python 和 pip 17 | 2. 下载 Fridare 项目到本地 18 | 19 | ### 修改 frida-server 20 | 21 | 1. 打开命令提示符,进入 Fridare 项目目录 22 | 2. 运行以下命令: 23 | 24 | ``` 25 | patch-frida.cmd <5字符魔改名> 26 | ``` 27 | 28 | 例如: 29 | 30 | ``` 31 | patch-frida.cmd frida-server-16.4.7-android-arm64 abcde 32 | ``` 33 | 34 | 3. 脚本将会生成一个修改后的 frida-server 文件,文件名为 `frida-server-16.4.7-android-arm64_abcde` 35 | 36 | ### 修改 frida-tools 37 | 38 | 1. 在命令提示符中运行: 39 | 40 | ``` 41 | patch-frida-tools.cmd 42 | ``` 43 | 44 | 2. 脚本会自动定位 frida 的安装路径 45 | 3. 根据提示输入 5 个字符的魔改名(必须是小写字母 a-z) 46 | 4. 脚本会自动修改 `core.py` 和 `_frida.pyd` 文件 47 | 48 | ### 注意事项 49 | 50 | - 在修改 frida-tools 之前,脚本会自动备份原文件 51 | - 确保你有足够的权限修改 Python 安装目录下的文件 52 | - 修改后,建议重新启动你的 Python 环境以确保更改生效 53 | 54 | ## 故障排除 55 | 56 | 如果遇到 "Error: hexreplace tool not found" 错误,请确保 `hexreplace_windows_amd64.exe` 文件位于与脚本相同的目录中。 57 | 58 | 如果修改过程中遇到权限问题,尝试以管理员身份运行命令提示符。 59 | 60 | ## 恢复原始文件 61 | 62 | 如果需要恢复原始的 frida-tools 文件: 63 | 64 | 1. 找到 frida 的安装目录 (通常在运行 `patch-frida-tools.cmd` 时会显示) 65 | 2. 将 `core.py.fridare` 重命名为 `core.py` 66 | 3. 将 `_frida.pyd.fridare` 重命名为 `_frida.pyd` 67 | 68 | ## 贡献 69 | 70 | 欢迎提交问题和拉取请求。对于重大更改,请先开 issue 讨论您想要更改的内容。 71 | 72 | ## 许可证 73 | 74 | [MIT LICENSE](LICENSE) 75 | -------------------------------------------------------------------------------- /win/hexreplace_windows_amd64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suifei/fridare/951f5c7e1e9c7ead737e20d3fc10f822280aeec0/win/hexreplace_windows_amd64.exe -------------------------------------------------------------------------------- /win/patch-frida-tools.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | :: 获取脚本所在路径 5 | set "SCRIPT_PATH=%~dp0" 6 | :: 设置 hexreplace 工具路径 7 | set "HEXREPLACE_PATH=%SCRIPT_PATH%hexreplace_windows_amd64.exe" 8 | 9 | :: 检查 hexreplace 工具是否存在 10 | if not exist "%HEXREPLACE_PATH%" ( 11 | echo Error: hexreplace tool not found at %HEXREPLACE_PATH% 12 | goto :eof 13 | ) 14 | 15 | :: 使用 pip 获取 Frida 安装路径 16 | for /f "tokens=2 delims= " %%a in ('pip show frida ^| findstr "Location"') do set FRIDA_PATH=%%a\frida 17 | 18 | echo Frida installation path: %FRIDA_PATH% 19 | 20 | :: 检查文件是否存在 21 | if not exist "%FRIDA_PATH%\core.py" ( 22 | echo Error: core.py not found in %FRIDA_PATH% 23 | goto :eof 24 | ) 25 | if not exist "%FRIDA_PATH%\_frida.pyd" ( 26 | echo Error: _frida.pyd not found in %FRIDA_PATH% 27 | goto :eof 28 | ) 29 | 30 | :: 备份文件 31 | if not exist "%FRIDA_PATH%\core.py.fridare" ( 32 | copy "%FRIDA_PATH%\core.py" "%FRIDA_PATH%\core.py.fridare" 33 | echo Backed up core.py 34 | ) 35 | if not exist "%FRIDA_PATH%\_frida.pyd.fridare" ( 36 | copy "%FRIDA_PATH%\_frida.pyd" "%FRIDA_PATH%\_frida.pyd.fridare" 37 | echo Backed up _frida.pyd 38 | ) 39 | 40 | :: 获取用户输入 41 | set /p "input=Please enter 5 characters (a-z): " 42 | if not "%input:~4,1%" == "" ( 43 | if "%input:~5,1%" == "" ( 44 | echo Input accepted. 45 | ) else ( 46 | echo Input must be exactly 5 characters. 47 | goto :eof 48 | ) 49 | ) else ( 50 | echo Input must be exactly 5 characters. 51 | goto :eof 52 | ) 53 | 54 | :: 使用 hexreplace 修改文件 55 | "%HEXREPLACE_PATH%" "%FRIDA_PATH%\_frida.pyd" %input% "%FRIDA_PATH%\_frida.pyd.modify" 56 | 57 | if %errorlevel% neq 0 ( 58 | echo Error occurred during file modification. 59 | goto :eof 60 | ) 61 | 62 | :: 替换原文件 63 | move /y "%FRIDA_PATH%\_frida.pyd.modify" "%FRIDA_PATH%\_frida.pyd" 64 | 65 | echo Modification complete. -------------------------------------------------------------------------------- /win/patch-frida.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | :: 检查参数数量 5 | if "%~2"=="" ( 6 | echo Usage: %~nx0 ^ ^<5_char_magic_name^> 7 | echo Example: %~nx0 "C:\path\to\frida-server.exe" abcde 8 | goto :eof 9 | ) 10 | 11 | :: 获取输入参数 12 | set "FRIDA_SERVER_PATH=%~1" 13 | set "MAGIC_NAME=%~2" 14 | 15 | :: 验证输入文件路径 16 | if not exist "%FRIDA_SERVER_PATH%" ( 17 | echo Error: frida-server file not found at %FRIDA_SERVER_PATH% 18 | goto :eof 19 | ) 20 | 21 | :: 验证魔改名长度 22 | if not "%MAGIC_NAME:~4,1%" == "" ( 23 | if "%MAGIC_NAME:~5,1%" == "" ( 24 | echo Magic name accepted. 25 | ) else ( 26 | echo Error: Magic name must be exactly 5 characters. 27 | goto :eof 28 | ) 29 | ) else ( 30 | echo Error: Magic name must be exactly 5 characters. 31 | goto :eof 32 | ) 33 | 34 | :: 获取脚本所在路径 35 | set "SCRIPT_PATH=%~dp0" 36 | :: 设置 hexreplace 工具路径 37 | set "HEXREPLACE_PATH=%SCRIPT_PATH%hexreplace_windows_amd64.exe" 38 | 39 | :: 检查 hexreplace 工具是否存在 40 | if not exist "%HEXREPLACE_PATH%" ( 41 | echo Error: hexreplace tool not found at %HEXREPLACE_PATH% 42 | goto :eof 43 | ) 44 | 45 | :: 构建输出文件名 46 | for %%F in ("%FRIDA_SERVER_PATH%") do ( 47 | set "FILE_NAME=%%~nF" 48 | set "FILE_EXT=%%~xF" 49 | ) 50 | set "OUTPUT_PATH=%~dp1%FILE_NAME%%FILE_EXT%_%MAGIC_NAME%" 51 | 52 | :: 使用 hexreplace 修改文件 53 | "%HEXREPLACE_PATH%" "%FRIDA_SERVER_PATH%" %MAGIC_NAME% "%OUTPUT_PATH%" 54 | 55 | if %errorlevel% neq 0 ( 56 | echo Error occurred during file modification. 57 | goto :eof 58 | ) 59 | 60 | echo Modification complete. 61 | echo Modified file saved as: %OUTPUT_PATH% --------------------------------------------------------------------------------