高版本Android如何利用反射调用系统隐藏的远程服务拦截来电

要说拦截Android系统来电,就不得不说起在低版本的时候Android提供给开发者使用的一个方法:endCall(),但由于谷歌后来考虑到对于一部手机来说,最重要的功能就是打电话了,如果这个功能随随便便就被人屏蔽了,安全性太差,所以在高版本的Android将这个方法屏蔽了,不再在TelephoneManager中暴露这个方法。

那么我们下面的目标就是要想办法调用到这个方法,当然首先我们还是需要实现一个广播接收者,来接收电话状态改变的广播,这里使用在服务中动态注册广播接收者的方法来实现,主要好处在于便于控制广播接收者的生命周期,同时也能比静态注册有更高的权限

private static final String PHONE = "PHONE";
	private static final String BOTH = "BOTH";
	private static final String SMS = "SMS";
	private TelephonyManager tm;
	private BlacklistDao dao;
	private inCommingCallReceiver callReceiver;
	private PhoneStateListener listener;
@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		dao = new BlacklistDao(this, 1);

		callReceiver = new inCommingCallReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction("android.intent.action.PHONE_STATE");
		filter.addAction("android.provider.Telephony.SMS_RECEIVED");
		filter.setPriority(Integer.MAX_VALUE);
		listener = new PhoneStateListener() {

			private BlacklistItem blacklistItem;

			@Override
			public void onCallStateChanged(int state, String incomingNumber) {
				super.onCallStateChanged(state, incomingNumber);
				switch (state) {
				case TelephonyManager.CALL_STATE_RINGING:// 如果是来电的时候
					blacklistItem = dao.queryItem(incomingNumber);

					if (blacklistItem != null) {
						String type = blacklistItem.getType();
						if ((BOTH.equals(type) || PHONE.equals(type))) {
							System.out.println("挂断电话");
							<strong>hangUpCallFromBlacklist(incomingNumber);//挂断电话的方法
						}
					}

					break;

				default:
					break;
				}

			}

		};
		registerReceiver(callReceiver, filter);// 注册广播接收者
	}

在服务的onDestroy()方法中取消注册广播接收者:

@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("关闭黑名单服务");
		unregisterReceiver(callReceiver);
		// 取消监听
		tm.listen(listener, PhoneStateListener.LISTEN_NONE);
		// listener = null;
	}

内部类广播接收者,用于接收电话状态改变的广播:

/**
	 * 监听来电
	 *
	 * @author Alex
	 *
	 */
	private class inCommingCallReceiver extends BroadcastReceiver {

		private BlacklistItem blacklistItem;

		@Override
		public void onReceive(Context context, Intent intent) {
			if ("android.intent.action.PHONE_STATE".equals(intent
					.getAction())) {
				// 如果收到的是电话状态的变化
				tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
			}
		}
	}

下面我们重点来看hangUpCallFromBlacklist(incomingNumber);这个实现挂断来电的方法,其中incomingNumber是来电的电话号码。

按照我的惯例,还是从安卓系统的源码入手,由于endCall方法原来是在TelephoneManager中的,所以我们不妨从TelephoneManager的实例化方法getSystemService入手:

我们可以发现这个方法是定义在ContextWrapper中的,而ContextWrapper又是继承自Context,我们不妨进入到Context的源码中去一探究竟:

在Context中,我们只找到了一个getSystemService的抽象方法,那么如何去找实现方法呢,在java中,抽象类的实现类一般名字都是在抽象类名后面加上一个"Impl",于是我们去搜索源码中的ContextImpl.java,找到之后打开发现:

我们发现getSystemService实际上返回了一个ServiceFetcher对象的一个getService方法的结果,我们来看看ServiceFetcher的getService方法:

在这里我们可以看到,在定义了一个static块中,注册了很多不同的service服务,而这些gerService方法都是由ServiceManager来调用的,返回值是一个IBinder对象。接下来我们可以在文件的导入包的部分找到ServiceManager的位置是在android/os下的:

由于getService返回的是一个IBinder对象,我们只要找到这个getService方法的实现,就可以传入TELEPONY_SERVICE从而拿到真正的TelephonyManager所代理的那个远程服务绑定对象,从而调用隐藏在其中的endCall方法。

幸运的是,在ServiceMnager.java中,我们找到了getService方法的实现:

我们可以发现,ServiceManager这个类也是一个隐藏类,我们无法在我们的代码中直接拿到这个类来调用其中的getService方法来获取IBinder对象,那么我们要如何做呢?

这里就只有使用反射的方法来处理:

