Android中經過進程注入技術修改廣播接收器的優先級 分類: Android 2014-12-23 10:02 1048人閱讀 評論(0) 收藏

前言

這個週末又沒有吊事,在家研究瞭如何經過進程的注入技術修改廣播接收器的優先級,關於這個應用場景是不少的,並且也很重要,因此就很急的去fixed了。html

Android中的四大組件中有一個廣播:Broadcastjava

關於它的相關知識能夠轉戰:http://blog.csdn.net/jiangwei0910410003/article/details/19150705android

咱們這裏就不作太多解釋了,如今來看一下問題:shell


知識前提

這篇文章和我以前介紹一篇文章: Andrdoid中對應用程序的行爲攔截實現方式之----從Java層進行攔截api

內容和知識點很是類似,若是想看明白這篇文章的話,那麼必須先看懂上面的一篇文章,不然很難理解的。安全


知識點

一、進程注入技術app

二、獲取系統中全部應用的IntentFilteride


問題

1、讓咱們本身定義的廣播接收器的最早接收到系統發送的安裝應用的廣播

如今不少安全應用都會註冊這個廣播(360手機衛士、清理大師等),廣播中能夠設置優先級的。同時動態註冊的廣播的優先級比靜態註冊的廣播的優先級高。測試

經過上面的知識咱們能夠這麼作:spa

一、將本身的廣播接收器註冊的優先級設置最高,通常是用最大值:Integer.MAX_VALUE

二、進行動態註冊廣播(那麼咱們可能須要開啓一個後臺服務了,否則應用退出以後,這個接收器就沒有了,是接收不到廣播的)

經過上面的兩步咱們能夠發現,咱們本身的廣播接收器的優先級應該比較高了。可以最早接收到廣播了。


問題來了,你的應用這麼作,那麼其餘應用也會這麼作的,並且這種作法的成本和代價不是很高。很容易實現的。

好吧。那麼咱們如今該怎麼辦呢?

這時候咱們就須要經過Android中的進程注入技術來進行攔截操做,而後去修改其餘應用的廣播接收器的優先級了

下面來看一下具體實現:

首先關於進程的注入技術這裏就不作介紹了,若是有疑問的同窗能夠轉戰:

http://blog.csdn.net/jiangwei0910410003/article/details/40949475

注:還有一個問題,我今天介紹的內容其實和這篇文章很是類似,功能差很少。因此強烈建議你們最好認真的把這篇文章從頭至尾仔細的讀一遍,同時最後動手去實現如下,那麼在來看這篇文章就簡單多了。否則是很費勁的。


這裏咱們須要注入到系統進程:system_server

而後在Java層自定義一個Binder對象,在經過底層去替換系統的Binder。而後咱們須要作的工做就是在Java中的自定義的這個Binder對象的onTransact方法中進行操做


很少說了,先來看代碼:

DemoInject3項目:

EntryClass.java

package com.demo.inject3;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

/**
 * 
 * @author boyliang
 * 
 */
public final class EntryClass {

	private static final class ProxyActivityManagerServcie extends Binder {
		private static final String CLASS_NAME = "android.app.IActivityManager";
		private static final int s_broadcastIntent_code;

		private SmsReceiverResorter mResorter;

		static {
			if (ReflecterHelper.setClass(CLASS_NAME)) {
				s_broadcastIntent_code = ReflecterHelper.getStaticIntValue("BROADCAST_INTENT_TRANSACTION", -1);
			} else {
				s_broadcastIntent_code = -1;
			}
		}

		private IBinder mBinder;

		public ProxyActivityManagerServcie(IBinder binder) {
			Logger.init();
			mBinder = binder;
			mResorter = new SmsReceiverResorter(binder);
		}

		@Override
		protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

			if (code == s_broadcastIntent_code) {
				Log.i("TTT", "broadcastintent:"+s_broadcastIntent_code);
				mResorter.updatePriority("com.demo.sms");
			}

			return mBinder.transact(code, data, reply, flags);
		}
	}

	public static Object[] invoke(int i) {
		IBinder activity_proxy = null;

		try {
			activity_proxy = new ProxyActivityManagerServcie(ServiceManager.getService("activity"));

			Log.i("TTT", ">>>>>>>>>>>>>I am in, I am a bad boy 3!!!!<<<<<<<<<<<<<<");
		} catch (Exception e) {
			e.printStackTrace();
		}

		return new Object[] { "activity", activity_proxy };
	}
}

