Android Hook Activity 的几种姿势

本文详细介绍了如何在Android中使用Hook技术绕过系统对未注册Activity的校验,从而启动未在AndroidManifest声明的Activity。通过hook AMS(ActivityManagerService)和ActivityThread的mH,以及动态代理,实现了在不同API级别上启动未声明Activity的方法。同时,针对AppCompatActivity子类的情况,文章提出了兼容解决方案,涉及NavUtils和PackageManager的hook。最后,文章总结了启动未注册Activity的两个关键步骤,并分享了作者的Android开发学习资源。
摘要由CSDN通过智能技术生成

Log.v(“ActivityManager”, "default service binder = " + b);

}

IActivityManager am = asInterface(b);

if (false) {

Log.v(“ActivityManager”, "default service = " + am);

}

return am;

}

};

}

同理我们看到 ActivityManagerNative 的 gDefault 是一个静态变量,因此,我们可以尝试 hook gDefault.

public static void hookAmsBefore26() throws Exception {

// 第一步:获取 IActivityManagerSingleton

Class<?> forName = Class.forName(“android.app.ActivityManagerNative”);

Field defaultField = forName.getDeclaredField(“gDefault”);

defaultField.setAccessible(true);

Object defaultValue = defaultField.get(null);

Class<?> forName2 = Class.forName(“android.util.Singleton”);

Field instanceField = forName2.getDeclaredField(“mInstance”);

instanceField.setAccessible(true);

Object iActivityManagerObject = instanceField.get(defaultValue);

// 第二步:获取我们的代理对象,这里因为 IActivityManager 是接口,我们使用动态代理的方式

Class<?> iActivity = Class.forName(“android.app.IActivityManager”);

InvocationHandler handler = new AMSInvocationHandler(iActivityManagerObject);

Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{iActivity}, handler);

// 第三步:偷梁换柱,将我们的 proxy 替换原来的对象

instanceField.set(defaultValue, proxy);

}

到此,hook Activity 的三种方式已讲解完毕


启动一个没有在 AndroidManifest 声明的 Activity


我们知道,当我们启动一个没有在 AndroidManifest 中声明的 activity,会抛出 ActivityNotFoundException 异常。

Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.xj.hookdemo/com.xj.hookdemo.activityhook.TargetAppCompatActivity}; have you declared this activity in your AndroidManifest.xml?

at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2124)

at android.app.Instrumentation.execStartActivity(Instrumentation.java:1802)

at android.app.Activity.startActivityForResult(Activity.java:4514)

at android.support.v4.app.BaseFragmentActivityApi16.startActivityForResult(BaseFragmentActivityApi16.java:54)

at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:67)

at android.app.Activity.startActivityForResult(Activity.java:4472)

at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:720)

at android.app.Activity.startActivity(Activity.java:4833)

at android.app.Activity.startActivity(Activity.java:4801)

at com.xj.hookdemo.activityhook.TestStartActivityNoRegister.onB

从报错的堆栈中,我们非常定位到 Instrumentation.execStartActivity 方法

public ActivityResult execStartActivity(

Context who, IBinder contextThread, IBinder token, String resultWho,

Intent intent, int requestCode, Bundle options, UserHandle user) {

----- // 省略若干代码

try {

intent.migrateExtraStreamToClipData();

intent.prepareToLeaveProcess(who);

int result = ActivityManager.getService()

.startActivityAsUser(whoThread, who.getBasePackageName(), intent,

intent.resolveTypeIfNeeded(who.getContentResolver()),

token, resultWho,

requestCode, 0, null, options, user.getIdentifier());

checkStartActivityResult(result, intent);

} catch (RemoteException e) {

throw new RuntimeException(“Failure from system”, e);

}

return null;

}

在该方法中,调用 startActivityAsUser 方法通过传入的 intent 获取 result,再通过 checkStartActivityResult 方法,判断 result 是否合法。

而我们知道我们启动的 activity 信息都储存在 intent 中,那么我们若想要 启动一个没有在 AndroidManifest 声明的 Activity,那我们只需要在 某个时机,即调用 startActivity 方法之前欺骗 AMS 我们的 activity 已经注册(即替换 intent),这样就不会抛出 ActivityNotFoundException 异常。

在前面的时候,我们已经讲解到如何 hook ams,这里我们不再具体讲述,主要步骤如下

  • 第一步, API 26 以后,hook android.app.ActivityManager.IActivityManagerSingleton, API 25 以前,hook android.app.ActivityManagerNative.gDefault

  • 第二步,获取我们的代理对象,这里因为是接口,所以我们使用动态代理的方式

  • 第三步:设置为我们的代理对象

private static void hookAMS(Context context) throws ClassNotFoundException,

NoSuchFieldException, IllegalAccessException {

// 第一步, API 26 以后,hook android.app.ActivityManager.IActivityManagerSingleton,

// API 25 以前,hook android.app.ActivityManagerNative.gDefault

Field gDefaultField = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

Class<?> activityManager = Class.forName(“android.app.ActivityManager”);

gDefaultField = activityManager.getDeclaredField(“IActivityManagerSin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值