网站开发设计的论文,广州宝盈网络科技有限公司网站,网络营销的八大能力,房地产行业发展前景分析一、Hook技术概述 Hook技术的核心实际上是动态分析技术#xff0c;动态分析是指在程序运行时对程序进行调试的技术。众所周知#xff0c;Android系统的代码和回调是按照一定的顺序执行的#xff0c;这里举一个简单的例子#xff0c;如图所示。 对象A调用类对象B#xff0c…一、Hook技术概述 Hook技术的核心实际上是动态分析技术动态分析是指在程序运行时对程序进行调试的技术。众所周知Android系统的代码和回调是按照一定的顺序执行的这里举一个简单的例子如图所示。 对象A调用类对象B对象B处理后将数据回调给对象A。接下来看看采用Hook的调用流程如下图 上图中的Hook可以是一个方法或者一个对象它就想一个钩子一样始终连着AB在AB之间互传信息的时候hook会在中间做一些处理比如修改方法的参数和返回值等就这样hook起到了欺上瞒下的作用我们把hook的这种行为称之为劫持。同理大家知道系统进程和应该进程之间是相互独立的应用进程要想直接去修改系统进程这个是很难实现的有了hook技术就可以在进程之间进行行为更改了。如图所示 可见hook将自己融入到它所劫持的对象B所在的进程中成为系统进程的一部分这样我们就可以通过hook来更改对象B的行为了对象B就称为hook点。 二、Hook Instrumentation 上面讲了Hook可以劫持对象被劫持的对象叫hook点用代理对象来替代这个Hook点这样我们就可以在代理上实现自己想做的操作。这里我们用Hook startActivity来举例。Activity的插件化中需要解决的一个问题就是启动一个没有在AndroidManifest中注册的Activity如果按照正常的启动流程是会报crash的。这里先简要介绍一下Activity的启动具体的启动方式讲解还需移步专门的文献。 2.1 Activity的Hook点 启动Activity时应用进程会发消息给AMS请求AMS创建ActivityAMS在SystemServer系统进程中其与应用进程是隔离的AMS管理所有APP的启动所以我们无法在系统进程下做hook操作应该在应用进程中。为了绕过AMS的验证我们需要添加一个在Manifest中注册过的Activity这个Activity称为占坑这样可以达到欺上瞒下的效果当AMS验证通过后再用插件Activity替换占坑去实现相应的功能。 核心功能两点 替换插件Activity为占坑Activity绕过AMS验证后需要还原插件Activity启动Activity的时候会调用Activity的startActivity如下 Overridepublic void startActivity(Intent intent) {this.startActivity(intent, null);}
复制代码接着又调用了startActivity Overridepublic void startActivity(Intent intent, Nullable Bundle options) {if (options ! null) {startActivityForResult(intent, -1, options);} else {// Note we want to go through this call for compatibility with// applications that may have overridden the method.startActivityForResult(intent, -1);}}
复制代码查看startActivityForResult方法 public void startActivityForResult(RequiresPermission Intent intent, int requestCode,Nullable Bundle options) {if (mParent null) {options transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar ! null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode 0) {// If this start is requesting a result, we can avoid making// the activity visible until the result is received. Setting// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the// activity hidden during this time, to avoid flickering.// This can only be done when a result is requested because// that guarantees we will get information back when the// activity is finished, no matter what happens to it.mStartedActivity true;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {if (options ! null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}}
复制代码上述方法中调用mInstrumentation的execStartActivity方法来启动Activity这个mInstrumentation是Activity的成员变量我们就选择Instrumentation为Hook点用代理的Instrumentation去替换原始的Instrumentation来完成Hook如下是代理类 public class InstrumentationProxy extends Instrumentation {private Instrumentation mInstrumentation;private PackageManager mPackageManager;public InstrumentationProxy(Instrumentation instrumentation, PackageManager packageManager) {this.mInstrumentation instrumentation;this.mPackageManager packageManager;}public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {ListResolveInfo resolveInfo mPackageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL);//判断启动的插件Activity是否在AndroidManifest.xml中注册过if (null resolveInfo || resolveInfo.size() 0) {//保存目标插件intent.putExtra(HookHelper.REQUEST_TARGET_INTENT_NAME, intent.getComponent().getClassName());//设置为占坑Activityintent.setClassName(who, replugin.StubActivity);}try {Method execStartActivity Instrumentation.class.getDeclaredMethod(execStartActivity,Context.class, IBinder.class, IBinder.class, Activity.class,Intent.class, int.class, Bundle.class);return (ActivityResult) execStartActivity.invoke(mInstrumentation, who, contextThread, token, target, intent, requestCode, options);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return null;}public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException,IllegalAccessException, ClassNotFoundException {String intentName intent.getStringExtra(HookHelper.REQUEST_TARGET_INTENT_NAME);if (!TextUtils.isEmpty(intentName)) {return super.newActivity(cl, intentName, intent);}return super.newActivity(cl, className, intent);}}
复制代码InstrumentationProxy类继承类Instrumentation实现了类execStartActivity方法接着通过反射去用原始Instrumentation的execStartActivity方法这就是替换为占坑Activity的过程。Activity的创建是在ActivityThread中里面有个performLaunchActivity方法 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...try {java.lang.ClassLoader cl appContext.getClassLoader();activity mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state ! null) {r.state.setClassLoader(cl);}}...activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);...
}
复制代码这里的newActivity就是创建Activity的过程我们同样的在代理类中去实现这个方法这就是还原插件Activity 的过程。 接下来我们看个例子 占位坑Activity public class StubActivity extends BaseActivity {Overridepublic int bindLayout() {return R.layout.activity_stub;}Overridepublic void initViews() {}Overridepublic void onClick(View v) {}
}
复制代码这个Activity一定是需要在AndroidManifest中去注册。 再写一个插件Activity public class TargetActivity extends BaseActivity {Overridepublic int bindLayout() {return R.layout.activity_target;}Overridepublic void initViews() {}Overridepublic void onClick(View v) {}
}
复制代码都是很简单的ActivityTargetActivity并没有注册现在我们需要启动这个Activity。代理类上面代码已经贴出来了。接下来就是替换代理类达到Hook的目的我们在Application中做这个事情 public class MyApplication extends Application {Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);hookActivityThreadInstrumentation();}private void hookActivityThreadInstrumentation() {try {Class? activityThreadClassClass.forName(android.app.ActivityThread);Field activityThreadFieldactivityThreadClass.getDeclaredField(sCurrentActivityThread);activityThreadField.setAccessible(true);//获取ActivityThread对象sCurrentActivityThreadObject activityThreadactivityThreadField.get(null);Field instrumentationFieldactivityThreadClass.getDeclaredField(mInstrumentation);instrumentationField.setAccessible(true);//从sCurrentActivityThread中获取成员变量mInstrumentationInstrumentation instrumentation (Instrumentation) instrumentationField.get(activityThread);//创建代理对象InstrumentationProxyInstrumentationProxy proxynew InstrumentationProxy(instrumentation,getPackageManager());//将sCurrentActivityThread中成员变量mInstrumentation替换成代理类InstrumentationProxyinstrumentationField.set(activityThread,proxy);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
复制代码这样就把原始的Instrumentation替换为代理的了具体的操作我们在InstrumentationProxy中去做实现。接下来我们就是从主界面跳转插件Activity了 public class PluginActivity extends BaseActivity {Overridepublic int bindLayout() {return R.layout.activity_stub;}Overridepublic void initViews() {Log.d(, initViews: );findViewById(R.id.btn_start_replugin).setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {startActivity(new Intent(PluginActivity.this, TargetActivity.class));}});}Overridepublic void onClick(View v) {}public static void startActivity(Context context) {Intent i new Intent(context, PluginActivity.class);context.startActivity(i);}}
复制代码转载于:https://juejin.im/post/5c67da6251882562547b99ab