核心的方法是onTransact:

這裏須要判斷一下code值,咱們只對廣播的code作操做。關於這個code的值,在上面的提到的那篇文章中有詳細介紹。

看到調用了mResorter.updatePriority方法。那麼咱們在來看一下mResorter變量的類型

SmsReceiverResorter.java

package com.demo.inject3;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;

final class SmsReceiverResorter {

	private static final String key = Intent.ACTION_PACKAGE_ADDED;
	
	private final String TAG = "TTT";
	private HashMap<String, IntentFilter[]> mActionToFilter;
	private Field mPackageNameField;

	@SuppressWarnings("unchecked")
	public SmsReceiverResorter(IBinder am) {
		Class<?> claxx = am.getClass();
		try {
			Field field = claxx.getDeclaredField("mReceiverResolver");
			field.setAccessible(true);
			Object mReceiverResolver = field.get(am);
			Log.i("TTT", "Binder:"+mReceiverResolver.getClass().getName());

			claxx = mReceiverResolver.getClass();
			
			field = claxx.getSuperclass().getDeclaredField("mActionToFilter");
			field.setAccessible(true);

			mActionToFilter = (HashMap<String, IntentFilter[]>) field.get(mReceiverResolver);
			Log.i("TTT", "mActionToFilter:"+mActionToFilter);
			
			if(mActionToFilter == null){
				return;
			}
			
			Log.i("TTT", "size:"+mActionToFilter.size());
			
			Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key));
			
			IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);
			Log.i("TTT", "filters:"+filters_tmp);
			
			if (filters_tmp != null) {
				Log.i("TTT", "length:"+filters_tmp.length);
				for (int i=0;i<filters_tmp.length;i++) {
					String pkg = getPackageName(filters_tmp[i]);
					Log.i("TTT", "pkg:"+pkg);
				}
			}
			
			Set<Entry<String, IntentFilter[]>> sets = mActionToFilter.entrySet();
			Iterator<Entry<String, IntentFilter[]>> iterators = sets.iterator();
			while(iterators.hasNext()){
				Log.i("TTT", "key:"+iterators.next().getKey());
			}
			
			
		} catch (Exception e) {
			Log.e(TAG, e.toString());
		}
	}

	public void updatePriority(String target_pkg) {
		
		if (mActionToFilter != null) {
				IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);

				Log.i("TTT", "filters:"+filters_tmp);
				
				if (filters_tmp != null) {
					
					Log.i("TTT", "add package...");
					
					IntentFilter[] newFilters = new IntentFilter[1];

					for (int i=0;i<filters_tmp.length;i++) {
						String pkg = getPackageName(filters_tmp[i]);
						Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority());
						//現將全部的應用的廣播接收器的優先級設置最低
						filters_tmp[i].setPriority(Integer.MIN_VALUE);
						if(pkg == null){
							continue;
						}
						if (target_pkg.equals(pkg)) {
							Log.i("TTT", "find pkg:"+pkg);
							//把咱們本身的廣播接收器的優先級設置最高
							filters_tmp[i].setPriority(Integer.MAX_VALUE);
							//newFilters[0] = filters_tmp[i];
							break;
						}
					}
					
					/*mActionToFilter.put(key, newFilters);
					
					IntentFilter[] filterss = mActionToFilter.get(key);
					for(int i=0;i<filterss.length;i++){
						Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i]));
					}*/
					
				}
			}

	}

	private String getPackageName(IntentFilter filter) {
		
		if (mPackageNameField == null && filter != null) {
			Class<?> claxx = filter.getClass();
			try {
				mPackageNameField = claxx.getDeclaredField("packageName");
				mPackageNameField.setAccessible(true);
			} catch (Exception e) {
				Log.e(TAG, e.toString());
			}
		}
		
		String result = null;

		if (filter != null) {
			try {
				result = (String) mPackageNameField.get(filter);
			} catch (Exception e) {
				Log.e(TAG, e.toString());
			}
		}
		
		return result;
	}
}

這裏面有兩個重要的方法:

一、構造方法

