android Hook 技术剖析

本代码实现的功能:

如何不在清单文件中注册activity就可直接运行使用。

其原理就是使用HOOK技术。

先看清单文件代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test_hook"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:name=".MyApplication"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ProxyActivity" />
    </application>

</manifest>


其中 ProxyActivity是代理类,我们实现的功能是从MainActivity通过intent跳转到OtherActivity

内部代码为:

public class ProxyActivity extends Activity {}

再来看一下MainActivity代码:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	
	public void startOther(View v){
		Toast.makeText(this, "onclick", 0).show();
		Intent intent = new Intent(this, OtherActivity.class);
		startActivity(intent);
	}
}

工具类HookAmsUtil用来实现具体功能(简单做了一些注释):

package com.example.test_hook;
/**
 * 原理:
 * 当从MainActivity通过intent启动OtherActivity时,会先通过ActivityManagerService调用StartActivity方法来执行,然后会通过PackageManagerService
   来检测intent是否有效,有效则通过ActivityThread继续执行,无效则抛出异常,我们要做的就是启动Activity时绕过PackageManagerService的检测.
 * 
 * */

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class HookAmsUtil {
	
	private Class<?> proxyActivity;
	private Context context;
	
	public HookAmsUtil	(Class<?> proxyActivity, Context context) {
		this.proxyActivity = proxyActivity;
		this.context = context;
	}
	
	public void hookAms() throws Exception {
		Log.d("qcdd", "start hook");
		Class<?> forname = Class.forName("android.app.ActivityManagerNative");
		Field defaultField = forname.getDeclaredField("gDefault");
		defaultField.setAccessible(true);
		//dDefault 变量值
		Object degaultValue = defaultField.get(null);  //拿到ActivityManagerNative类的gDefault属性
		//反射SingleTon
		Class<?> forname2 = Class.forName("android.util.Singleton");
		Field instanceField = forname2.getDeclaredField("mInstance");
		instanceField.setAccessible(true);
		//获取系统的iActivityManager对象
		Object iActivityManagerObject = instanceField.get(degaultValue); //获取IActivityManager对象
		//hook
		Class<?> iActivityManagerInercept = Class.forName("android.app.IActivityManager"); //IActivityManager接口
		AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerObject); //将IActivityManager对象传代理handler
		
		/**
		 * newProxyInstance参数解析
		 * classLoader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
           interfaces:   一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣
                    称实现了该接口(多态),这样我就能调用这组接口中的方法了
           invocationHandler: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
		 * */
		Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
				new Class<?>[]{iActivityManagerInercept}, handler);  //创建代理
		instanceField.set(degaultValue, proxy); //将原iActivityManager,替换成代理的proxy,它也属于IActivityManager类型.
		
	}
	
	class AmsInvocationHandler implements InvocationHandler{
		/**
		 * InvocationHandler类
		 * 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,
		 * 这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
		 * */
		private Object iActivityManagerObject;
		public AmsInvocationHandler(Object iActivityManagerObject) {
			this.iActivityManagerObject = iActivityManagerObject;
		}
		
		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			Log.d("qcdd", "methodName: "+ method.getName());
			//当ActivityManagerService调用方法时先会掉此invoke方法.
			if("startActivity".contains(method.getName())){
				Intent intent = null;
				int index = 0;
				for (int i = 0; i < args.length; i++) {
					if (args[i] instanceof Intent) {
						//说明找到了startActivity方法的intnet参数
						intent = (Intent) args[i];//原意图,过不了安检
						index = i;
						break;
					}
				}
				Intent proxyIntent = new Intent();
				ComponentName componentName = new ComponentName(context, proxyActivity);
				proxyIntent.setComponent(componentName);
				proxyIntent.putExtra("oldIntent", intent);
				args[index] = proxyIntent;
				return method.invoke(iActivityManagerObject, args); //替换后继续向下执行
			}
			return method.invoke(iActivityManagerObject, args);
		}
	}
	
	public void hookSystemHandler() throws Exception {
		
		/**
		 * ActivityThread 代表了Android的主线程,具体启动Activity、service,接收广播等等工作就在此类中
		 * final H mH = new H()
		 * 这个H是继承自Handler的,它是个私有的内部类,其实就是主线程的Handler,通过这个Handler就可以往主线程的消息队列发消息,(所以我们要hook此类)
		 * 具体处理动作是在,public void handleMessage(Message msg) {}方法中
		 * 
		 * public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: { //启动activity
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
		 * 
		 * */
		Class<?> forName = Class.forName("android.app.ActivityThread");
		Field currentActivityThreadField = forName.getDeclaredField("sCurrentActivityThread");
		currentActivityThreadField.setAccessible(true);
		Object activityThreadValue = currentActivityThreadField.get(null); //sCurrentActivityThread 当前的进程
		
		Field handlerField = forName.getDeclaredField("mH");
		handlerField.setAccessible(true);
		//mH的变量值
		Handler handlerObject = (Handler) handlerField.get(activityThreadValue); //当前的进程handler
		Field callbackField = Handler.class.getDeclaredField("mCallback");
		callbackField.setAccessible(true);
		callbackField.set(handlerObject, new ActivityThreadHandlerCallback(handlerObject)); //将当前进程handler替换成代理ActivityThreadHandlerCallback
		
	}
	
	class ActivityThreadHandlerCallback implements Handler.Callback {
		
        Handler handler;
        public ActivityThreadHandlerCallback (Handler handler) {
        	super();
        	this.handler = handler;
        }
		@Override
		public boolean handleMessage(Message msg) {
			//当ActivityThread的handler发送消息时会先调用此handleMessage方法.
			Object obj = msg.obj; 
			/**
			 * 此obj对象是ActivityClientRecord类型
			 * ActivityClientRecord是ActivityThread的内部类,用来记录activity的相关属性
			 * 
			 * IBinder token;
        	  int ident;
            Intent intent; //我们用到的就是这个属性
        	  String referrer;
        	  IVoiceInteractor voiceInteractor;
        	  Bundle state;
        	  PersistableBundle persistentState;
        	  Activity activity;
        	  Window window;
        	  Activity parent;
        	  String embeddedID;
        	  Activity.NonConfigurationInstances lastNonConfigurationInstances;
        	  boolean paused;
        	  boolean stopped;
        	  boolean hideForNow;
        	  .........
			 * 
			 * */
			try {
				Field intentField = obj.getClass().getDeclaredField("intent");
				intentField.setAccessible(true);
				Intent proxyIntent = (Intent) intentField.get(obj); //proxyIntent
				Intent realIntent = proxyIntent.getParcelableExtra("oldIntent");
				if (realIntent != null) {
					proxyIntent.setComponent(realIntent.getComponent()); //将真正要启动的intent替换过来
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return false;
		}
		
	}
	
}

具体的调用来看一下MyApplication的调用:

public class MyApplication extends Application {
    private static AmsInvocationHandler handler;
    private Object activityThreadValueObject;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		HookAmsUtil mHookAmsUtil = new HookAmsUtil (ProxyActivity.class,this);
		try {
			mHookAmsUtil.hookAms();
			mHookAmsUtil.hookSystemHandler();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

OK,功能已实现。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值