首页
社区
课程
招聘
[原创]Albatross Android——快速、优雅的强大安卓hook框架
发表于: 2025-7-20 13:57 9842

[原创]Albatross Android——快速、优雅的强大安卓hook框架

2025-7-20 13:57
9842

项目地址

该项目是两年前开发的,一年前已经开始尝试集成到沙箱中,最近根据功能需求,后续的代码都使用自研的框架。非常的好用,所以特定分享出来。现在是自己写的albatros-server用于hook的system_server和app,可用于hook和反射,能极大的简化代码逻辑,可以强制将被hook的类转换成hooker,直接调用方法和访问字段,避免反射的开销

Albatross Android 是一个专为 Android 平台(支持 Android 8.0 到 Android 16)设计的高性能、低影响的 Hook 框架。

Albatross Android 的核心机制是通过定义“Hooker 类”(镜像类)来描述需要 Hook 的类和字段。框架会自动推导出目标方法和字段,并实现对目标类的无缝调用和访问。与传统的反射机制不同,Albatross 几乎没有性能损耗,同时兼顾了安全性和兼容性。

Albatross 基于 YAHFA 框架进行了大量优化和功能扩展,使其在Android系统上具备更强的稳定性和性能表现。

其设计目标包括:

通过定义 Hooker 类(即镜像类)来描述目标类的方法和字段,框架会自动推导出目标类并进行 Hook。例如:

Albatross 支持基于事务的批量 Hook,自动解决 Hook 类之间的依赖关系,确保 Hook 流程的原子性和稳定性。

不同于传统 Hook 框架依赖反射调用方法和访问字段的方式,Albatross 直接使用本地机器码调用方法和访问字段,几乎没有任何性能损耗。

支持在目标类加载时自动触发 Hook,无需关心类何时加载。框架会在新 DEX 被加载时主动寻找目标类并进行 Hook。

不仅可以作为 Hook 框架使用,还可以作为高性能的反射库使用,避免传统反射带来的性能开销。

Albatross 正在持续开发中,计划引入以下功能(根据反馈优先级实现):

开发Albatross的目标是淘汰掉Xposed,这种基于callback根本不是好的实现方式,导致后面的新框架都认为callback是理所应当的,成了一种规范。所以计划后面开发多开软件,免root方案加载基于albatross开发的插件,一点点蚕食掉xposed的份额。

@TargetClass(Activity.class)
public class ActivityHooker {
    @FieldRef
    public boolean mCalled;
 
    @MethodHookBackup
    private void onCreate(Bundle savedInstanceState) {
        // Hook 后可以调用原始方法
        onCreate(savedInstanceState);
    }
}
@TargetClass(Activity.class)
public class ActivityHooker {
    @FieldRef
    public boolean mCalled;
 
    @MethodHookBackup
    private void onCreate(Bundle savedInstanceState) {
        // Hook 后可以调用原始方法
        onCreate(savedInstanceState);
    }
}
Android 版本 支持状态 说明
Android 8 - Android 16 完全支持 支持方法和字段 Hook
Android 7 (API 24-25) 有限支持 方法 Hook 支持,字段 Hook 因 dex优化限制被禁用
Android 6 及以下版本 不支持 没有JIT,dex指令优化原因Field特性无法实现
@TargetClass(Activity.class)
public class ActivityH {
    @TargetClass(Bundle.class)
    public static class BundleH {
        @FieldRef
        public static Bundle EMPTY;
    }
 
    @FieldRef
    public boolean mCalled;
 
    @MethodHookBackup
    private void onCreate(BundleH savedInstanceState) {
        assert BundleH.EMPTY == Bundle.EMPTY;
        assert !mCalled;
        onCreate(savedInstanceState);
        assert mCalled;
    }
}
@TargetClass(Activity.class)
public class ActivityH {
    @TargetClass(Bundle.class)
    public static class BundleH {
        @FieldRef
        public static Bundle EMPTY;
    }
 
    @FieldRef
    public boolean mCalled;
 
    @MethodHookBackup
    private void onCreate(BundleH savedInstanceState) {
        assert BundleH.EMPTY == Bundle.EMPTY;
        assert !mCalled;
        onCreate(savedInstanceState);
        assert mCalled;
    }
}
@TargetClass(className = {"com.android.server.LocationManagerService", "com.android.server.location.LocationManagerService"})
public class LocationManagerServiceH {
    @MethodHookBackup
    private void requestLocationUpdates(LocationRequest request, Object listener, PendingIntent intent, String packageName) {
        requestLocationUpdates(request, listener, intent, packageName);
    }
}
@TargetClass(className = {"com.android.server.LocationManagerService", "com.android.server.location.LocationManagerService"})
public class LocationManagerServiceH {
    @MethodHookBackup
    private void requestLocationUpdates(LocationRequest request, Object listener, PendingIntent intent, String packageName) {
        requestLocationUpdates(request, listener, intent, packageName);
    }
}
@TargetClass
public static class ActivityClientRecord {
    @FieldRef
    public LoadedApk packageInfo;
    @FieldRef
    public Intent intent;
}
 