public SmsReceiverResorter(IBinder am) {
		Class<?> claxx = am.getClass();
		try {
			Field field = claxx.getDeclaredField("mReceiverResolver");
			field.setAccessible(true);
			Object mReceiverResolver = field.get(am);
			Log.i("TTT", "Binder:"+mReceiverResolver.getClass().getName());

			claxx = mReceiverResolver.getClass();
			
			field = claxx.getSuperclass().getDeclaredField("mActionToFilter");
			field.setAccessible(true);

			mActionToFilter = (HashMap<String, IntentFilter[]>) field.get(mReceiverResolver);
			Log.i("TTT", "mActionToFilter:"+mActionToFilter);
			
			if(mActionToFilter == null){
				return;
			}
			
			Log.i("TTT", "size:"+mActionToFilter.size());
			
			Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key));
			
			IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);
			Log.i("TTT", "filters:"+filters_tmp);
			
			if (filters_tmp != null) {
				Log.i("TTT", "length:"+filters_tmp.length);
				for (int i=0;i<filters_tmp.length;i++) {
					String pkg = getPackageName(filters_tmp[i]);
					Log.i("TTT", "pkg:"+pkg);
				}
			}
			
			Set<Entry<String, IntentFilter[]>> sets = mActionToFilter.entrySet();
			Iterator<Entry<String, IntentFilter[]>> iterators = sets.iterator();
			while(iterators.hasNext()){
				Log.i("TTT", "key:"+iterators.next().getKey());
			}
			
			
		} catch (Exception e) {
			Log.e(TAG, e.toString());
		}
	}

在構造方法中咱們主要作的工做是獲取mActionToFilter的值,它的定義:

private HashMap<String, IntentFilter[]> mActionToFilter;
這個值是幹什麼的呢?它是全部應用的IntentFilter的值,關於IntentFilter的做用能夠自行百度,這裏就不解釋了。

這裏的key是action的名稱。由於咱們在動態註冊廣播的時候,須要傳遞IntentFilter的。

因此,咱們拿到這個值以後,就能夠獲取全部應用註冊廣播的信息了

這個變量是非公開的,咱們沒法經過api去獲取。那麼不用說用反射去搞定它:

這個變量的定義是在  Android源碼目錄\services\java\com\android\server\IntentResolver.java  

   /**
     * All filters that have been registered.
     */
    private final HashSet<F> mFilters = new HashSet<F>();

    /**
     * All of the MIME types that have been registered, such as "image/jpeg",
     * "image/*", or "{@literal *}/*".
     */
    private final ArrayMap<String, F[]> mTypeToFilter = new ArrayMap<String, F[]>();

    /**
     * The base names of all of all fully qualified MIME types that have been
     * registered, such as "image" or "*".  Wild card MIME types such as
     * "image/*" will not be here.
     */
    private final ArrayMap<String, F[]> mBaseTypeToFilter = new ArrayMap<String, F[]>();

    /**
     * The base names of all of the MIME types with a sub-type wildcard that
     * have been registered.  For example, a filter with "image/*" will be
     * included here as "image" but one with "image/jpeg" will not be
     * included here.  This also includes the "*" for the "{@literal *}/*"
     * MIME type.
     */
    private final ArrayMap<String, F[]> mWildTypeToFilter = new ArrayMap<String, F[]>();

    /**
     * All of the URI schemes (such as http) that have been registered.
     */
    private final ArrayMap<String, F[]> mSchemeToFilter = new ArrayMap<String, F[]>();

    /**
     * All of the actions that have been registered, but only those that did
     * not specify data.
     */
    private final ArrayMap<String, F[]> mActionToFilter = new ArrayMap<String, F[]>();

    /**
     * All of the actions that have been registered and specified a MIME type.
     */
    private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>();
那麼 IntentResolver這個類的對象咱們能夠從哪裏獲取呢?

Android源碼目錄\services\java\com\android\server\am\ActivityManagerService.java 中定義:

 /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
            = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
        @Override
        protected boolean allowFilterResult(
                BroadcastFilter filter, List<BroadcastFilter> dest) {
            IBinder target = filter.receiverList.receiver.asBinder();
            for (int i=dest.size()-1; i>=0; i--) {
                if (dest.get(i).receiverList.receiver.asBinder() == target) {
                    return false;
                }
            }
            return true;
        }

        @Override
        protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) {
            if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL
                    || userId == filter.owningUserId) {
                return super.newResult(filter, match, userId);
            }
            return null;
        }

        @Override
        protected BroadcastFilter[] newArray(int size) {
            return new BroadcastFilter[size];
        }

        @Override
        protected boolean isPackageForFilter(String packageName, BroadcastFilter filter) {
            return packageName.equals(filter.packageName);
        }
    };

關於這個ActivityManagerService的對象,咱們該怎麼獲取呢?咱們知道它是一個系統的Service,還有系統的Service都是一個IBinder對象的。