Class clazz = CallSmsSafeService.class.getClassLoader().loadClass(
					"android.os.ServiceManager");
		Method method = clazz.getMethod("getService", String.class);
		IBinder binder = (IBinder) method.invoke(null, TELEPHONY_SERVICE);

通过上面的反射做法,我们拿到了对应于TelephonyManager的IBinder对象,下面我们需要做的利用aidl来调用远程方法,既然是使用的TelephonyManager的IBinder对象,我们再进入到TelephonyManager的源码中去看看:

我们发现,在TelephonyManager中,类似于getCallState()这类的方法基本都返回的是getITelephony()的返回值调用的方法,那么这个getITelephy()是什么呢:

我们发现,返回的实际上是一个ITelephony对象,而且是以一种调用远程服务方法的形式返回的;

我们在文件的头部找到ITelephony的位置:

打开上面的目录,我们发现ITelephony是一个aidl文件,进入其中,我们可以找到endCall方法:

由于在ITelephony.aidl的头部有如下信息:

我们想要通过aidl来调用远程服务telephony的方法endCall(),我们需要将Telehpony.aidl拷贝到我们工程中新建的com.android.internal.telephony包中,同时将android.telephony.NeighboringCellInfo.aidl文件拷贝到工程中新建的android.telephony包中,这样在gen目中下就会自动生成一个对应的ITelephony.java文件。至此,我们就可以使用下面的语句来调用远程服务的endCall方法:

ITelephony.Stub.asInterface(binder).endCall();

最后,不要忘记在清单文件中加入对应的权限:

<!-- 授予该应用控制通话的权限 -->
    <uses-permission android:name="android.permission.CALL_PHONE">
    <!-- 授予该应用读取通话状态的权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE">
时间: 2024-12-29 11:22:18

高版本Android如何利用反射调用系统隐藏的远程服务拦截来电的相关文章

利用反射调用注解

利用反射调用注解 package net.jeesite.java; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; @Retention(value = RetentionPolicy.RUNTIME) @interface Meta { String length(); String name(); int

反射学习(三)--------利用反射调用方法

利用反射调用方法 C1 newC1Instance = new C1(); var funM = newC1Instance.GetType().GetMethod("fun", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); object[] para = { }; if (funM == null) { Console.Write("error, fu

如何调用系统隐藏的API,或者使用系统未开放的类

一.反射 可以通过反射来调用系统隐藏的API, 但对于已经被系统隐藏的类似乎不太行得通. 二.使用系统源码编译后的classes.jar 路径:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates 将此jar包添加到项目中后,在使用系统相关类或者隐藏的API时,就不会出现错误标识的小红点提示. 需要注意的是: 1,在manifest中标识:android:sharedUserId="android.uid.system"

【Android】使用Intent调用系统其它程序,使用onKeyDown对音量键的监听,长按事件

Intent在安卓编程中非常常见,在<[Android]多个Activity之间利用bundle传递数值>(点击打开链接)中已经展示了它可以唤醒其它Activity并在Activity之间传递数据.其实Intent的作用远非于此,它还可以调用系统中其它固有程序,比如拨打电话.发送短信等.onKeyDown也是如此,不仅仅可以对设备的菜单键进行监听,这在<[Android]各式各样的弹出框与对菜单键.返回键的监听>(点击打开链接)中已经展示过的,对设备的音量调节键也是可以监听的, 下

Android图片裁剪功能——调用系统裁剪

花了两天时间看了下android的图片裁剪功能的实现.其实刚开始做这个我挺虚的,以为整个功能都需要自己写出来,但查了些资料,发现android已经提供了裁剪功能,需要的话自己调用就成了.soga,这下轻松多了. 首先推荐几篇博客 Android大图片裁剪终极解决方案 要想弄明白裁剪功能,这系列博客非常重要,你可以不看我下面总结的,但你一定要看他这系列的几篇文章. Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪) 这篇也不错,比较喜欢他的注释.虽然也有些误导,比如说他有一段对setD

Java反射(三)利用反射调用方法

有Student类: package testreflection; public class Student{ private static int count; private String stuNum; public Student(String stuNum) { // TODO Auto-generated constructor stub this.stuNum = stuNum; count++; } public String getStuNum() { return stuN

C#控制台 activator与invoke,利用反射调用一个类的无参数方法

1 code 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ConsoleApplication1 9 { 10 class Program 11 { 12 static void Main(string[] a

C#控制台 activator与invoke,利用反射调用一个类的有参数方法

1 code 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ConsoleApplication1 9 { 10 class Program 11 { 12 static void Main(string[] a

Android连接wifi,调用系统API【转】

本文转载自:http://blog.csdn.net/aaa1050070637/article/details/54136472 直接上代码,简单粗暴,一看就懂 [java] view plain copy import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; impor