概述
Xposed是Android上的一个Hook框架,通过替换app_process来使得所有App进程在启动时就已经加载了Hook模块。从而达到在不侵入App程序的情况下,修改App的程序行为。这对App的完整性是有破坏的,如某些App需要统计其安装信息(如安装的设备数),通过Xposed就可以修改设备参数,进行设备伪装,从而干扰App的统计功能。
阅读Xposed的代码可以知道,Xposed框架hook程序的java函数的实现是将需要hook的java函数设置为函数,再申请一个内存空间用于保存该java函数的原来的信息,并把该空间的地址保存到该函数的java指令指针里。其核心代码如下:
|
|
从以上代码可以看出xposed的hook主要是把method的flag置为NATIVE标志,并且对nativeFunc指针进行了赋值(其用于实现函数劫持)。关键的地方还在与其把method的原有信息拷贝之后,将保存地址赋值给了insns。
检测方法
1. 简易的检测方法
了解xposed的实现过程之后,我们知道xposed框架要Hook一个函数,最先改变的就是这个函数的属性,由java函数变为了native函数。所以我们在判断一个函数是否被xposed框架hook的第一步就是判断其是否本应是一个java函数的函数被置为了native函数。
例如判断TelephonyManager.getDeviceId()是否被Hook,该函数常常被hook,来达到欺骗App的目的。
|
|
上面的代码,通过判断java函数的属性是否被改为了native来判断函数被hook与否。
2. 更进一步的检测方式
由于客户机的环境各不相同,常常会出现各种各样的异常情况。所以仅仅判断java函数的属性是native属性就认为函数被hook也许过于草率。所以为了进一步验证函数是否被xposed所hook,我们可以在jni层做更多的判断。
从Xposed的实现过程看,其把原有的method结构体进行了拷贝保存,而把现有的结构体进行了一定的修改。而在jni层我们只要取得保存结构的内存空间,并把其与现有的结构进行对比,如果除去修改过的值之外,其余的值都一样,就可以判断其经过了xposed的处理。代码可以写为
|
|
3. 恢复被xposed修改的函数
由于已经确定函数被xposed修改,并且已经找到了保存原有method变量的内存空间,那么如果要恢复xposed的修改,只要把method变量进行还原就可以
由于客户机器情况较为复杂,如果xposed的检测出错,只会发生误报的情况。而如果恢复出错,则会导致程序僵死。
其中恢复出错的情况,可能有xposed版本升级之后,代码实现发生改变,或者有开发者在xposed的基础上做了自己的修改,甚至还有手机厂商修改了底层变量的定义等情况。
所以在没有更加复杂细致的验证之前不能将xposed的恢复方法用于产品中。能够想到的方法是,启动一个专门的独立的App进程,进行恢复尝试。
考虑到开发的高效性以及系统效率和稳定,第一种简易的检测方式已经可以定位到大部分的异常情况,该方法可以在初版本中进行使用来作比较初级的检测。而更复杂的检测机制,则可以更加有针对性的识别主流的xposed框架的hook行为。