第二篇读书笔记
拜读姜维大神的Android系统篇之—-免root实现Hook系统服务拦截方法
梳理了下思路,解决了疑惑
我们使用剪切板服务的时候是调用了ContextImpl
的getSystemService
方法
ContextImpl
的getSystemService
方法
1 | @Override |
该方法将返回Object
类型对象,我们将它强制转换为一个ClipboardManager
,也就是说它返回了一个ClipboardManager
供我们使用。而这个方法最终将构造一个ClipboardManager
,在ClipboardManager
构造的过程中,将获取远端Binder
并调用IClipboard.Stub
的asInterface
方法转化为本地代理对象保存在其中,
ClipboardManager
的一个构造函数
1 | /** {@hide} */ |
获取远端Binder
的操作其实是调用了ServiceManager
中的getService
方法,它返回的是一个远端Binder
,实际上也就是一个BinderProxy
(当然ServiceManager
会把这个远端对象缓存到sCache
中以应对频繁调用),姜维的文章里就是从这里切入,第一步先动态代理了这个BinderProxy
。
这里需要铭记一点,远端
Binder
需要调用Stub
的asInterface
方法转化为本地代理对象才能使用(上面说到在ClipboardManager
的构造函数中,这一步骤ClipboardManager
帮我们封装了这一操作)
ServiceManager
中的getService
方法
1 | /** |
下面继续解析姜维的文章中hook的流程,在上一步的动态代理之后,拦截了被代理对象(BinderProxy
对象)的queryLocalInterface
方法,下面是
BinderProxy
中queryLocalInterface
的实现
1 | public IInterface queryLocalInterface(String descriptor) { |
可以看见它直接返回了null
,而这个方法是在哪里被调用的呢,反编译framework.jar
发现,是在IClipboard.Stub
中,这里IClipboard
就是用aidl
生成的,和我们自己生成的差不多
看看
IClipboard.Stub
的asInterface
方法
1 | public static IClipboard asInterface(IBinder obj) { |
回到正题,姜维的文章里拦截了queryLocalInterface
以后,一开始我以为它又动态代理了一个叫做base
的对象,因为这里new了一个HookBinderInvocationHandler
,传入的第一个参数就是base
突然有点蒙这个base
是哪里冒出来的,看看上下文,发现是在第一个动态代理的Handler的构造函数里,传入了一个rawBinder
,赋值给了成员变量base
了,而这个rawBinder
,就是第一次代理中,被代理的那个远端Binder
,我就有点纳闷了,代理两次干啥?,仔细想,这只是个构造函数啊,我想传进去什么和我要动态代理什么对象没有关系呀。
于是翻回去看,动态代理的接口是this.iinterface
,看了下第一次动态代理的Handler的构造函数,看到1
this.iinterface = Class.forName("android.content.IClipboard")
仔细想想,这是要搞出来一个IClipboard
啊,其实这个IClipboard
我们前文接触过了,这里贴上IClipboard
部分源码(主要看结构)
1 | package android.content; |
梳理一遍,
第一次动态代理了远端Binder
,Handler是IClipboardHookBinderHandler
,
在第一次代理的Handler里面,拦截了queryLocalInterface
方法,
这个方法是在asInterface
里面调用的,
拦截以后,开始第二次动态代理,
用IClipboard
这个接口合成了一个代理对象,Handler是HookBinderInvocationHandler
,
把这个合成的代理对象return
了!!!
没错,这里是关键,它直接把它作为queryLocalInterface
方法的返回值return
了
看一下原来的BinderProxy中queryLocalInterface的实现
再看一下IClipboard.Stub的asInterface方法
在asInterface
方法里,我们合成的代理对象,赋值给了iin,接下来1
2
3
4
5IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin == null || !(iin instanceof IClipboard)) { //关键!!!!!
return new Proxy(obj); //没走这!!!
}
return (IClipboard) iin; //走了这里,我们合成的代理对象被强制转换以后直接返回了,被用来之后进行剪切板的一些操作
哇,几乎哭出来,看了那么久终于懂了关键部分,为什么作者不标记一下呢
/(ㄒoㄒ)/~~
我们比较一下:
hook前:
1 | [调用 getSystemService ] |
hook后:
1 | [Hook开始] |
就这样,两次动态代理,第一次代理远端对象,拦截queryLocalInterface
方法,第二次动态代理合成了一个实现了IClipboard
接口的对象,骗过了ClipboardManager
。