@TargetClass
public static class LoadedApk {
    @FieldRef
    public String mPackageName;
}
 
@TargetClass(className = "android.app.ActivityThread")
public static class ActivityThreadH {
    public static Class<?> Class;
 
    @StaticMethodBackup
    public static native Application currentApplication();
 
    @MethodBackup(option = MethodDefOption.NOTHING)
    private native Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent);
 
    @FieldRef
    Map<IBinder, ActivityClientRecord> mActivities;
 
    @StaticMethodBackup
    public static native ActivityThreadH currentActivityThread();
}
 
public static void test() throws AlbatrossErr {
  assert Albatross.hookClass(ActivityThreadH.class) != 0;
  ActivityThreadH activityThread = ActivityThreadH.currentActivityThread();
  assert activityThread.getClass() == ActivityThreadH.Class;
  Application app = ActivityThreadH.currentApplication();
  String targetPackage = app.getPackageName();
  for (ActivityClientRecord record : activityThread.mActivities.values()) {
    assert targetPackage.equals(record.packageInfo.mPackageName);
  }
}
@TargetClass
public static class ActivityClientRecord {
    @FieldRef
    public LoadedApk packageInfo;
    @FieldRef
    public Intent intent;
}
 
@TargetClass
public static class LoadedApk {
    @FieldRef
    public String mPackageName;
}
 
@TargetClass(className = "android.app.ActivityThread")
public static class ActivityThreadH {
    public static Class<?> Class;
 
    @StaticMethodBackup
    public static native Application currentApplication();
 
    @MethodBackup(option = MethodDefOption.NOTHING)
    private native Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent);
 
    @FieldRef
    Map<IBinder, ActivityClientRecord> mActivities;
 
    @StaticMethodBackup
    public static native ActivityThreadH currentActivityThread();
}
 
public static void test() throws AlbatrossErr {
  assert Albatross.hookClass(ActivityThreadH.class) != 0;

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-7-22 08:39 被WanQing编辑 ,原因: 添加BinderHook的示例
收藏
免费 187
支持
分享
最新回复 (158)
雪    币: 1
活跃值: (3798)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
是要不用frida,自己来,厉害了
2025-7-20 23:11
0
雪    币: 45
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
是的,不需要,项目里的arm64 hook也是最完美的方案,会代码分析,选出合适的临时寄存器,java aot或jit短的代码,都能被完美hook.
2025-7-20 23:22
1
雪    币: 5
活跃值: (1905)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
so层代码没开源吗
2025-7-21 01:31
0
雪    币: 3011
活跃值: (3849)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
恋一世的爱 so层代码没开源吗
不是写了其他模块陆续开源嘛
2025-7-21 03:24
0
雪    币: 213
活跃值: (1286)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
666
2025-7-22 13:27
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
666
2025-7-22 13:40
0
雪    币: 280
活跃值: (535)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
tql
2025-7-22 13:55
0
雪    币: 6101
活跃值: (5880)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
66
2025-7-22 14:23
0
雪    币: 4076
活跃值: (3141)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
666
2025-7-22 14:31
0
雪    币: 5619
活跃值: (9407)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
注解是hook框架吗,  niubplus
2025-7-22 14:32
0
雪    币: 375
活跃值: (3181)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
niubplus
2025-7-22 14:39
0
雪    币: 51
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
niubi
2025-7-22 14:45
0
雪    币: 3243
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
看看
2025-7-22 14:59
0
雪    币: 143
活跃值: (545)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
66666666666
2025-7-22 16:20
0
雪    币: 102
活跃值: (3290)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
mark..........
2025-7-22 16:25
0
雪    币: 751
活跃值: (1797)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
好东西,支持一下
2025-7-22 17:36
0
雪    币: 229
活跃值: (343)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
m
2025-7-22 17:43
0
雪    币: 10
活跃值: (1925)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
如果类名和方法名是在运行时动态找出来的,怎么 hook?如果实现不了这个,很难取代 Xposed。
2025-7-22 18:26
0
雪    币: 45
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
支持pending hook的,类似demo中的@TargetClass(className = {"name1", "name2"},pendingHook=true),把可能的类名写进去。如果能拿到对象,可以调用hookObject
2025-7-22 18:52
0
雪    币: 45
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
twsxtd 如果类名和方法名是在运行时动态找出来的,怎么 hook?如果实现不了这个,很难取代 Xposed。
如果想要一个方法去hook多个类,就比如okhttp,sdk可能和app都集成了,app中有好几个,我的方案是拷贝好几个OkHttphooker,在一个类的数组中,去用可用的hooker去hook去加载出来的okhttp。还有一种方案是方案签名多一个参数,用于区分是调用哪个方法,但field特性就不能用了,字段偏移不一样。
2025-7-22 19:01
0
雪    币: 1689
活跃值: (281)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
太强了,qqqqq
2025-7-22 21:56
0
雪    币: 6
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
6666
2025-7-23 13:47
0
雪    币: 210
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
康康
2025-7-23 14:10
0
雪    币: 105
活跃值: (2227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
6666
2025-7-23 14:15
0
游客
登录 | 注册 方可回帖
返回