您的位置:首页 > 移动开发 > Android开发

android Hook 技术剖析

2017-03-19 23:46 411 查看
本代码实现的功能:

如何不在清单文件中注册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,功能已实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: