简述
要发动未注册的Activity首要是要躲避AMS的检测,思路是,检测前要发动的Activity换成注册的,检测经过了,再在发动前换回来。这儿首要是两个点。检测前,hookAMS
。检测后hookHandler
。hook点有许多尽量找静态变量、单例和public
hookAMS
1、android 11举例,发动acitivty是在ATMS中(11之前是AMS,这个自己能够去适配)
2、拿到ATMS的署理。
3、然后ATMS整个动态署理
在startActivity之前将Intent
偷梁换柱
4、换成现已注册的Activity之后记住原目标Acitivty存起来,在骗完AMS之后换回来
public static void hookAMS() {
// 10之前
try {
Class<?> clazz = Class.forName("android.app.ActivityTaskManager");
Field singletonField = clazz.getDeclaredField("IActivityTaskManagerSingleton");
singletonField.setAccessible(true);
Object singleton = singletonField.get(null);
Class<?> singletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Method getMethod = singletonClass.getMethod("get");
Object mInstance = getMethod.invoke(singleton);
Class IActivityTaskManagerClass = Class.forName("android.app.IActivityTaskManager");
Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{IActivityTaskManagerClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startActivity".equals(method.getName())) {
int index = -1;
// 获取 Intent 参数在 args 数组中的index值
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
index = i;
break;
}
}
// 生成署理proxyIntent -- 孙悟空(署理)的Intent
Intent proxyIntent = new Intent();
// 这个包名是宿主的
proxyIntent.setClassName("com.leo.amsplugin",
ProxyActivity.class.getName());
// 原始Intent能丢掉吗?保存原始的Intent目标
Intent intent = (Intent) args[index];
proxyIntent.putExtra(TARGET_INTENT, intent);
// 运用proxyIntent替换数组中的Intent
args[index] = proxyIntent;
}
// 本来流程
return method.invoke(mInstance, args);
}
});
// 用署理的目标替换体系的目标
mInstanceField.set(singleton, mInstanceProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
hookHandler
hookAMS完成,欺骗了AMS,接下来要把Intent中的原目标扶起回正位, 发动Activity要用handler,咱们从这儿hook吧
1、Activtiy thread 中的handler用来发动activity class H extends Handler
2、handlerMessage中的EXECUTE_TRANSACTION(159)来发动activity
3、
final ClientTransaction transaction = (ClientTransaction) msg.obj;–包含Intent
mTransactionExecutor.execute(transaction);–履行发动
launchActivityItem
中有Intent
,而ta继承于ClientTransactionItem
,而ClientTransaction
中包含List<ClientTransactionItem>
4、所以我只需拿到msg
就能够拿到Intent
。
msg.obj –> ClientTransaction –> List mActivityCallbacks(LaunchActivityItem)
–> private Intent mIntent 替换
5、handlerMessage(MSG)之前有个callback也能够拿到msg。则会callback是一个接口,如果重写这个接口可就可重新handlerMessage这个办法,然后操作msg。
6、ActivityThread当中,Handler的构建没有传参数。
...//去ActivityThread.java里看
@UnsupportedAppUsage
final H mH = new H();
...
class H extends Handler //也没写构造办法
...//去Handler.java里看
@Deprecated
public Handler() {
this(null, false);
}
7、实际上callback是看,那么我自己替换体系的call就能够啦
8、那我经过反射
拿Handler中的mCallback
,
public void hoodHandler() {
try {
Class<?> clazz = Class.forName("android.app.ActivityThread");
Field activityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
activityThreadField.setAccessible(true);
Object activityThread = activityThreadField.get(null);
Field mHField = clazz.getDeclaredField("mH");
mHField.setAccessible(true);
final Handler mH = (Handler) mHField.get(activityThread);
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
mCallbackField.set(mH, new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case 159:
// msg.obj = ClientTransaction
try {
// 获取 List<ClientTransactionItem> mActivityCallbacks 目标
Field mActivityCallbacksField = msg.obj.getClass()
.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List mActivityCallbacks = (List) mActivityCallbacksField.get(msg.obj);
for (int i = 0; i < mActivityCallbacks.size(); i++) {
// 打印 mActivityCallbacks 的所有item:
//android.app.servertransaction.WindowVisibilityItem
//android.app.servertransaction.LaunchActivityItem
// 如果是 LaunchActivityItem,则获取该类中的 mIntent 值,即 proxyIntent
if (mActivityCallbacks.get(i).getClass().getName()
.equals("android.app.servertransaction.LaunchActivityItem")) {
Object launchActivityItem = mActivityCallbacks.get(i);
Field mIntentField = launchActivityItem.getClass()
.getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Intent proxyIntent = (Intent) mIntentField.get(launchActivityItem);
// 获取发动插件的 Intent,并替换回来
Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
if (intent != null) {
mIntentField.set(launchActivityItem, intent);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return false;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
总结
一个分为两步
1、hookAMS首要就是躲避ams检测,让ams检测的是一个现已注册了的activity。
2、hookHandler在生成activity之前再把activity换回来。
所以一定要熟悉动态署理,反射和Activity的发动流程。
首要经过hook,核心在于hook点
插桩 1、尽量找 静态变量 单利 2、public
动态署理
AMS检测之前我改下