Android Hook告诉你 如何启动未注册的Activity(1)

文章讲述了如何通过Java反射和代理模式(包括静态代理和动态代理)来hookAndroid的ActivityManagerNative单例,进而实现对startActivity方法的拦截和修改,以绕过Activity的注册检查并启动未注册的Activity。作者还介绍了如何通过自定义InvocationHandler和Handler.Callback来实现这一过程。
摘要由CSDN通过智能技术生成

Object gDefault = Reflex.getStaticFieldObject(“android.app.ActivityManagerNative”,“gDefault”);

gDefault是 Singleton类型的对象,Singleton是一个单例模式

public abstract class Singleton {

private T mInstance;

public Singleton() {

}

protected abstract T create();

public final T get() {

synchronized(this) {

if(this.mInstance == null) {

this.mInstance = this.create();

}

return this.mInstance;

}

}

}

接下里我们来取出mInstance字段

Object mInstance = Reflex.getFieldObject(“android.util.Singleton”,gDefault,“mInstance”);

然后创建一个代理对象

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

Object proxy = Proxy.newProxyInstance(classInterface.getClassLoader(),

new Class<?>[]{classInterface},new AMNInvocationHanlder(mInstance));

我们的代理对象就是new AMNInvocationHanlder(mInstance),(ps:代理模式分为静态代理和动态代理,如果对代理模式不了解可以百度一波,也可以关注我,等待我的代理模式相关文章)

public class AMNInvocationHanlder implements InvocationHandler {

private String actionName = “startActivity”;

private Object target;

public AMNInvocationHanlder(Object target) {

this.target = target;

}

@Override

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

if (method.getName().equals(actionName)){

Log.d(“—”,“啦啦啦我是hook AMN进来的”);

return method.invoke(target,args);

}

return method.invoke(target,args);

}

}

所有的代理类都要实现InvocationHandler接口,在invoke方法中method.invoke(target,args);表示的就是 执行被代理对象所对应的方法。因为AMN Singleton做的事情比较多,所以这里只对startActivity方法hook

if (method.getName().equals(actionName)){

Log.d(“—”,“啦啦啦我是hook AMN进来的”);

return method.invoke(target,args);

}

然后我们将gDefault字段替换为我们的代理类

Reflex.setFieldObject(“android.util.Singleton”,gDefault,“mInstance”,proxy);

AmsHookHelperUtils方法整体如下:

public class AmsHookHelperUtils {

public static void hookAmn() throws ClassNotFoundException {

Object gDefault = Reflex.getStaticFieldObject(“android.app.ActivityManagerNative”,“gDefault”);

Object mInstance = Reflex.getFieldObject(“android.util.Singleton”,gDefault,“mInstance”);

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

Object proxy = Proxy.newProxyInstance(classInterface.getClassLoader(),

new Class<?>[]{classInterface},new AMNInvocationHanlder(mInstance));

Reflex.setFieldObject(“android.util.Singleton”,gDefault,“mInstance”,proxy);

}

}

我们调用AmsHookHelperUtils.hookAmn();然后启动一个新的Activity,运行日志如下:

这样我们就成功Hook了AMN的getDefault方法。

2.3 如何启动一个未注册的Activity

如何启动一个未注册的Activity,首先我们了解Activity的启动流程,App的启动流程已经在上篇文章中讲解了,APP启动流程解析,还不了解的小伙伴,可先移步至上篇文章。假设现在MainActivity,Main2Activity,Main3Activity,其中Main3Activity未注册,我们在MainActivity中启动Main3Activity,当启动Main3Activity的时候,AMS会在配置文件中检查,是否有Main3Activity的配置信息如果不存在则报错,存在则启动Main3Activity。

所以我们可以做的是,将要启动的Activity发送给AMS之前,将要启动的Activity替换未已经注册Activity Main2Activity,这样AMS就可以检验通过,当AMS要启动目标Activity的时候再将Main2Activity替换为真正要启动的Activity。

首先我们按照上面逻辑先对startActivity方法进行Hook,这里采用对AMN Hook的方式。和上述代码一样,不一样的地方在于mInstance的代理类不同。

新建一个AMNInvocationHanlder1对象同样继承自InvocationHandler,只拦截startActivity方法。

if (method.getName().equals(actionName)){}

在这里我们要做的就是将要启动的Main3Activity替换为Main2Activity,这样能绕过AMS的检验,首先我们从目标方法中取出目标Activity。

Intent intent;

int index = 0;

for (int i = 0;i<args.length;i++){

if (args[i] instanceof Intent){

index = i;

break;

}

}

