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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!