❶ Android Binder Hook的实现
Binder Hook可以Hook掉 当前App 用到的系统Service服务。
以LocationManager为例,在获取一个LocationManager时分为两步。第一,获取IBinder对象;第二:IBinder对象通过asInterface()转化为LocationMangerService对象。最后初始化LocationManager,application层用到的都是LocationManager。
Hook的大致原理是:ServiceManager在获取某个Binder时,如果本地有缓存的Binder,就不再跨进程请求Binder了。我们可以在缓存中加入自己的Binder,使得ServiceManager查询本地缓存时得到一个自定义的CustomBinder对象,不再跨进程向系统请求。并且ILocationManager.Stub.asInterface(CustomBinder)方法返回我们自定义的Service对象。
这里面有两个地方需要用到自定义的对象。由于我们只Hook其中一部分的功能,其他功能还需要保留,所以用动态代理的方式创建自定义的Binder和自定义的Service。
在理解后面的内容前你需要了解这些知识点:
Activity等类在获取系统Service时,都是调用getSystemService(serviceName)方法获取的。
Context 的 getSystemService() 方法调用了 SystemServiceRegistry 的 getSystemService() 方法。
SystemServiceRegistry 中有一个常量 SYSTEM_SERVICE_FETCHERS,这是一个Map。保存了ServiceName和对应的ServiceFetcher。ServicFetcher是用于创建具体Service的类。ServiceFetcher 的关键方法是 createService() 方法。
在 ServiceFetcher 的 createService() 方法中,调用了 ServiceManager.getService(name) 方法。以 LocationManager 对应的 ServiceFetcher 为例,它的createService()方法源码如下:
假如我们要修改 LocationManager 的 getLastKnownLocation() 方法(下文都是)。我们要做的就是让ServiceManager.getService("location")返回我们自定义的Binder。先看一下这个方法简化后的源码:
sCache是一个Map,缓存了已经向系统请求过的Binder。如果我们需要让这个方法返回我们我们自己的binder,只需要事先往sCache中put一个自定义的Binder就行了。
在put之前,需要先创建出一个自定义的Binder。这个Binder在被 ILocationManager.Stub.asInterface 处理后,可以返回一个自定义的 LocationManagerService。
先看一下Binder的 asInterface() 的实现:
如果把 queryLocalInterface()方法返回一个自定义的Service,使得走if语句内部,不走else,那就算是Hook成功了。
假设我们想让系统的LocationManager返回的位置信息全是在天安门(116.23, 39.54)。那我们需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (116.23, 39.54)。
由于我们不能直接拿到系统的这个Service对象,可以先用反射的方式拿到系统的LocationManagerService。然后拦截getLastLocation()方法。
原生的Binder对象在调用 queryLocalInterface() 方法时会返回原生的Service对象。我们希望返回3.1中的自定义Service。所以这里拦截 queryLocalInterface() 方法。
有了自定义的Binder后,将它注入到ServiceManger的sCache变量中就完成Hook了~
当onClick被调用的时候,Toast和Log都会显示天安门的坐标(116.23, 39.54)。证明Hook成功!
你甚至可以用Binder Hook的方式Hook掉 ActivityManager 。