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插件启动总结:
- Hook系统的Instrumentation对象,设置创建的代理类
- 在代理类中修改启动Activity的Intent,将启动的目标Activity替换为占位Activity,从而避免注册清单的检查
- 在代理类中重写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;