Android Hook Activity 的几种姿势

本文详细介绍了三种Hook Android Activity的方法:通过ActivityThread的mH,Hook AMS以及API 25之前的ActivityManagerNative。文章提供了具体的代码示例,解释了如何使用动态代理替换原始对象以实现Hook,并讨论了Hook过程中可能遇到的问题和解决方案,如处理未注册Activity的启动。
摘要由CSDN通过智能技术生成

// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法

try {

Method execStartActivity = Instrumentation.class.getDeclaredMethod

(“execStartActivity”, Context.class, IBinder.class, IBinder.class, Activity

.class, Intent.class, int.class, Bundle.class);

execStartActivity.setAccessible(true);

return (ActivityResult) execStartActivity.invoke(mBase, who, contextThread, token,

target, intent, requestCode, options);

} catch (Exception e) {

// rom修改了 需要手动适配

throw new RuntimeException(“do not support!!! pls adapt it”);

}

}

}

可以看到在 ApplicationInstrumentation 里面,我们只是打印出 startActivity 中各个方法参数的值。

运行以下测试代码

try {

HookHelper.attachContext();

} catch (Exception e) {

e.printStackTrace();

}

Intent intent = new Intent(this, TestActivityStart.class);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

getApplicationContext().startActivity(intent);

将看到以下 log


Hook AMS


上面 hook activity 的两种方法其实都有一定缺陷,比如,第一种方法,只能 hook 住通过 Activity startActivity 的 activity。第二种方法,只能 hook 住通过 getApplicationContext().startActivity 启动的 activity。那有没有一种方法能 hook 上述两种的,其实是有的,那就是 hook AMS。下面让我们一起来看一下。

上面 hook startActivity 其实都是 hook 相应的 mInstrumentation.execStartActivity 方法,因此,我们可以从这里下手,看 mInstrumentation.execStartActivity 里面有没有一些共性的东西,可以 hook。

我们先来 mInstrumentation.execStartActivity 方法

public ActivityResult execStartActivity(

Context who, IBinder contextThread, IBinder token, Activity target,

Intent intent, int requestCode, Bundle options) {

IApplicationThread whoThread = (IApplicationThread) contextThread;

Uri referrer = target != null ? target.onProvideReferrer() : null;

if (referrer != null) {

intent.putExtra(Intent.EXTRA_REFERRER, referrer);

}

if (mActivityMonitors != null) {

synchronized (mSync) {

final int N = mActivityMonitors.size();

for (int i=0; i<N; i++) {

final ActivityMonitor am = mActivityMonitors.get(i);

ActivityResult result = null;

if (am.ignoreMatchingSpecificIntents()) {

result = am.onStartActivity(intent);

}

if (result != null) {

am.mHits++;

return result;

} else if (am.match(who, null, intent)) {

am.mHits++;

if (am.isBlocking()) {

return requestCode >= 0 ? am.getResult() : null;

}

break;

}

}

}

}

try {

intent.migrateExtraStreamToClipData();

intent.prepareToLeaveProcess(who);

int result = ActivityManager.getService()

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

intent.resolveTypeIfNeeded(who.getContentResolver()),

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

requestCode, 0, null, options);

checkStartActivityResult(result, intent);

} catch (RemoteException e) {

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

}

return null;

}

这里我们留意 ActivityManager.getService().startActivity 这个方法

public static IActivityManager getService() {

return IActivityManagerSingleton.get();

}

private static final Singleton IActivityManagerSingleton =

new Singleton() {

@Override

protected IActivityManager create() {

final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);

final IActivityManager am = IActivityManager.Stub.asInterface(b);

return am;

}

};

可以看到 IActivityManagerSingleton 是一个单例对象,因此,我们可以 hook 它。

public static void hookAMSAfter26() throws Exception {

// 第一步:获取 IActivityManagerSingleton

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

Field declaredField = aClass.getDeclaredField(“IActivityManagerSingleton”);

declaredField.setAccessible(true);

Object value = declaredField.get(null);

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

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

instanceField.setAccessible(true);

Object iActivityManagerObject = instanceField.get(value);

// 第二步:获取我们的代理对象,这里因为 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(value, proxy);

}

public class AMSInvocationHandler implements InvocationHandler {

private static final String TAG = “AMSInvocationHandler”;

Object iamObject;

public AMSInvocationHandler(Object iamObject) {

this.iamObject = iamObject;

}

@Override

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

// Log.e(TAG, method.getName());

if (“startActivity”.equals(method.getName())) {

Log.i(TAG, “ready to startActivity”);

for (Object object : args) {

Log.d(TAG, “invoke: object=” + object);

}

}

return method.invoke(iamObject, args);

}

}

执行以下测试代码

try {

HookHelper.hookAMS();

} catch (Exception e) {

e.printStackTrace();

}

startActivity(new Intent(this,TestActivityStart.class));

将会看到以下 log

I/AMSInvocationHandler: ready to startActivity

接下来我们一起来看一下 API 25 Instrumentation 的代码(自 API 26 开始 ,Instrumentation execStartActivity 方法有所改变)

public ActivityResult e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值