android 禁止插件化,Android 插件化实现方式(Hook)

一、首先我们要找到Hook的点

1. 分析

我们先大概看下activity的启动流程(图片来自Android 插件化开发指南)

c3ad3ea8d58b

image

当我们调用startActivity的时候,AMS对我们要启动的Activity进行检查,是否在AndroidManifest中声明过,如果没有就报没有在AndroidManifest的错误。这个时候需要欺骗AMS,我们需要hook,要它去检查一个我们预配置的Activity,通过AMS的检查。

为什么不能直接hook掉AMS,AMS是系统的进程,管理者所有app的启动,不仅仅只是我们自己的app。

2. 看看源码怎么启动的(主要就是拦截这个方法startActivity)

//通过ActivityManagerNative.getDefault()获取一个对象,开始启动新的Activity

int result = ActivityManagerNative.getDefault().startActivity(whoThread,

who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),

token, target != null ? target.mEmbeddedID : null,

requestCode, 0, null, options);

3. 看看代码的实现

private Context mContext;

private Class> mProxyClass;

private String TAG = HookUtil.class.getName();

private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";

public HookUtil(Context context, Class> proxyClass) {

this.mContext = context.getApplicationContext();

this.mProxyClass = proxyClass;

}

public void hookStartActivity() throws Exception {

//1. 通过反射,拿到IActivityManager对象;

Class amnClass = Class.forName("android.app.ActivityManagerNative");

//2. 获得指定的私有属性

Field gDefaultField = amnClass.getDeclaredField("gDefault");

gDefaultField.setAccessible(true);

// 获取字段上面的值传递null 证明是属性是static的,此处返回的是

// new Singleton()

Object gDefault = gDefaultField.get(null);

Class singletonClass = Class.forName("android.util.Singleton");

Field mInstanceField = singletonClass.getDeclaredField("mInstance");

mInstanceField.setAccessible(true);

//不是static的方法 ,需要传入当前使用的对象 此处返回的是IActivityManager

Object iamInstance = mInstanceField.get(gDefault);

Class iamClass = Class.forName("android.app.IActivityManager");

Object proxyInstance = Proxy.newProxyInstance(HookUtil.class.getClassLoader(),

new Class[]{iamClass},

// InvocationHandler 必须执行者,谁去执行

new StartActivityInvocationHandler(iamInstance));

//f.set(obj, "刘德华");

mInstanceField.set(gDefault, proxyInstance);

}

private class StartActivityInvocationHandler implements InvocationHandler {

// 方法执行者

private Object mObject;

public StartActivityInvocationHandler(Object object) {

this.mObject = object;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 替换Intent,过AndroidManifest.xml检测

if (method.getName().equals("startActivity")) {

Log.e(TAG,"Activity已经开始启动");

Log.e(TAG,"小弟到此一游!!!");

// 1.首先获取原来的Intent

Intent originIntent = (Intent) args[2];

// 2.创建一个安全的

Intent safeIntent = new Intent(mContext, mProxyClass);

args[2] = safeIntent;

// 3.绑定原来的Intent

safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);

}

return method.invoke(mObject, args);

}

}

4. 初始化插件

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ButterKnife.bind(this);

mButton.setText("test");

//初始化插件

HookUtil hookUtil =

new HookUtil(this, ProxyActivity.class);

try {

hookUtil.hookStartActivity();

} catch (Exception e) {

e.printStackTrace();

}

}

@OnClick(R.id.btn)

public void btnOnclick() {

Intent intent = new Intent(MainActivity.this, Main3Activity.class

);

startActivity(intent);

}

5. 打印结果(没有报错,打印了当前activity的stop方法,证明通过AMS的检查了)

com.dhcc.net.plug.HookUtil: Activity已经开始启动

com.dhcc.net.plug.HookUtil: 小弟到此一游!!!

二、启动时替换成我们自己的Actvity

1. 当AMS加载activty完成以后,就要启动activity了,这个时候他是通过ActivityThread类中的Handler去处理的。我们首先看看Handler是怎么分发消息的(我们处理msg.callback,将优先级最大化)

/**

* Handle system messages here.

*/

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

2. 替换成为自己的Activity

public void hookLaunchActivity() throws Exception{

// 3.4.1 获取ActivityThread实例

Class> atClass = Class.forName("android.app.ActivityThread");

Field scatField = atClass.getDeclaredField("sCurrentActivityThread");

scatField.setAccessible(true);

Object sCurrentActivityThread = scatField.get(null);

// 3.4.2 获取ActivityThread中的mH

Field mhField = atClass.getDeclaredField("mH");

mhField.setAccessible(true);

Object mHandler = mhField.get(sCurrentActivityThread);

// 3.4 设置当前对象(也就是ActivityThread)的mH的成员变量

Class> handlerClass = Class.forName("android.os.Handler");

Field mCallbackField = handlerClass.getDeclaredField("mCallback");

mCallbackField.setAccessible(true);

mCallbackField.set(mHandler,new HandlerCallBack());

}

private class HandlerCallBack implements Handler.Callback{

@Override

public boolean handleMessage(Message msg) {

Log.e(TAG,"handleMessage");

// 每发一个消息都会走一次这个CallBack发放

if(msg.what == 100){

handleLaunchActivity(msg);

}

return false;

}

/**

* 开始启动创建Activity拦截

* @param msg

*/

private void handleLaunchActivity(Message msg) {

try {

Object record = msg.obj;

// 1.从record 获取过安检的Intent

Field intentField = record.getClass().getDeclaredField("intent");

intentField.setAccessible(true);

Intent proxyInent = (Intent) intentField.get(record);

// 2.从safeIntent中获取原来的originIntent

Intent realIntent = proxyInent.getParcelableExtra(EXTRA_ORIGIN_INTENT);

// 3.重新设置回去

if(realIntent != null){

Log.e(TAG,"启动我们自己的activity了");

intentField.set(record,realIntent);

}

}catch (Exception e){

e.printStackTrace();

}

}

}

3. 修改一下OnCreate方法

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ButterKnife.bind(this);

mButton.setText("test");

//初始化插件

HookUtil hookUtil =new HookUtil(this, ProxyActivity.class);

try {

hookUtil.hookStartActivity();

hookUtil.hookLaunchActivity();

} catch (Exception e) {

e.printStackTrace();

}

}

4. 看看打印结果

com.dhcc.net.plug.HookUtil: Activity已经开始启动

com.dhcc.net.plug.HookUtil: 小弟到此一游!!!

com.dhcc.net.plug.HookUtil: 启动我们自己的activity了

com.dhcc.net E/Main3Activity: 我是没有注册的Activity

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值