如何绕过清单文件,动态注入activity
Posted _ArcticOcean
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何绕过清单文件,动态注入activity相关的知识,希望对你有一定的参考价值。
【Android】Android插件开发 —— 打开插件的Activity(Hook系统方法)
Android打开插件中Activity的实现原理
摘要
android打开插件Activity的方式有很多种,类名固定的可以使用预注册的方式。代理也是一种很好的方式,同时代理的方式也可以用于打开插件中的Service。
这两种方式都有一些弊端,这篇文章要分享的是如何更好地打开插件中的Activity,采用Instrumentation注入的方式。
1. Activity是如何被实例化的
1.1 在哪一个类、哪一个方法中实例化的
当开发者实现一个Activity时,不能自己添加一个带参数的构造方法。如果添加了,也需要实现一个无参构造方法。原因是在调用Context.startActivity(…)后,系统会利用反射的方式根据activityClass实例化一个Activity对象:
?1 |
Activity activity = (Activity)clazz.newInstance();
|
其中clazz就是传入的Activity的子类。这一行代码是在Instrumentaion.java中的newActivity(…)方法中的。也就是说,Activity的实例化是在Instrumentation这个类里面,通过反射的方式进行的。
1.2 谁持有了Instrumentation的引用
每个Activity对象都持有了一个mInstrumentation的变量,该变量并不是Activity自己创建的,而是由ActivityThread传递给Activity的。而在ActivityThread中,持有了一个名为mInstrumentation的变量。因此,创建Activity的Instrumentation的对象,是被ActivityThread持有着。
2. 如何偷梁换柱打开插件的Activity
2.1 Activity是否在AndroidManifest.xml注册的校验
如果一个Activity没有注册,想要打开它,会抛出异常:
Unable to find explicit activity class XXXXActivity have you declared this activity in your AndroidManifest.xml?
这个异常是Instrumentation的checkStartActivityResult方法中抛出的:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/** @hide */
public
static
void
checkStartActivityResult(
int
res, Object intent)
if
(res >= ActivityManager.START_SUCCESS)
return
;
switch
(res)
case
ActivityManager.START_INTENT_NOT_RESOLVED:
case
ActivityManager.START_CLASS_NOT_FOUND:
if
(intent
instanceof
Intent && ((Intent)intent).getComponent() !=
null
)
throw
new
ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+
"; have you declared this activity in your AndroidManifest.xml?"
);
throw
new
ActivityNotFoundException(
"No Activity found to handle "
+ intent);
...(以下省略)
|
很明显的一件事,插件中的Activity是没有在AndroidManifest.xml中注册的,直接打开肯定抛异常崩溃。读者可能会想:我要是直接重写这个方法,不管什么情况全部不抛异常,校验不就通过了吗?但是很抱歉,这个方法是static类型的,子类无法重写。这个条件我们没有办法解决,只能绕过去。
2.2 如何绕过Activity的注册校验
Instrumentation有一个很重要的事:checkStartActivityResult(…)方法 是在newActivity(…)方法之前执行的。请看这两个信息:
当开发者使用一个已经注册过的Activity去接受校验时,肯定能通过校验; 实例化出来的Activity一定是经过校验的那一个Activity吗?不一定。 让我们看一下Instrumentation#newActivity(…)方法的具体实现(有两个重载实现):
第一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public
Activity newActivity(Class<!--?--> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance)
throws
InstantiationException,
IllegalAccessException
Activity activity = (Activity)clazz.newInstance();
SQL注入绕过总结
|