GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

应用安全 --- 安卓逆向 之 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 的类)

// TargetClass.java
public class TargetClass {
    public String getMessage() {
        return "Hello from Original! 😊";
    }
}

3. 创建 Hook 类

// TargetHook.java
public class TargetHook {
    
    // Hook 方法:必须是 static
    // 第一个参数:如果是实例方法,需要添加 this 参数(类型为目标类)
    // 如果是静态方法,不需要 this 参数
    public static String hook_getMessage(TargetClass thiz) {
        return "Hello from Hook! 🎉";
    }
    
    // Backup 方法:占位符,必须是 static
    // 签名需要与目标方法兼容
    public static String backup_getMessage(TargetClass thiz) {
        return "backup";
    }
}

4. 执行 Hook

import lab.galaxy.yahfa.HookMain;
import java.lang.reflect.Method;
 
// 获取目标方法
Method targetMethod = TargetClass.class.getDeclaredMethod("getMessage");
 
// 获取 hook 方法
Method hookMethod = TargetHook.class.getDeclaredMethod("hook_getMessage"
TargetClass.class);
 
// 获取 backup 方法
Method backupMethod = TargetHook.class.getDeclaredMethod("backup_getMessage"
TargetClass.class);
 
// 执行 hook
HookMain.backupAndHook(targetMethod, hookMethod, backupMethod);

二、方法签名规则

目标方法类型Hook 方法签名要求
实例方法 public static 返回类型 hook_方法名(目标类类型 this, 参数类型1, 参数类型2, ...)
静态方法 public static 返回类型 hook_方法名(参数类型1, 参数类型2, ...)

三、完整示例代码

示例 1:Hook 实例方法

// 目标类
public class Calculator {
    public int add(int aint b) {
        return a + b;
    }
}
 
// Hook 类
public class CalculatorHook {
    public static int hook_add(Calculator thizint aint b) {
        return a * b; // 将加法改为乘法
    }
    
    public static int backup_add(Calculator thizint aint b) {
        return 0;
    }
}
 
// 使用
Method target = Calculator.class.getMethod("add"int.classint.class);
Method hook = CalculatorHook.class.getMethod("hook_add"Calculator.classint.
classint.class);
Method backup = CalculatorHook.class.getMethod("backup_add"Calculator.classint.
classint.class);
HookMain.backupAndHook(target, hook, backup);
 
// 测试
Calculator calc = new Calculator();
int result = calc.add(23)// 返回 6 而不是 5

示例 2:Hook 静态方法

// 目标类
public class MathUtils {
    public static int multiply(int aint b) {
        return a * b;
    }
}
 
// Hook 类
public class MathUtilsHook {
    public static int hook_multiply(int aint b) {
        return a + b; // 将乘法改为加法
    }
    
    public static int backup_multiply(int aint b) {
        return 0;
    }
}
 
// 使用
Method target = MathUtils.class.getMethod("multiply"int.classint.class);
Method hook = MathUtilsHook.class.getMethod("hook_multiply"int.classint.class);
Method backup = MathUtilsHook.class.getMethod("backup_multiply"int.classint.
class);
HookMain.backupAndHook(target, hook, backup);
 
// 测试
int result = MathUtils.multiply(23)// 返回 5 而不是 6

四、便捷方法

YAHFA 还提供了便捷方法:

// 只 hook,不需要 backup
HookMain.hook(targetMethod, hookMethod);
 
// 自动查找方法并 hook
HookMain.findAndHook(
    TargetClass.class,      // 目标类
    "getMessage",           // 方法名
    "()Ljava/lang/String;"// 方法签名
    hookMethod              // hook 方法
);
 
// 自动查找方法并 hook(带 backup)
HookMain.findAndBackupAndHook(
    TargetClass.class,
    "getMessage",
    "()Ljava/lang/String;",
    hookMethod,
    backupMethod
);

五、方法签名格式

方法签名使用 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

六、注意事项

  1. Hook 方法必须是 static
  2. Backup 方法只是占位符,内容不重要,但签名必须兼容
  3. 实例方法需要添加 this 参数作为第一个参数
  4. Hook 会影响该类的所有实例
  5. 建议在 Application 或 Activity 的 onCreate 中初始化 hook
  6. 需要注意 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(),方法签名是否匹配

 

 

 

 

posted on 2026-04-04 07:42  GKLBB  阅读(25)  评论(0)    收藏  举报