南阳建设网站招聘,wordpress分类指定页面,西安网络科技公司排名,四川建设人才网官网查询第一步、先爆项目demo照片#xff0c;代码不多#xff0c;不要怕 第二步、应该知道Java反射相关知识 如果不知道或者忘记的小伙伴请猛搓这里#xff0c;Android插件化开发基础之Java反射机制研究 http://blog.csdn.net/u011068702/article/details/49863931第三步、应该知道…第一步、先爆项目demo照片代码不多不要怕 第二步、应该知道Java反射相关知识
如果不知道或者忘记的小伙伴请猛搓这里Android插件化开发基础之Java反射机制研究 http://blog.csdn.net/u011068702/article/details/49863931第三步、应该知道Java静态代理知识
如果不知道或者忘记的小伙伴请猛搓这里Android插件化开发基础之静态代理模式 http://blog.csdn.net/u011068702/article/details/51765578第四部、应该知道Java动态代理知识
如果不知道或者忘记的小伙伴请猛搓这里Android插件化开发基础之Java动态代理proxy机制的简单例子 http://blog.csdn.net/u011068702/article/details/53185210上面只有代码的解释如果不是很清楚的小伙伴可以再去到网上搜一搜相关知识。第五步、应该知道Android里面的ActivityThread类和Instrumentation类
如果不知道或者忘记的小伙伴请猛搓这里Android插件化开发之AMS与应用程序(客户端ActivityThread、Instrumentation、Activity)通信模型分析 http://blog.csdn.net/u011068702/article/details/53207039希望认真看知道ActivityThread和Instrumentation是干嘛的方便下面分析。第六步、理解hook并且分析源码
如果我们自己创建代理对象然后把原始对象替换为我们的代理对象那么就可以在这个代理对象为所欲为了修改参数替换返回值我们称之为Hook。接下来我们来实现Hook掉startActivity这个方法当每次调用这个方法的时候来做我们需要做的事情我这里之打印了一些信息读者可以更具自己的需求来修改我们的目的是拦截startActivity方法有点类是spring 里面AOP的思想。1、hook一般在哪里hook?
首先分析我们需要hook哪些对象也就是说我们要hook的地方什么样的对象比较好Hook呢一般是容易找到和不容易改变的对象这思路就来了不改变一般在我们类的里面单例对象是唯一对象静态变量我们一般加上final static 修饰有了final就不会改变不变模式里面比如String类里面就很多final,我们更加这些找到hook的地方。2、我们hook startActivity,分析startActivity到底是怎么实现的 我们每次Context.startActivity由于Context的实现实际上是ContextImpl来实现的;我们看ConetxtImpl类的startActivity方法Override
public void startActivity(Intent intent, Bundle options) {warnIfCallingFromSystemProcess();if ((intent.getFlags()Intent.FLAG_ACTIVITY_NEW_TASK) 0) {throw new AndroidRuntimeException(Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?);}mMainThread.getInstrumentation().execStartActivity(getOuterContext(), mMainThread.getApplicationThread(), null,(Activity)null, intent, -1, options);
} 我们可以看到startActivity方法最后还是通过Instrumentation对象来执行execStartActivity来实现的,如果你认真看了《Android插件化开发之AMS与应用程序(客户端ActivityThread、Instrumentation、Activity)通信模型分析 》上面这篇博客我们知道ActivityThread就是主线程也就是我们常说的UI线程可以去更新UI一个进程只有一个主线程我们可以在这里hook. 我们需要Hook掉我们的主线程对象把主线程对象里面的mInstrumentation给替换成我们修改过的代理对象要替换主线程对象里面的字段
1首先我们得拿到主线程对象的引用如何获取呢ActivityThread类里面有一个静态方法currentActivityThread可以帮助我们拿到这个对象类但是ActivityThread是一个隐藏类我们需要用反射去获取代码如下 // 先获取到当前的ActivityThread对象
Class? activityThreadClass Class.forName(android.app.ActivityThread);
Method currentActivityThreadMethod activityThreadClass.getDeclaredMethod(currentActivityThread);
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread currentActivityThreadMethod.invoke(null); 2拿到这个currentActivityThread之后我们需要修改它的mInstrumentation这个字段为我们的代理对象我们先实现这个代理对象由于JDK动态代理只支持接口而这个Instrumentation是一个类我们可以手动写静态代理类覆盖掉原始的方法代码如下package com.example.hookstartactivity;import java.lang.reflect.Method;import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityResult;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;public class InstrumentationProxy extends Instrumentation {public static final String TAG InstrumentationProxy;public static final String EXEC_START_ACTIVITY execStartActivity;// ActivityThread里面原始的Instrumentation对象,这里千万不能写成mInstrumentation,这样写//抛出异常已亲测试所以这个地方就要注意了public Instrumentation oldInstrumentation;//通过构造函数来传递对象public InstrumentationProxy(Instrumentation mInstrumentation) {oldInstrumentation mInstrumentation;}//这个方法是由于原始方法里面的Instrumentation有execStartActivity方法来定的public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {Log.d(TAG, \n打印调用startActivity相关参数: \n who [ who ], \ncontextThread [ contextThread ], \ntoken [ token ], \ntarget [ target ], \nintent [ intent ], \nrequestCode [ requestCode ], \noptions [ options ]);Log.i(TAG, ------------hook success-------------);Log.i(TAG, 这里可以做你在打开StartActivity方法之前的事情);Log.i(TAG, ------------hook success-------------);Log.i(TAG, );//由于这个方法是隐藏的所以需要反射来调用先找到这方法try {Method execStartActivity Instrumentation.class.getDeclaredMethod(EXEC_START_ACTIVITY,Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);execStartActivity.setAccessible(true);return (ActivityResult) execStartActivity.invoke(oldInstrumentation, who, contextThread, token, target, intent, requestCode, options);} catch (Exception e) {//如果你在这个类的成员变量Instrumentation的实例写错mInstrument,代码讲会执行到这里来throw new RuntimeException(if Instrumentation paramerter is mInstrumentation, hook will fail);}}
} 3然后用代理对象替换代码如下 package com.example.hookstartactivity;import java.lang.reflect.Field;
import java.lang.reflect.Method;import android.app.Application;
import android.app.Instrumentation;
import android.util.Log;public class MyApplication extends Application {public static final String TAG MyApplication;public static final String ACTIVIT_THREAD android.app.ActivityThread;public static final String CURRENT_ACTIVITY_THREAD currentActivityThread;public static final String INSTRUMENTATION mInstrumentation;Overridepublic void onCreate() {try {//这个方法一般是写在Application的oncreate函数里面如果你写在activity里面的oncrate函数里面就已经晚了attachContext();} catch (Exception e) {e.printStackTrace();}}public static void attachContext() throws Exception{//获取当前的ActivityThread对象Class? activityThreadClass Class.forName(ACTIVIT_THREAD);Method currentActivityThreadMethod activityThreadClass.getDeclaredMethod(CURRENT_ACTIVITY_THREAD);currentActivityThreadMethod.setAccessible(true);Object currentActivityThread currentActivityThreadMethod.invoke(null);//拿到在ActivityThread类里面的原始mInstrumentation对象Field mInstrumentationField activityThreadClass.getDeclaredField(INSTRUMENTATION);mInstrumentationField.setAccessible(true);Instrumentation mInstrumentation (Instrumentation) mInstrumentationField.get(currentActivityThread);//构建我们的代理对象Instrumentation evilInstrumentation new InstrumentationProxy(mInstrumentation);//通过反射换掉字段注意这里是反射的代码不是Instrumentation里面的方法mInstrumentationField.set(currentActivityThread, evilInstrumentation);//做个标记方便后面查看Log.i(TAG, has go in MyApplication attachContext method);}
} 要注意这个替换要在Application里面的oncreate方法里面去执行如果到Activity方法里面去执行的话就晚了程序不会报错但是hook不到。 然后我是在主页面写了一个按钮点击来触发startActivity的。 MainActivity.java 文件如下package com.example.hookstartactivity;import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;public class MainActivity extends ActionBarActivity {public static final String TAG MainActivity;public TextView tv;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv (TextView)findViewById(R.id.start);tv.setOnClickListener(new OnClickListener(){Overridepublic void onClick(View v) {try {Intent intent new Intent(MainActivity.this, SecondActivity.class); Bundle bundle new Bundle();Log.i(TAG, --------------------------------);Log.i(TAG, startActivity before);Log.i(TAG, --------------------------------);startActivity(intent, bundle);Log.i(TAG, --------------------------------);Log.i(TAG, startActivity after);Log.i(TAG, --------------------------------);} catch (Exception e) {e.printStackTrace();}}} );}
} 跳转到的Second.java文件如下package com.example.hookstartactivity;import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;public class SecondActivity extends ActionBarActivity{Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);}
} 第七步、运行代码
启动项目在ubuntu终端打印的日志图片如下然后我点击图标调用startActivity方法后ubuntu终端打印的日志图片如下日志上面看到hook success了看到ubuntu终端日志打印,前面显示了类方便通过日志找bug,我用的是pidcat下载pidcat 然后在ubuntu上面运行 pidcat.py 包名 就可以非常方便看的日志找bug了。第八步、总结
通过这篇日志希望打击可以更好的理解hook、java反射、静态代理、动态代理、ActivityThread、Instrumentation最后附上源码下载地址需要的小伙伴请猛搓这里 HookStartActivityDemo