ServiceManager.getService("activity")
這種方式就能夠獲取到ActivityManagerService對象了。

具體代碼在回去看一下EntryClass.java中初始化SmsReceiverResorter的部份內容。


好了,找到了它,下面的工做就是用反射去獲取了,工做就簡單了,這裏就很少說了。


還有一個重要的方法

二、修改優先級的方法:updatePriority

public void updatePriority(String target_pkg) {
		
		if (mActionToFilter != null) {
				IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);

				Log.i("TTT", "filters:"+filters_tmp);
				
				if (filters_tmp != null) {
					
					Log.i("TTT", "add package...");
					
					IntentFilter[] newFilters = new IntentFilter[1];

					for (int i=0;i<filters_tmp.length;i++) {
						String pkg = getPackageName(filters_tmp[i]);
						Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority());
						//現將全部的應用的廣播接收器的優先級設置最低
						filters_tmp[i].setPriority(Integer.MIN_VALUE);
						if(pkg == null){
							continue;
						}
						if (target_pkg.equals(pkg)) {
							Log.i("TTT", "find pkg:"+pkg);
							//把咱們本身的廣播接收器的優先級設置最高
							filters_tmp[i].setPriority(Integer.MAX_VALUE);
							//newFilters[0] = filters_tmp[i];
							break;
						}
					}
					
					/*mActionToFilter.put(key, newFilters);
					
					IntentFilter[] filterss = mActionToFilter.get(key);
					for(int i=0;i<filterss.length;i++){
						Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i]));
					}*/
					
				}
			}

	}
在這個方法中,傳遞進來一個包名(com.demo.sms),這個包名其實就是咱們想將其優先級設置最高的一個應用。

咱們首先經過key去獲取對應的IntentFilter[]對象

IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);
這裏的key是:

private static final String key = Intent.ACTION_PACKAGE_ADDED;
就是安裝應用的對應的系統action名

那麼咱們就獲取到了系統中全部註冊了安裝應用的廣播的應用了。

這裏咱們再次使用反射從IntentFilter對象中拿到包名,這樣咱們就能夠進行過濾了。

for (int i=0;i<filters_tmp.length;i++) {
	String pkg = getPackageName(filters_tmp[i]);
	Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority());
	//現將全部的應用的廣播接收器的優先級設置最低
	filters_tmp[i].setPriority(Integer.MIN_VALUE);
	if(pkg == null){
		continue;
	}
	if (target_pkg.equals(pkg)) {
		Log.i("TTT", "find pkg:"+pkg);
		//把咱們本身的廣播接收器的優先級設置最高
		filters_tmp[i].setPriority(Integer.MAX_VALUE);
		//newFilters[0] = filters_tmp[i];
		break;
	}
}
而後就開始遍歷IntentFilter[]對象,首先將其說有的應用的廣播接收器的優先級設置最低,直接調用IntentFilter的setPriority方法

而後發現若是當前的包名和咱們須要設置優先級的包名同樣,就將其優先級設置最高。


好了,上面的代碼看完了。


下面來看一下咱們自定義的兩個廣播來進行測試:

第一個測試項目:com.demo.sms

咱們看了上面的代碼以後,會發現,這個項目就是咱們須要修改最高優先級的應用

一、廣播接收器:

package com.demo.sms;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public final class SmsReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(final Context context, Intent intent) {
		Log.i("TTT", "com.demo.sms:"+intent.getAction());
	}
}
打印一下action的值


二、後臺用於動態註冊廣播的service

package com.demo.sms;

import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;

public final class MyService extends Service {

	@Override
	public void onCreate() {
		super.onCreate();
		IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
		filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
		filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
		filter.addDataScheme("package");
		filter.setPriority(Integer.MIN_VALUE);
		registerReceiver(new SmsReceiver(), filter);
		filter = null;
	}
	
	@Override
	public IBinder onBind(Intent paramIntent) {
		return null;
	}

}
而後就開啓這個service就能夠了。這裏咱們將它的優先級設置最低


第二個測試項目:com.demo.smstrojan

這個項目的代碼和上面的一個測試項目代碼如出一轍,就是對應的包名不同以及註冊廣播的優先級不同。這裏就不作解釋了。

package com.demo.smstrojan;

import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;

public final class MyService extends Service {

	@Override
	public void onCreate() {
		super.onCreate();
		
		IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
		filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
		filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
		filter.addDataScheme("package");
		filter.setPriority(Integer.MAX_VALUE);
		registerReceiver(new SmsReceiver(), filter);
	}
	