你可能会问你怎么知道args中一定有intent类的参数,因为invoke方法中最终会执行

return method.invoke(target,args);

表示会执行原本的方法,而我们来看原本的startActivity方法如下:

int var16 = ActivityManagerNative.getDefault().startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null?target.mEmbeddedID:null, requestCode, 0, (String)null, (ParcelFileDescriptor)null, options);

所以我们说args中肯定有个intent类型的参数,获取真实目标Activity之后,我们获取目标的包名

intent = (Intent) args[index];

String packageName = intent.getComponent().getPackageName();

新建一个Intent 将intent设置为 冒充者Main2Activity的相关信息

Intent newIntent = new Intent();

ComponentName componentName = new ComponentName(packageName,Main2Activity.class.getName());

newIntent.setComponent(componentName);

args[index] = newIntent;

这样目标Activity就被替换成了Main2Activity,不过这个冒充者还要将原本的目标携带过去,等待真正打开的时候再替换回来,否则就真的启动这个冒充者了

newIntent.putExtra(AmsHookHelperUtils.TUREINTENT,intent);

这个时候我们调用这个方法什么都不做,这个时候启动Main3Activity

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

显示的其实是Main2Activity,如图所示:

这样说明我们的冒充者已经成功替换了真实目标,所以我们接下来要在启动的时候,将冒充者再重新替换为目标者,ActivityThread通过mH发消息给AMS

synchronized(this) {

Message msg = Message.obtain();

msg.what = what;

msg.obj = obj;

msg.arg1 = arg1;

msg.arg2 = arg2;

this.mH.sendMessage(msg);

}

AMS收到消息后进行处理

public void handleMessage(Message msg) {

ActivityThread.ActivityClientRecord data;

switch(msg.what) {

case 100:

Trace.traceBegin(64L, “activityStart”);

data = (ActivityThread.ActivityClientRecord)msg.obj;

data.packageInfo = ActivityThread.this.getPackageInfoNoCheck(data.activityInfo.applicationInfo, data.compatInfo);

ActivityThread.this.handleLaunchActivity(data, (Intent)null);

Trace.traceEnd(64L);

mH是Handler类型的消息处理类,所以sendMessage方法会调用callback,Handler消息处理机制可看我之前一篇博客

深入理解Android消息机制,所以我们可以对callback字段进行Hook。如果不明白怎么办?关注我!

新建hookActivityThread方法,首先我们获取当前的ActivityThread对象

Object currentActivityThread = Reflex.getStaticFieldObject(“android.app.ActivityThread”, “sCurrentActivityThread”);

然后获取对象的mH对象

Handler mH = (Handler) Reflex.getFieldObject(currentActivityThread, “mH”);

将mH替换为我们的自己自定义的MyCallback。

Reflex.setFieldObject(Handler.class, mH, “mCallback”, new MyCallback(mH));

自定义MyCallback首先 Handler.Callback接口,重新处理handleMessage方法

@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case 100:

handleLaunchActivity(msg);

break;

default:

break;

}

mBase.handleMessage(msg);

return true;

}

我们获取传递过来的目标对象

Object obj = msg.obj;

Intent intent = (Intent) Reflex.getFieldObject(obj, “intent”);

然后从目标对象中取出携带过来的真实对象,并将intent修改为真实目标对象的信息,这样就可以启动真实的目标Activity

Intent targetIntent = intent.getParcelableExtra(AmsHookHelperUtils.TUREINTENT);

intent.setComponent(targetIntent.getComponent());

MyCallbackt如下

**

  • Created by Huanglinqing on 2019/4/30.

*/

public class MyCallback implements Handler.Callback {

Handler mBase;

public MyCallback(Handler base) {

mBase = base;

}

@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case 100:

handleLaunchActivity(msg);

break;

default:

break;

}

mBase.handleMessage(msg);

return true;

}

private void handleLaunchActivity(Message msg) {

Object obj = msg.obj;

Intent intent = (Intent) Reflex.getFieldObject(obj, “intent”);

Intent targetIntent = intent.getParcelableExtra(AmsHookHelperUtils.TUREINTENT);

intent.setComponent(targetIntent.getComponent());

}

【附】相关架构及资料

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ntent");

Intent targetIntent = intent.getParcelableExtra(AmsHookHelperUtils.TUREINTENT);

intent.setComponent(targetIntent.getComponent());

}

【附】相关架构及资料

[外链图片转存中…(img-AMliHuub-1714279805915)]

[外链图片转存中…(img-GweR1WdS-1714279805916)]

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值