超越系统权限—-Android黑名单电话拦截
首先要普及一下,我们的电话设计的最初始目的就是打电话,所以我们很应该能够很自然的想到,这个电话拦截的功能是不可能随意的暴露出来的(要不然有人又要想砸电话了——有个不怀好意的开发个应用,在后台默默的给你开个服务,把你的所有来电都拦截掉,这时候恐怕~~~~悲剧)。
但是我们仔细想一下,既然系统提供的拨号器中有个挂断功能,它怎么实现的?有两种方式,一种直接通过使用java代码写的暴露出来的API,另一种就是aidl,我们之前分析了,像这样关键的功能,人家是不可能让你去随意操作的,那就只有通过AIDL方式了。原理分析,我们就差不多了,下面进行实现分析:
我们回想一下Context.getSystemService(“XXX”),记得么?这条语句是干什么用的?对嘛,就是获得一个系统服务啊,那我们的拨打电话,挂断电话是不是一个系统服务呢?当然是了!并且很确定的告诉你,这个服务名称就是TELEPHONY_SERVICE,所以自然而然的TelephonyManager tm = Context.getSystemService(TELEPHONY_SERVICE) 这样的代码就出来了是不是(我们是不是经常去拿到这个服务去获取设备的各种信息啊?)?, 那就是我们也可以使用这个服务了来拦截电话了?认为可以的好好要反思一下了,一口吞不掉一个胖子,一步一步的来,好好的回去看第一段。那我们怎么办呢?我们说google工程师没有给我们暴露出挂断电话的API,但我们想一下,如果我们知道了这个API是在哪个类(首先要确信有这样的API),那我们是不就哈哈,告诉你吧,这个API在android.os.ServiceManager这个类里面的。…..,…… , …… , 10分钟过去了,还没想到怎么办?去补补JAVA基础,有了类名,我们当然可以通过反射了是不是?那么Method method = Class.forName(“android.os.ServiceManager”).getMethod(“getService”, String.class);这句代码就出来了,“getService”是什么?当然是方法名了!我们说过,这样的API是不随意暴露出来,它是通过AIDL的方式,使用IBinder来传递的(IBinder熟悉么?我们的
@Override
public IBinder onBind(Intent intent) {
return null;
}
这句代码熟悉么,再给你看看:
public class BlockService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
这个熟悉么?不熟悉的话,那就去好好的学习了。
好了言归正传。
既然它是通过IBinder传递的,那么我们执行一下ServiceManager.getService(TELEPHONY_SERVICE)不就可以得到这个对象了,看代码:
IBinder binder = (IBinder) method.invoke(null,new String[] { TELEPHONY_SERVICE });
现在这个对象得到了,我们的工作也去了一半了(什么这么半天,才去一半?<-_->我说你在看什么呢,我们不是一直都在将解原理么,你看看我们到现在写了多少行代码:
Method method = Class.forName("android.os.ServiceManager")getMethod("getService",String.class);
IBinder binder = (IBinder) method.invoke(null,new String[] { TELEPHONY_SERVICE });
讲了那么多,也就只是写了两行代码,是不是很 惊讶呀(重在原理嘛)
好了,现在我们得到了IBinder对象后,真正的aidl来了!使用aidl我们要做什么准备呢?…..当然是导入aidl文件引入接口了,第一个是ITelephony.aidl文件,但是当我们导入这个aidl文件后,是报错的,原因是这个接口需要依赖于NeighboringCellInfo.aidl,所以我们也要导入NeighboringCellInfo.aidl接口(这两个文件我会在文章后面给出)。
为了帮助没有使用过aidl服务的同学我们就在啰嗦一下怎么导入:
首先我们要在自己的项目中新建两个包,这两个包的名称是根据这两个文件package 的声明(必须一致):如图
1.
2.
3.
看到了吧ITelephony.aidl是在com.android.internal.telephony包下,NeighboringCellInfo.aidl是在android.telephony包下,一定要一致,要不然你就等着哭吧。
我们打开ITelephony.aidl文件,注意看73行:是不是有个endCall()方法啊,这个方法就是挂掉电话的方法,我们只要调用它就可以了,但是我们注意看ITelephony.aidl文件的声明28行
是不是有个{@hide},它就是让这个文件的接口不向外暴露的”罪魁祸首”,所以也才有从开头到这里的这一段,要不然就直接XXOO就把电话给挂掉了。现在有同学又有问题了,既然这个文件我们都有了,并且也说了这个接口不像外暴露是因为有{@hide}声明,那么我们为什么不直接把{@hide}给叉掉就算了,我只能告诉你,你这个方法是可以的,只是可能你需要重新编译系统的源码,然后重新刷机可能就ok了(我可没有这能耐去干这事,有兴趣你可以去试试)。老老实实的继续往下看吧:
现在这个接口有了,我们只要获取这个对象然后直接调用不就大功告成了。。。哈哈哈
怎么办呢?我们注意看下ITelephony.aidl生成的Java类:
(太长了,看不完,同同们自己去看了)是不是有个方法
public static ITelephony asInterface(IBinder obj)
,参数刚好是IBinder,而返回值是不是也刚好是ITelephony对象呢,是不是符合我们的条件了,那 我们等什么呢,赶快得到它把:
ITelephony itelepony = ITelephony.Stub.asInterface(binder);
哎,绕了半天终于得到它了,接下来的事情交给你们了!!!
现在附上所有的关键代码:
Method method = Class.forName("android.os.ServiceManager")
.getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null,new String[] { TELEPHONY_SERVICE });
ITelephony itelepony = ITelephony.Stub.asInterface(binder);
itelepony.endCall();
在啰嗦两句吧,市面上的app的黑名单拦截功能核心代码就这3行,但是拦截掉之后,在通话记录里还是有记录的,所以接下来的工作就是删除这个通话记录了。大功告成!那么多的文字最后被这4行代码给秒杀了,是不是觉得我吃饱了没事干,如果你是大神,小弟我面壁思过,如果你和我一样是个小罗罗,那我只能呵呵了。
最后留下那两个小宝宝:
http://download.youkuaiyun.com/detail/linyimu000/8953563