	@Override
	public IBinder onBind(Intent paramIntent) {
		return null;
	}

}
這裏咱們將它的優先級設置最高

好了,咱們如今首先運行這兩個測試項目。後臺的Service也起來了

在來運行一下上面的DemoInject3,

這個應用是不會運行有界面的,他只是一個插件apk.

咱們運行以後,獲取DemoInject3.apk文件。


下面就開始進行注入了。

這裏我不作演示了,操做步驟和:http://blog.csdn.net/jiangwei0910410003/article/details/40949475  這篇文章如出一轍。


下面來看一下運行結果:

這裏其實還須要兩個文件:libproxybinder.so和poison

這兩個文件從上面提到的那篇文章中能夠找到的


開啓一個終端來查看一下系統進程的pid:

=>adb shell

=>ps |grep system_server



在開啓一個終端進行注入:

=>adb shell

=>su

=> cd /data/data/

=>./poison /data/data/libproxybinder.so 579



在開啓一個終端來打印log值,由於這個log值有點多:因此咱們將log輸出到一個文件中:

=>adb logcat -s TTT >log.txt

這裏須要等待一會,而後咱們退出這個命令(Ctrl+C),查看log.txt文件

=>start log.txt


這裏的log.txt文件有點大,這裏直截取一部份內容:

咱們看到了打印的key值了。可是這裏發現一個問題

isHave:false

這個值是在SmsReceiverResorter.java的構造方法中打印的:

Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key));
這裏的key是: android.intent.action.PACKAGE_ADDED,安裝應用的系統action名

那麼問題就來了,咱們在兩個測試項目中都進行註冊了這個action,爲何這裏獲取到的mActionToFilter中的key沒有這個action呢?

這個糾結了我一天,最後才發現問題所在的。

咱們在測試項目中註冊廣播是:

IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
filter.setPriority(Integer.MIN_VALUE);
registerReceiver(new SmsReceiver(), filter);
發現有一個地方:就是IntentFilter中不只添加了action值,還有一個 scheme的值,好吧,問題還得去看源代碼:

仍是在IntentResolver.java

咱們看到還有一個變量:mSchemeToFilter,用來存儲scheme的IntentFilter的值。

那麼繼續來看一下IntentResolver類中的addFilter方法



發現到問題了:

這裏有兩個判斷:

首先將IntentFilter添加到mSchemeToFilter變量中

而後判斷IntentFilter中有沒有scheme和mime,沒有的話就將IntentFilter添加到mActionToFilter變量中

好吧,到這裏咱們就找到問題了,由於咱們如今有scheme字段的,值是:package

那麼咱們註冊的IntentFilter就不會再mActionToFilter中,而是在mSchemeToFilter中。


問題找到了,下面我就開始修改DemoInject項目中的SmsReceiverResorter.java代碼:

1)首先修改一下反射的字段

將下面代碼:

field = claxx.getSuperclass().getDeclaredField("mActionToFilter");
改爲:

field = claxx.getSuperclass().getDeclaredField("mSchemeToFilter");


2)在修改一下key值

將下面代碼:

private static final String key = Intent.ACTION_PACKAGE_ADDED;
改爲:

private static final String key = "package";
由於咱們註冊的時候都是用的是這個值: package


咱們再次運行DemoInject項目,獲得DemoInject3.apk

而後再次進行操做(和上面的操做同樣):

不過這裏有一個問題,就是system_server進程只能注入一次,因此若是在次進行注入操做的話,須要從新啓動設備了

等到設備重啓以後,還要記得分別運行上面兩個測試項目,而後咱們隨便安裝一個應用,用於測試廣播接收的

這時候咱們在來看一下log.txt


這時候看到了isHave是true了



這時候,咱們發現,com.demo.sms項目的優先級最高,其餘的應用的優先級都是最低的。咱們還發現

com.demo.sms比com.demo.smstrojan先獲取廣播

咱們看到上面的兩個測試項目的代碼:

com.demo.sms項目中的廣播優先級設置最低

com.demo.smstrojan項目的廣播優先級設置最高

因此正常狀況下,應該是com.demo.smstrojan項目最早接收到廣播的。

可是如今咱們修改了優先級以後,com.demo.sms項目最早接收到廣播

到這裏咱們的問題解決了,能夠將咱們本身特定的應用的廣播接收的優先級設置最高,讓其最早接收到廣播。


