Android系统篇之----免root实现Hook系统服务拦截方法

技术概念来源:[ 360开源插件框架,项目地址:https://github.com/DroidPluginTeam/DroidPlugin ]

一、Binder机制回顾

在之前一篇文章中介绍了 Android中的Binder机制和系统远程服务调用机制,本文将继续借助上一篇的内容来实现Hook系统服务拦截指定方法的逻辑,了解了上一篇文章之后,知道系统的服务其实都是一个远程Binder对象,而这个对象都是由ServiceManager大管家管理的,用户在使用系统服务的时候,会通过指定服务的Stub方法的asInterface把远程的Binder对象转化成本地化对象即可使用,而在这个过程中,我们也知道因为系统服务是在system_server进程中的,所以这个系统服务使用过程中属于跨进程调用,那么返回的对象其实就是Proxy代理对象。

二、系统中服务使用流程

本文主要就是借助这个知识点,通过Hook系统的服务来拦截服务方法,下面我们就通过系统剪切板服务案例作为分析

这里看到了,使用系统服务的时候都是用了getSystemService方法,通过定义在Context中的服务描述符常量来获取服务对象,而getSystemService方法定义在ComtextImpl.java类中:

这里维护了一个ServiceFetcher的Map结构,看看这个结构在哪里填充数据的:

在registerService方法中添加一个服务名称和一个ServiceFetcher对象,而这个方法在静态代码块中进行调用的:

我们找到了ClipboardManager这个服务:

这里其实是一个ClipboardManager对象,其实这个对象是内部封装了IClipboard.Stub功能,可以看看其他的服务:

比如这里的联网服务,直接调用了IConnectivityManager.Stub类的asInterface方法获取Proxy对象。

下面就进去ClipboardManager.java中看看究竟:

看到这里的设置剪切板内容的方法,其实内部是调用了getService方法获取对象然后在调用指定方法,那么可以大概知道了这个getService方法返回的应该就是IClipboard.Stub通过asInterface方法返回的Proxy对象:

好吧,果然是这样,这里通过ServiceManager获取到Clipboard的远端IBinder对象,然后通过asInterface方法返回一个Proxy对象即可。

到这里我们就简单的分析完了系统中的获取剪切板的服务,其实系统中的服务都是这么个逻辑,只是有的可能会在外面包装一层罢了,下面总结一下流程:

现在只要记住一点:每次获取系统服务的流程都是一样的,先通过ServiceManager的getService方法获取远端服务的IBinder对象,然后在通过指定服务的Stub类的asInterface方法转化成本地可使用对象,而这个对象其实就是一个Proxy对象,在这个过程中,Stub类继承了Binder对象和实现了AIDL接口类型,Proxy对象实现了AIDL接口类型,而AIDL接口类型实现了IInterface接口类型。

三、Hook系统服务

上面分析完了Android中系统服务的使用流程以及原理解析,下面在来看一下Android中实现Hook机制的方法和原理解析,我们知道其实在很多系统中都存在这样一个Hook技术,有的也叫作钩子,但是不管任何系统,Hook技术的核心点都是一样的,只有两点即可完成Hook技术:

1、找到Hook点,即你想Hook哪个对象,那么得先找到这个对象定义的地方,然后使用反射获取到这个对象实例。所以这里可以看到,一般Hook点都是一个类的单例方法或者是静态变量,因为这样的话Hook起来就非常方便,都是static类型,反射调用都比较方便无需具体的实例对象即可。而关于这个点也是整个Hook过程中最难的点,因为很难找到这个点。Android中主要是依靠分析系统源码类来做到的。

2、构造一个Hook原始对象的代理类,关于这个代理其实在Java中有两种方式,一种是静态代理,一种是动态代理。

静态代理:代理类中维护一个原始对象的成员变量,每个方法调用之前调用原始对象的方法即可。无需任何条件限制

动态代理:比静态代理复杂点就是有一个规则:就是原始对象必须要实现接口才可以操作,原理是因为动态代理其实是自动生成一个代理类的字节码,类名一般都是Proxy$0啥的,这个类会自动实现原始类实现的接口方法,然后在使用反射机制调用接口中的所有方法。

案例使用就很简单了,下面我们通过源码分析这个原理:

主要调用了getProxyClass0方法生成代理类的字节码:

然后生成代理类:

看到这里,其实这里的生成字节码不是很复杂的,我们可以借助asm等工具包就可以手动的生成一个字节码,然后在使用类加载器加载即可,所以会发现需要传递类加载器。

当上面生成代理类之后,我们可以把这个类反编译看一下,看一下方法的调用,在代理类中的静态代码块:

会使用反射获取到类的所有方法。

然后在指定方法中调用传递进来的InvocationHandler的回调接口的invoke方法,就是这么实现的。

从源码角度分析完动态代理之后,发现其实没什么复杂的,就是手动的生成一个代理类,然后用反射获取类中所有的方法,在指定方法中用反射调用,同时回调InvocationHandler的invoke方法即可,所以这里看到InvocationHandler中的invoke方法的第一个参数对象是代理类对象。

注意:

在JavaWeb开发中我们会用到Spring框架中的AOP编程,其实他就是利用了Java中动态代理技术,但是他依赖的是CGlib的功能,不是采用Java原生的这种自动产生代理类,从上面可以看到能够做动态代理的类必须要实现一个接口,而这一个规则有时候要求非常高,很多类都没有实现接口,导致无法实现代理功能,所以Spring采用了cglib,原理其实差不多,他采用asm工具包也是手动生成一个类,但是这个类是原始对象的子类,这样也可以实现代理功能,但是这样一来也有一个限制了,那就是代理对象不能是final类型,同时一些主要方法最好不能是final类型的,当然这个限制和上面的那个接口实现限制比起来还是好点的。

到此我们了解了Java中的Hook技术的核心知识点了,下面就用开始的剪切板服务来做实验,我们Hook系统的剪切板服务功能,拦截其方法,上面也说道了,既然要Hook服务,首先得找到Hook点,通过开始对Android中系统服务的调用流程分析知道,其实这些服务都是一些保存在ServiceManager中的远端IBinder对象,这其实是一个Hook点:

其实ServiceManager中每次在获取服务的时候,其实是先从一个缓存池中查找,如果有就直接返回了:

而这个缓存池正好是全局的static类型,所以就可以很好的使用反射机制获取到他了,然后进行操作了。

接下来,我们就需要构造一个剪切板的服务IBinder对象了,然后在把这个对象放到上面得到的池子中即可。那么按照上面的动态代理的流程,

第一、原始对象必须实现一个接口,这里也正好符合这个规则,每个远程服务其实是实现了IBinder接口的。

第二、其次是要有原始对象,这个也可以,通过上面的缓存池即可获取

有了这两个条件那么接下来就可以使用动态代理构造一个代理类了:

通过反射去获取ServiceManager中的缓存池Binder对象就不多说了,完全反射机制即可,我们先获取到缓存池,然后得到剪切板服务Binder对象,构造一个代理类,最后在设置回去即可。下面主要来看一下构造了代理类之后,如何拦截哪些方法?

这里一定要注意了,有的同学可能想直接在这里拦截setPrimaryClip这样的剪切板方法不就可以了吗?想想是肯定不可以的,为什么呢?因为我们现在代理的是远端服务的Binder对象,他还没有转化成本地对象呢?如何会有这些方法呢,而我们真正要拦截的方法是IClipboardManager,其实就是Proxy类,而这个对象也是Stub类的asInterface方法得到的,所以我们现在的思路是有了远端服务的代理对象,拦截肯定是拦截这个代理对象Binder的一些方法,那么这个远端服务有哪些方法会在这个过程中被调用呢?我们再看看之前的一个简单AIDL的例子:

在asInterface方法中可以看到,传递进来的就是一个远端服务IBinder对象,这里会先调用它的queryLocalInerface方法获取本进程的本地化对象,那么这个方法就是拦截的目标了。

然后在想,我们如果想拦截IClipboardManager的setPrimaryClip方法,其实就是要拦截ClipboardManager$Proxy的这些方法,那么还需要做一次代理,代理ClipboardManager$Proxy类对象

第一、ClipboardManager$Proxy类实现了AIDL接口类型,符合规则。

第二、我们可以直接使用反射获取到IClipboardManager$Stub类,然后反射调用它的asInterface方法就可以得到了IClipboardManager$Proxy对象了,符合规则。

到这里,看来这个对象也符合了代理的条件,那么就简单了,继续使用动态代理机制产生一个代理类即可:

这个代理类的InvocationHandler中,先需要通过反射获取到Proxy原始对象:

最后才开始实现拦截操作。

下面来看一个实验结果:

我们调用系统的剪切板服务,但是返回的结果却是:

看到了,这里的剪切板的内容已经被之前拦截,内容也被替换了。

上面就全部介绍了如何Hook系统的剪切板服务功能,流程如下:

1、我们的目的就是拦截系统的服务功能,那么最开始的入口就是服务大管家ServiceManager对象,而在他内部也正好有一个远端服务对象的IBinder缓存池,那么这个变量就是我们操作的对象了,可以先使用反射机制去获取到他,然后在获取到指定的剪切板服务IBinder对象实例。

2、下一步肯定是Hook这个剪切板服务的Binder对象,这里采用动态代理方式产生一个Binder对象代理类,符合两个规则:

1》这个Binder对象实现了IBinder接口类型

2》我们已经得到了原始的Binder对象实例

构造完代理类之后,我们拦截的方法是queryLocalInterface方法,为什么是这个方法呢?因为在整个服务使用过程中之后在Stub类中使用到了这个方法,很多同学会认为为什么不在这里直接拦截系统方法呢?这是一个误区,要想清楚,这里的代理对象是远程服务的Binder,还不是本地化对象,不能会有哪些系统方法的,所以得再做一次Hook,去Hook住系统的本地化对象。

3、在拦截了Binder对象的queryLocalInterface方法之后,再一次做一下本地化服务对象的代理生成操作,而这个本地化对象一般都是IClipboard$Proxy,那么动态代理的规则:

1》本地化服务对象都会实现AIDL接口类型(这里才有哪些我们想拦截的系统方法)

2》通过反射调用IClipboard$Stub类的asInterface方法得到IClipboard$Proxy类对象实例

符合这两个规则那么就可以产生代理对象了,然后开始拦截服务的指定方法即可。

上面总结的这个流程是可以完全用于其他系统服务的Hook工作的,因为系统服务的机制都是一致的,所以这个流程一定要理解清楚,后面的工作才好进行。

四、补充说明

有的同学可能会好奇询问,这个Hook系统服务貌似只对本应用有效吧?哈哈,的确是这样的,上面的拦截只会对本应用有效,那有的同学会问,只对本应用有效意义就不是很大的,其实这个要看个人需求了,后面会介绍一些开发中遇到的问题,就需要借助这个技术去解决了,但是真正能够拦截系统的服务对所有的应用有效,其实想想实现也不难,因为应用都会请求服务,而所有的服务都在system_server进程中,那么就可以采用root之后,注入system_server进程,那时候在开始Hook工作即可完成真正意义上的拦截操作,这个用途就大了,比如我们可以修改系统的经纬度信息,伪造假的当前位置信息,篡改设备的IMEI值,让有的游戏识别唯一设备无效等。但是这个就需要root了之后才可以操作了,具体方案感兴趣的同学可以去这里看看:Android中注入系统进程实现拦截

五、总结

到这里我们就介绍完了Android中Hook系统服务的流程,本文中主要介绍了Hook系统剪切板服务,拦截指定方法,其实后面还会继续介绍拦截AMS和PMS服务,实现应用启动的拦截操作,达到我们想要的效果。

更多内容:点击这里

关注微信公众号,最新技术干货实时推送

时间: 2024-08-04 03:29:41

Android系统篇之----免root实现Hook系统服务拦截方法的相关文章

Android系统篇之----编写系统服务并且将其编译到系统源码中

在之前已经介绍了一篇关于如何编写简单的驱动以及访问该驱动的小程序,最后将程序编译到Android内核源码中通过程序访问驱动验证是可以通过的,那么本文就继续这个知识点,把这个驱动程序通过JNI连接创建一个系统服务,提供给上层应用访问改服务功能,可以看到前一篇介绍驱动程序的功能是属于内核层的,而本文介绍的内容是Framework层的知识. 声明:本文内容参考罗升阳的书籍:<Android系统源代码情景分析> 如果想了解更详细的内容非常建议购买此书 非常感谢罗神的这本书,给我带来很多未知的知识,大神

Android系统篇之—-编写系统服务并且将其编译到系统源码中【转】

本文转载自:http://www.wjdiankong.cn/android%E7%B3%BB%E7%BB%9F%E7%AF%87%E4%B9%8B-%E7%BC%96%E5%86%99%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%E5%B9%B6%E4%B8%94%E5%B0%86%E5%85%B6%E7%BC%96%E8%AF%91%E5%88%B0%E7%B3%BB%E7%BB%9F%E6%BA%90%E7%A0%81/ 在之前已经介绍了一篇关于 如何编写简单的

Android系统篇之----Android中的智能指针

一.前言 今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一下:Android中的智能指针的概念,为什么说先看一下智能指针这个知识呢?因为我们在看Android源码的时候,会发现几乎好多地方都用到了这个东东,所以我们在介绍后面的知识点,先来看看这个吧. 二.问题 那么Android中的智能指针是个什么东西呢?我们知道Android用的Java语言开发的,J

Android系统篇之----Hook系统的AMS服务实现应用启动的拦截功能

技术概念来源:[ 360开源插件框架,项目地址:https://github.com/DroidPluginTeam/DroidPlugin ] 一.Hook系统剪切板服务流程回顾 在之前的一篇文章中已经介绍了 Android中的应用启动流程,这个流程一定要理解透彻,这样我们才可以进行后续的Hook操作,在之前还介绍了Android中如何Hook系统的剪切板服务实现方法的拦截效果,实现原理就是: 1.先找到Hook点,这个一般是分析源码来得到,而一般的Hook点都是静态变量或者是单例方法. 2.

Android系统篇之----解读AMS远端服务调用机制以及Activity的启动流程

一.为何本文不介绍Hook系统的AMS服务 在之前一篇文章中已经讲解了 Android中Hook系统服务,以及拦截具体方法的功能了,按照流程本文应该介绍如何Hook系统的AMS服务拦截应用的启动流程操作,但是本文并不会,因为在介绍这个知识点之前,还有一件大事要做,那就是得先分析一下Android中应用的启动流程,如果这个流程不搞清楚的话,后面没办法Hook的,因为你都找不到Hook点,当然Hook代理对象倒是很容易获得,如果没有Hook点,是没办法后续的操作的,所以得先把流程分析清楚了,当然现在

Android系统篇之----Binder机制和远程服务调用机制分析

一.前景概要 最近要实现Android中免注册Activity就可以运行的问题,那么结果是搞定了,就是可以不用在AndroidManifest.xml中声明这个Activity即可运行,主要是通过骗取系统,偷龙转凤技术的,这个知识点后面会详细讲解的,因为在研究了这个问题过程中遇到了很多知识点,当然最重要也是最根本的就是Android中的Binder机制和远程服务调用机制,而关于Binder机制的话,在Android中算是一个非常大的系统架构模块了,光这篇文章是肯定不能讲解到全部的,而且本人也不是

Android系统篇之----Android中的run-as命令引出升降权限的安全问题(Linux中的setuid和setgid)

一.前言 最近一周比较忙,没时间写东西了,今天继续开始我们今天的话题:run-as命令,在上周的开发中,遇到一个问题,就是在使用run-as命令的时候出现了一个错误,不过当时因为工作进度的问题,这问题就搁浅没有解决,用了其他一个曲线救国的方式去解决的.那么咋们今天闲来说说Android中的run-as命令吧. 二.遇到的问题&解决问题 Android中我们知道如果设备没有root,我们想看一个应用的沙盒数据(/data/data/目录内容),在以前的方式很难办到,一般人都是选择root之后,去查

Android系统篇之—-编写简单的驱动程序并且将其编译到内核源码中【转】

本文转载自:大神 通过之前的一篇文章,我们了解了 Android中的Binder机制和远程服务调用 在这篇文章中主要介绍了Android中的应用在调用一些系统服务的时候的原理,那么接下来就继续来介绍一下如何通过编译Android源码来手动添加一个系统服务,让编译之后的Android系统中存在我们的这个服务,每个应用都可以调用.但是本文得先介绍一下如何编写一个简单的驱动程序,先介绍了驱动程序,然后在通过JNI让framework层访问这个驱动程序,在通过注册服务来封装这个功能,最后在把这个服务添加

Android系统篇之----编写简单的驱动程序并且将其编译到内核源码中

通过之前的一篇文章,我们了解了 Android中的Binder机制和远程服务调用 在这篇文章中主要介绍了Android中的应用在调用一些系统服务的时候的原理,那么接下来就继续来介绍一下如何通过编译Android源码来手动添加一个系统服务,让编译之后的Android系统中存在我们的这个服务,每个应用都可以调用.但是本文得先介绍一下如何编写一个简单的驱动程序,先介绍了驱动程序,然后在通过JNI让framework层访问这个驱动程序,在通过注册服务来封装这个功能,最后在把这个服务添加到系统中,实现上层