应用安全 --- 安卓逆向 之 YAHFA框架
https://github.com/PAGalaxyLab/YAHFA
YAHFA框架是一个实现ART运行时替换一个函数的功能,也可以称为函数级别的hook框架
我们定义好要替换的函数,目标原始函数,就可以发送给框架自动替换
它和著名的frida有什么区别,frida虽然强大,但是只能用电脑和手机配合使用,无法脱离电脑,而且只支持root手机
这个框架可以无root内嵌入apk中实现hook效果。他们的使用场景不同,frida侧重于内部分析,yahfa侧重于内部修改比如去签名
这个项目最大的缺点就是长时间没有人维护,不支持高版本的安卓,而且互联网资料几乎没有,只是流传于民间行业内部。这也是全网首发最详细的教程
这是我更新到安卓16的项目
https://gitee.com/null_465_7266/yahfademo
YAHFA 使用方法
基于项目中的示例代码,以下是完整的使用指南:
一、基本使用步骤
1. 添加依赖
项目已配置好本地库依赖,无需额外配置。
2. 创建目标类(待 hook 的类)
3. 创建 Hook 类
4. 执行 Hook
二、方法签名规则
| 目标方法类型 | Hook 方法签名要求 |
|---|---|
| 实例方法 | public static 返回类型 hook_方法名(目标类类型 this, 参数类型1, 参数类型2, ...) |
| 静态方法 | public static 返回类型 hook_方法名(参数类型1, 参数类型2, ...) |
三、完整示例代码
示例 1:Hook 实例方法
示例 2:Hook 静态方法
四、便捷方法
YAHFA 还提供了便捷方法:
五、方法签名格式
方法签名使用 JNI 描述符格式:
| Java 类型 | 描述符 |
|---|---|
| void | V |
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | J |
| float | F |
| double | D |
| 类类型 | L包名/类名; |
| 数组 | [ + 元素类型 |
示例:
- String getMessage() → ()Ljava/lang/String;
- int add(int, int) → (II)I
- void log(String) → (Ljava/lang/String;)V
六、注意事项
- Hook 方法必须是 static
- Backup 方法只是占位符,内容不重要,但签名必须兼容
- 实例方法需要添加 this 参数作为第一个参数
- Hook 会影响该类的所有实例
- 建议在 Application 或 Activity 的 onCreate 中初始化 hook
- 需要注意 SDK 版本兼容性(本项目已支持到 Android 16)
这就是 YAHFA 的完整使用方法!
YAHFA 库迁移指南
本指南总结如何从在线 YAHFA 库迁移到本地构建的支持 Android 16 的 YAHFA 库。
一、迁移步骤总结
1. 修改 settings.gradle
// 修改前
include ':app'
// 修改后
include ':app', ':library'
2. 修改 app/build.gradle
// 修改前
dependencies {
implementation 'io.github.pagalaxylab:yahfa:0.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
}
// 修改后
dependencies {
implementation project(':library')
implementation 'androidx.appcompat:appcompat:1.6.1'
}
3. 确保 library 模块存在
项目结构应包含:
yafha/
├── library/ # 本地 YAHFA 库模块
│ ├── src/
│ │ └── main/
│ │ ├── java/lab/galaxy/yahfa/
│ │ ├── jni/
│ │ └── res/
│ ├── build.gradle
│ └── CMakeLists.txt
├── app/
└── settings.gradle
二、library 模块的 build.gradle 配置
plugins {
id 'com.android.library'
}
android {
namespace 'lab.galaxy.yahfa'
compileSdk 33
defaultConfig {
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=none"
}
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
buildFeatures {
prefab true
buildConfig true
}
packagingOptions {
exclude "**/libdlfunc.so"
}
}
dependencies {
implementation 'io.github.rk700:dlfunc:0.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
三、CMakeLists.txt 配置
cmake_minimum_required(VERSION 3.4.1)
find_library(
log-lib
log
)
add_library(
yahfa
SHARED
src/main/jni/HookMain.c
src/main/jni/trampoline.c
src/main/jni/utils.c
)
if(${ANDROID_ABI} MATCHES "arm")
find_package(dlfunc REQUIRED CONFIG)
target_link_libraries(
yahfa
${log-lib}
dlfunc::dlfunc
)
else()
target_link_libraries(
yahfa
${log-lib}
)
endif()
四、代码修改(支持 Android 16)
1. common.h 修改
// 添加 Android 15 和 16 的 API 常量
// Android 16
#ifndef __ANDROID_API_V__
#define __ANDROID_API_V__ 36
#endif
// Android 15
#ifndef __ANDROID_API_U2__
#define __ANDROID_API_U2__ 35
#endif
// Android 14
#ifndef __ANDROID_API_U__
#define __ANDROID_API_U__ 34
#endif
2. HookMain.c 修改
// 更新 switch 语句支持 SDK 35 和 36
switch (sdkVersion) {
case __ANDROID_API_V__: // Android 16
case __ANDROID_API_U2__: // Android 15
case __ANDROID_API_U__: // Android 14
case __ANDROID_API_T__:
case __ANDROID_API_S_L__:
case __ANDROID_API_S__:
kAccPreCompiled = 0x00800000;
// ... 其他代码
五、构建命令
# 设置 Android SDK 路径
$env:ANDROID_HOME = "C:\Users\Administrator\AppData\Local\Android\Sdk"
# 清理并构建
.\gradlew.bat clean
.\gradlew.bat assembleDebug
六、验证迁移成功
1. 检查 APK 是否生成
app/build/outputs/apk/debug/app-debug.apk
2. 测试 Hook 功能
安装 APK 后,点击按钮测试 hook 是否正常工作,应该能看到 "Hello from Hook!" 的消息。
七、迁移前后对比
项目 迁移前 迁移后
YAHFA 库来源 在线仓库 io.github.pagalaxylab:yahfa:0.10.0 本地模块 project(':library')
支持的最高 SDK SDK 34 SDK 36 (Android 16)
库可定制性 不可修改 可自由修改源码
构建速度 依赖网络下载 本地构建,更快
八、注意事项
Gradle 版本:使用 Gradle 7.5 或兼容版本
Java 版本:使用 Java 17
NDK:确保已安装 Android NDK
SDK 版本:library 模块的 compileSdk 为 33,但代码已支持到 SDK 36
清理构建:迁移后建议先运行 clean 再构建
九、快速迁移检查清单
[ ] 修改 settings.gradle 添加 :library 模块
[ ] 修改 app/build.gradle 替换依赖为 project(':library')
[ ] 确认 library/ 目录存在且包含完整源码
[ ] 确认 common.h 包含 SDK 35 和 36 的常量
[ ] 确认 HookMain.c 的 switch 语句支持 SDK 35 和 36
[ ] 运行 .\gradlew.bat clean
[ ] 运行 .\gradlew.bat assembleDebug
[ ] 验证 APK 生成成功
[ ] 测试 Hook 功能正常
十、问题排查
问题 1:找不到 library 模块
解决方案:检查 settings.gradle 是否正确包含 :library
问题 2:编译错误 "multiple default labels"
解决方案:确保 HookMain.c 中只有一个 default: 标签
问题 3:JNI 构建失败
解决方案:检查 NDK 是否已安装,local.properties 中配置正确的 NDK 路径
问题 4:Hook 不生效
解决方案:检查代码是否正确调用 HookMain.backupAndHook(),方法签名是否匹配
浙公网安备 33010602011771号