2、如今想特定的應用最早接收到廣播以後,就不讓其餘應用在接收到這個廣播了

可是問題尚未結束,如今還有這種需求,若是咱們如今想讓一個應用最早接收到廣播,以後就不讓後續的應用接收到這個廣播了,有人說能夠在這個特定的應用中終止這個廣播,那個只是對於有序廣播來講的,如今若是是無序廣播呢?咱們該怎麼操做呢?

其實看懂了SmsReceiverResorter.java中的updatePriority方法,咱們這裏就容易修改了。

原理:咱們能夠將其餘應用的IntentFilter刪除,只保留須要修改優先級的應用的IntentFilter便可

實現:那麼能夠重新定義一個IntentFilter[]對象,而後將咱們須要設置最早接收到廣播的那個應用的IntentFilter添加進去,而後在put進map中

具體修改以下:

updatePriority方法:

public void updatePriority(String target_pkg) {
	
	if (mActionToFilter != null) {
			IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);

			Log.i("TTT", "filters:"+filters_tmp);
			
			if (filters_tmp != null) {
				
				Log.i("TTT", "add package...");
				
				IntentFilter[] newFilters = new IntentFilter[1];

				for (int i=0;i<filters_tmp.length;i++) {
					String pkg = getPackageName(filters_tmp[i]);
					Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority());
					if(pkg == null){
						continue;
					}
					if (target_pkg.equals(pkg)) {
						Log.i("TTT", "find pkg:"+pkg);
						newFilters[0] = filters_tmp[i];
						break;
					}
				}
				
				//重新覆蓋IntentFilter[]
				mActionToFilter.put(key, newFilters);
				
				IntentFilter[] filterss = mActionToFilter.get(key);
				for(int i=0;i<filterss.length;i++){
					Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i]));
				}
				
			}
		}

}

核心代碼:

mActionToFilter.put(key, newFilters);
將咱們新的IntentFilter[]對象去覆蓋mActionToFilter中的指定key的對象。


其餘地方不須要修改,再次運行

查看log.txt


這裏看到了,咱們上面代碼打印新的IntentFilter[]

如今只有一個

new_pkg:com.demo.sms

並且,咱們在安裝一個apk包,發現只有com.demo.sms可以接收到廣播了

而com.demo.smstrojan已經接收不到廣播了

同時咱們會發現之前很牛逼的360衛士如今也接收不到廣播了,哈哈~~

咱們沒有操做前360衛士能夠接收到這個安裝廣播:



咱們操做以後,哈哈~~,沒有攔截到,由於這個廣播被咱們手動的給幹掉了

通知欄中沒有通知了。


好吧,到這裏咱們算是完全的作到了廣播接收的獨裁專政了,如今是能夠設置特定的應用能接收到廣播,並且無論這個廣播是有序的仍是無序的,咱們均可以將其靜止,不讓其餘應用接收到。

說實話,這個問題解決了,真的好開心好開心,特別是發現360如今也接收不到這個廣播了。內心特別爽。哈哈~~


項目下載

DemoInject項目下載

DemoSms項目(com.demo.sms)下載

DemoSms1項目(com.demo.smstrojan)下載


總結

關於這篇文章的研究意義在於咱們能夠控制特定的應用的廣播接收器的優先級了,如今市面上有不少應用都會接收系統發送的一些廣播,那麼每一個應用可能都會將本身的廣播接收器的優先級設置最高,讓自家的接收器最早接收到廣播。那麼主動權就可控了,可是那些常規的方法貌似如今每一個應用都在用,因此若是想作到最牛逼的,那麼只能用很是規的方法了,那麼這些很是規的方法也是須要必定代價的:設備必須root了。同時這麼作從理論上來講就有點流氓了。

並且如今有一些惡意的apk,它須要接收到系統發送的短信廣播,那麼這時候他確定但願本身最早收到這個短信了,而後把這個廣播給終止了。這時候就能夠這麼作了。


PS:

有的同窗可能會有疑問,說咱們這麼作,那麼其餘家的應用應該也想到這麼作了,是的,因此這裏就須要強調一點:

這種作法是很流氓的,不合常規的,並且設備必須root,因此咱們之後在作相似的功能的時候,最好仍是按照常規的方式去實

現。不要用很是規的方法,那些方法只能騙騙小白用戶,長期這樣對於應用自己發展也是不利的。以上只是我我的觀點。

相關文章
相關標籤/搜索