Android插件化——高手必备的Hook技术,零基础开发android

简介: Android插件化——高手必备的Hook技术,零基础开发android
intent.setComponent(componentName);
className = classnameIntent;
}
Log.d("FixInstrumentation == ", “set activity is original” + className);
try {
@SuppressLint(“PrivateApi”)
Method method = instrumentation.getClass().getDeclaredMethod(“newActivity”,
ClassLoader.class, String.class, Intent.class);
if (!Modifier.isPublic(method.getModifiers())) {
method.setAccessible(true);
}
return (Activity) method.invoke(instrumentation, cl, className, intent); // 执行原来的创建方法
}
}

Hook Instrumentation实现Activity插件启动总结:

  1. Hook系统的Instrumentation对象,设置创建的代理类
  2. 在代理类中修改启动Activity的Intent,将启动的目标Activity替换为占位Activity,从而避免注册清单的检查
  3. 在代理类中重写newActivity()将启动的活动换回真实目标,然后继续执行原有逻辑

3、Binder Hook(Hook 系统服务)

上面通过Hook技术修改了活动的启动过程,属于应用程序的Hook,下面尝试Hook Android的系统服务,修改系统的功能,在Hook之前还是先了解一下系统服务的获取过程,并尝试寻找Hook点;

3.1、系统获取服务的原理
• ContextImpl.getSystemService(String name)
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
public static Object getSystemService(ContextImpl ctx, String name) {
//1、从注册的SYSTEM_SERVICE_FETCHERS中根据名称获取ServiceFetcher
ServiceFetcher fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null; //2、ServiceFetcher中创建服务
}
在使用系统服务时会直接调用Context的getSystemService(),最终调用ContextImpl中的方法,在ContextImpl中调用SystemServiceRegistry.getSystemService(),关于SystemServiceRegistry简单介绍一下,系统在启动时会向SystemServiceRegistry中注册一系列服务,在使用过程中直接根据服务名换获取服务;
• SYSTEM_SERVICE_FETCHERS中注册服务(以JOB_SCHEDULER_SERVICE为例)
//注册服务
registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class, new StaticServiceFetcher() {
@Override
public JobScheduler createService() {
IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE); //从ServiceManager中获取Binder
return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)); //获取Binder的代理对象
}});
private static void registerService(String serviceName, Class serviceClass,ServiceFetcher serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); //以键值对的形式保存服务名称、StaticServiceFetcher实例
}
从上面的注册过程知道,系统首先将每个服务的创建过程封装在对应的ServiceFetcher对象中,然后将ServiceFetcher对象以服务名称注册在SYSTEM_SERVICE_FETCHERS中,这也就是为什么获取服务时传入服务名称;
• ServiceManager.getService():获取系统中相应服务对应的Binder对象
public JobScheduler createService() throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.JOB_SCHEDULER_SERVICE);
return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
}
在服务获取的过程中会调用ServiceFetcher的createService()方法,在create()中首先获取系统中保存的Binder对象,然后根据Binder对象调用asInterface()查找代理类,asInterface()会先检查本进程是否存在Binder对象,如果不存在则创建一个代理对象;
• 总结一下服务的获取过程:
1. 在系统开始时,系统会像SYSTEM_SERVICE_FETCHERS注册封装服务的ServiceFetcher实例
2. 在程序调用获取服务时,根据服务名称从SYSTEM_SERVICE_FETCHERS查找并返回对应的ServiceFetcher实例
3. 调用实例的get()获取服务时,首先从ServerManager中获取系统中保存服务的Binder
4. 调用IxxInterface的asInterface()方法查找并返回Binder的代理类
3.2、寻找Hook点
1. 通过上面的分析知道,可以操作的地方就是obj.queryLocalInterface(),如果我们Hook了传入的Binder对象,修改他的queryLocalInterface就可以返回替代的对象的代理对象,就可实现代理;
2. 要想实现目标1就必须确保ServerManager的查找中能返回我们指定的Binder,好在ServerManager中从系统Map缓存中获取,我们只要将代理的Binder放在缓存的Map,然后在查找时即可返回指定的Binder;
3.3、实战——以剪切版服务为例
• 创建服务的动态代理类
public class FixBinder implements InvocationHandler {
private static final String TAG = “BinderHookHandler”;
// 原来的Service对象 (IInterface)
Object base;
public FixBinder(IBinder base, Class stubClass) {
try {
Method asInterfaceMethod = stubClass.getDeclaredMethod(“asInterface”, IBinder.class);//获取原接口的asInterface
this.base = asInterfaceMethod.invoke(null, base); //使用原来的Binder反射执行获取本来服务的代理类
} catch (Exception e) {
throw new RuntimeException(“hooked failed!”);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 欺骗系统,使之认为剪切版上一直有内容
if (“hasPrimaryClip”.equals(method.getName())) {
return true;
}
return method.invoke(base, args); //其余方法使用原Binder代理反射执行
}
}
1. 这里和前面直接保存系统对象不同,因为在查找服务时首先获得的是系统的Binder,只有自己利用Binder其查找才会返回代理类
2. 在构造函数中传入系统中查找的Binder对象,然后反射调用asasInterface()获取并保存系统服务本身的服务的代理类
3. 拦截剪切方法,拦截hasPrimaryClip()方法返回true,使系统一直认为剪切板上有内容
• 创建Binder对象
public class ProxyBinder implements InvocationHandler {
IBinder base;
Class stub;
Class iinterface;
public ProxyBinder(IBinder base) {
this.base = base; //(1)
try {
this.stub = Class.forName("android.content.IClipboard$Stub”); //(2)
this.iinterface = Class.forName(“android.content.IClipboard”);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (“queryLocalInterface”.equals(method.getName())) { //(3)
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(),//(4)
// asInterface 的时候会检测是否是特定类型的接口然后进行强制转换
// 因此这里的动态代理生成的类型信息的类型必须是正确的,即必须是以下3个接口实例
new Class[] { IBinder.class, IInterface.class, this.iinterface },
new FixBinder(base, stub));
}
return method.invoke(base, args);
}
}
第一创建了系统服务的代理类,由前面分析知道了,代理类的使用是由Binder查询出来的,所以下一步要创建一个Binder类,并且内部拦截查询的queryLocalInterface()方法,让此方法返回第一步的代理类,创建步骤:
1. 和普通代理一样,在代理内部保存ServerManager中原来真正的Binder
2. 利用反射获取IClipboard$Stub类,用于查找代理类
3. Hook了queryLocalInterface方法
4. 在invoke()拦截到方法后,使用动态代理创建并返回IClipboard的代理Binder
• Hook 替换ServerManager中的Binder
final String CLIPBOARD_SERVICE = “clipboard”;
// 下面这一段的意思实际就是: ServiceManager.getService(“clipboard”);
Class serviceManager = Class.forName(“android.os.ServiceManager”);
Method getService = serviceManager.getDeclaredMethod(“getService”, String.class);
// (1)ServiceManager里面管理的原始的Clipboard Binder对象
IBinder rawBinder = (IBinder) getService.invoke(null, CLIPBOARD_SERVICE);
//(2) Hook 掉这个Binder代理对象的 queryLocalInterface 方法
IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader(),
new Class[] { IBinder.class },
new BinderProxyHookHandler(rawBinder));
// (3)把这个hook过的Binder代理对象放进ServiceManager的cache里面
Field cacheField = serviceManager.getDeclaredField(“sCache”);
cacheField.setAccessible(true);
Map cache = (Map) cacheField.get(null);
cache.put(CLIPBOARD_SERVICE, hookedBinder);

通过前面两部已经将所有要创建的代理Binder实现了,剩下的就是要将ProxyBinder放入系统ServiceManager的缓存中,这样在查询时才会按我们的要求返回Binder,后面的套路才能执行下去,具体的Hook过程见代码注释;

4、Hook 系统服务AMS(Android 9.0)

上面两个例子已经将Hook的使用介绍清楚了,接下来再利用Hook技术拦截系统的AMS,改变系统的服务启动,也是插件化启动服务的原理,这里实现启动未注册的MyService,关于Service的启动过程点击上面的四大组件的链接查看,因为AMS也是通过Binder通信的所以Hook的第一步要实现Binder的动态代理

• 创建AMS的代理,实现功能拦截服务的启动过程
public class HookProxyBinder implements InvocationHandler {
public static final String HookProxyBinder = “HookProxyBinder”;
Object binder;
public HookProxyBinder(Object binder) {
this.binder = binder;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e(“HookProxyBinder==”, method.getName());
if (“startService”.equals(method.getName())) { //拦截启动服务
int i = 0;
Intent intent = null;
for (int index = 0; index < args.length; index++) {
if (args[index] instanceof Intent) {
i = index;


相关文章
|
20天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
20天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
45 14
|
21天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
31 5
|
20天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
21天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
21天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
21天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
27 0
|
7月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
410 1
|
4月前
|
安全 Android开发 Swift
安卓与iOS开发:平台差异与技术选择
【8月更文挑战第26天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各占一方。本文旨在探索这两个系统在开发过程中的不同之处,并分析开发者如何根据项目需求选择合适的技术栈。通过深入浅出的对比,我们将揭示各自平台的优势与挑战,帮助开发者做出更明智的决策。
79 5
|
4月前
|
移动开发 搜索推荐 Android开发
安卓与iOS开发:一场跨平台的技术角逐
在移动开发的广阔舞台上,两大主角——安卓和iOS,持续上演着激烈的技术角逐。本文将深入浅出地探讨这两个平台的开发环境、工具和未来趋势,旨在为开发者揭示跨平台开发的秘密,同时激发读者对技术进步的思考和对未来的期待。