武汉,黄鹤楼
一、Hook的必要条件根据上一篇中Java反射与代理机制 讲的动态代理机制,主要的是两点:
1、Hook工具须要实现一个接口,并且这个接口方法中有我们须要注入代码的目标方法。

知足这两点,就可以利用newProxyInstance方法布局出目标工具的代理类,并且在代理工具反射调用的时候,可以调用到Handler里面的对应方法invoke方法里面。
2、知足1条件的同时,获取目标Hook工具。
这点为全体Hook过程中的难点,要想对某个工具的方法Hook,就要得到该类的工具,然后对付系统的类调用,很多情形是不随意马虎获取工具引用的。然后我们可以找一些静态变量(不用获取类实例)或者一些单例类(反正是单例子,肯定就一个),
来降落hook的难度及寻求技巧。
二、系统做事层架构大略剖析想要hook系统做事,就要熟习系统做事的基本架构,紧张是理解运用与系统交互的Binder架构办法,最好要先理解Binder的干系知识。
结合上节讲的Binder,总的来说可以理解系统做事的利用紧张理解下面这几点:
1.调用getSystemService(serviceName)方法可获取做事工具在本地进程的一个业务逻辑管理类。
2.方法内用到远端工具的,实在是调用了ServiceManager的getService方法,获取Ixxx类或xxxManager(以下用Ixxx代替)的远端Binder实体的一个本地BinderProxy。
3.调用ServiceManager的getService方法获取远端做事的IBinder工具,这个过程须要底层Binder驱动完成IPC通信。
4.有了远端做事的IBinder工具之后,通过Stub类的asInterface方法进行类型转化,获取目标接口工具。
5.系统中的做事获取都是肯定是跨进程的,远端做事都是在system_server进程中的,以是asInterface方法中返回的是Proxy代理工具,也便是本地真个中间者。
6.末了返回的工具实在便是这个Proxy工具,而这个工具内部利用了静态代理办法,内部有一个来自远真个mRemote变量即IBinder工具。然后直接调用方法实在便是调用mRemote的transact方法进行通信了。
三、Android系统中常用Hook点安卓系统中有很多我们可以直接动态代理的地方,要想理解和创造这些可hook的点,须要我们闇练的通读和理解源码知识、比如运用的启动过程、四大组件的启动过程、Handler源码剖析、View绘制流程等一系列基本知识体系。
通用的hook方案来接管系统各种ManagerService
我们想要获取系统的一个做事都会用到这么一段代码如下:
1
XXXManager manager=(XXXManager)getSystemService(XXX_SERVICE);
然后剖析getSystemService方法的详细实现,可以创造此类Manager自身材系做事干系方法在运用本地供应的一个代理类,真正的实现方法会同行getService()方法IPC到系统进程。
那么我们剖析下安卓源码的实现,SystemServiceRegistry供应了本地可类Manager的获取接口,任何找个Manager,剖析,比如进入ActivityManager,创造每个方法进步都会调用
ActivityManagerNative.getDefault()方法获取远端proxy来IPC系统进程的实现。
其他Manager类似,终极都会通过下面方法,来获取远端工具的Proxy。
1
IBinder b = ServiceManager.getService(\公众activity\公众);
剖析到这里,是不是就可以肯定只要我们Hook掉这个本地的代理,就可以骗掉系统远端实现,并在这个代理类中注入我们需求逻辑,那接下来看看这个本地代理的获取源码,符合动态代理哀求吗?
public final class ServiceManager {private static final String TAG = \公众ServiceManager\"大众;private static IServiceManager sServiceManager;private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}/ Returns a reference to a service with the given name. @param name the name of the service to get @return a reference to the service, or <code>null</code> if the service doesn't exist/public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return getIServiceManager().getService(name);}} catch (RemoteException e) {Log.e(TAG, \"大众error in getService\"大众, e);}return null;}/ Place a new @a service called @a name into the service manager. @param name the name of the new service @param service the service object/public static void addService(String name, IBinder service) {try {getIServiceManager().addService(name, service, false);} catch (RemoteException e) {Log.e(TAG, \"大众error in addService\"大众, e);}}..........省略}
该类中,紧张看有个getService方法,和一个sCache 缓存。
sCache中保存的是远端做事的一个Ibinder工具,很明显他是实现Ibinder接口的, 并且这两个东西都是静态的,意味着我们可以反射调用getService,然后把sCache里的目标Ibinder更换为我们的动态代理工具。
Hook掉这个工具是不是就可以拦截系统方法了呢? 答案是否定的。
应为这里hook掉的是一个IBinder接口,只是Binder驱动给我们的一个BinderProxy,BinderProxy是Binder内部final类型的类只是实现类IBinder接口,并没有我们须要拦截的方法。
那怎么才能够拦截我们的目标方法呢? 当然是找到有这些方法的接口类,比如:IActivityManager、IServiceManager、IClipboard等…
那么这些接口类是怎么通过Binder驱动返回的BinderProxy工具来转化的呢? 做过AIDL开拓的,该当很熟习下面代码
//参数便是返回的BinderProxy....public static Ixxx asInterface(IBinder obj) {if(obj == null) {return null;} else {IInterface iin = obj.queryLocalInterface(\"大众android.app.Ixxx\"大众);return (Ixxx)(iin != null && iin instanceof Ixxx?(Ixxx)iin:new Ixxx.Stub.Proxy(obj));}}
可以看出,只要obj.queryLocalInterface返回不为null,就会返回这个方法里的内容给外界调用的地方(即Ixx类的接口赋值)。
而queryLocalInterface方法又恰好是IBinder接口中的方法,那么我们已经Hook掉的BinderProxy,再次hook掉BinderProxy的queryLocalInterface()方法,就可以完备更换系统层Ixx
类的远端做事确当地代理接口。
关键代码如下:
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {........if(\"大众queryLocalInterface\"大众.equals(method.getName()){............return Proxy.newProxyInstance(getClassLoader(),........................................new Class[]{Ixxx},........................................new HookBinderInvocationHandler();........}}
通过以上代码,就可以在HookBinderInvocationHandler类中,的invoke方法中连接Ixx接口的所有系统方法,并且注入自己的代码逻辑。
到这里大功告成,通过这种方法,基本上系统方法都可以hook掉。但是有没有别的办法呢?这种在办法至少须要有两个hook点,是否有必要呢?
实在hook是一项技巧活,Hook的次数须要实际情形的而定,要想通过动态代理实现hook,就须要从上面说的两点出发,获取可hook的工具及地点,找这两个点的难易程度决定了全体hook过程的次数及难易程度。
AMS做事的hook剖析
在插件化实现过程中,Hook系统AMS是最基本也是最主要的学习内容, 接管AMS才能定制化干系插件逻辑,为运用层开拓解耦。
Hook的技能须要灵巧运用,比如AMS的Hook本来可以用上面的通用方法Hook掉,那详细问题详细剖析,有没有更加大略的办法呢? 有!
想要找到AMS精确的hook点,须要对运用的启动有一定理解,可以这篇文章剖析AMS远端做事调用机制以及Activity的启动流程。
通用Hook方案中,由于第一次hook无法获取Ixx类的接口工具,以是多了一次hook。然后是不是只要我们一次性获取Ixx类的实例工具,就可以一次Hook完成接管系统做事。
ams
AMS
看下运用启动过程源码及ActivityManager源码,会创造远端代理的获取并没有每次都采取getService,而是采取单例形式保存在一个静态变量里。
123456789101112131415
ActivityManagerNative.getDefault()private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService(\"大众activity\"大众);if (false) {Log.v(\公众ActivityManager\"大众, \"大众default service binder = \公众 + b);}IActivityManager am = asInterface(b);if (false) {Log.v(\"大众ActivityManager\公众, \"大众default service = \"大众 + am);}return am;}};
从上面代码可以看出,这里获取带远真个BinderProxy后,通过asInterface()方法转化成我们的hook目标接口类,并且返回后保存在一个静态变量里。
这样就为我们反射和动态代理这个点供应了方便。
1、利用反射获取这个gDefault里保存的IActivityManager;
2、动态代理产生一个代理类,更换掉这个IActivityManager;
代码如下:
try{....Class<?> activityManagerNativeClass = Class.forName(\公众android.app.ActivityManagerNative\公众);....// 获取 gDefault 这个字段, 想办法更换它....Field gDefaultField = activityManagerNativeClass.getDeclaredField(\公众gDefault\公众);....gDefaultField.setAccessible(true);....Object gDefault = gDefaultField.get(null);....// 4.x以上的gDefault是一个 android.util.Singleton工具; 我们取出这个单例里面的字段....Class<?> singleton = Class.forName(\"大众android.util.Singleton\公众);....Field mInstanceField = singleton.getDeclaredField(\公众mInstance\公众);....mInstanceField.setAccessible(true);....// ActivityManagerNative 的gDefault工具里面原始的 IActivityManager工具....Object rawIActivityManager = mInstanceField.get(gDefault);....// 创建一个这个工具的代理工具, 然后更换这个字段, 让我们的代理工具帮忙干活....Class<?> iActivityManagerInterface = Class.forName(\"大众android.app.IActivityManager\"大众);....Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(rawIActivityManager));....mInstanceField.set(gDefault, proxy);}四、总结
android平台动态代理办法hook系统,首选须要对hook的整理逻辑很熟习,并且能给灵巧找到hook地方,核心规则便是:能获取到要hook点的类工具,然后动态代理更换掉。
通过阅读源码创造,安卓平台架构中,很多地方都是类似的框架,以是我们可以用同样的办法取hook掉系统的其他做事。
——————
常兴E站 | www.canking.win