在上一篇文章中已经分享了,apk加固的整体思路和具体的实现,在上一篇文章中还有一个问题没有分享完,在apk加固后,主App的Application是已经没有作用了,所以这次主要是分享如果让主App的Application可以正常的使用。
https://www.jianshu.com/p/e836428d61b9 apk加固实现原理(一)
Application的创建
要解决主App的Application不生效的问题,首先得先搞清楚Application是在哪里创建的。main方法是所有程序的入口;在Android的应用中main方法是在ActivityThread中,所以Application就是在ActivityThread中被创建出来的。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...............................
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
............................................
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
.................................
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
每一个应用的Application都是在performLaunchActivity的方法中被创建出来的,在上面的源码中也可以看到,先是Activity被创建出来后;Application才被创建出来,这里也是有一个面试点:是Activity被创建先还是Application被创建先,很多没有看过源码的人都是觉得是Application先创建出来,其实不是这样的,Activity被创建出来只是还没有走生命周期,Application的生命周期先调用。
Application的生命周期与Application替换
Applicationt的生命周期主要有两个,一个是onCreate、另外一个是attachBaseContext,其它的几个很少用得上,这里先不描述。在Application被创建出来后第一个走的生命周期是:attachBaseContext然后再走onCreate这样一个App的Application就创建完成了。
在attachBaseContext中已经有将解密出来的dex交给系统处理了,在第一篇文章中已经分享过,这里就不具体描述了,ProxyApplication在onCreate的时候要将主App的Application创建出来,并替换系统中的Application引用,如果不替换则还是ProxyApplication的引用,则在App调用Application是就会出错,最后回调主App的Application的onCreate方法完成替换。
通过对源码的查看,可以看到ActivityThread中有两个全局变量需要要替换。一个是Application的成员变量、另外一个是集合中的。
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
以上是ActivityThread中要替换成主App的Application。
接下来就是LoadedApk,LoadedApk里面有一个全局变量的Application也是需要替换
private Application mApplication;
以上这些替换的Application需要使用反射来进行替换,当前替换完成后再主动调用主 App的Application这样就达到目的了
private void replaceApplication() throws Exception{
//得到attachBaseContext的上下文
Log.d(TAG,"app_name:"+app_name);
Context baseContext = getBaseContext();
//创建真实的Application
Class<?> delegateClass = Class.forName(app_name);
delegate = (Application) delegateClass.newInstance();
Method attach = Application.class.getDeclaredMethod("attach",Context.class);
attach.setAccessible(true);
attach.invoke(delegate,baseContext);
//设置ContextImp中的setOuterContext
Class<?> contextImpClass = Class.forName("android.app.ContextImpl");
Field mOuterContextFileId = contextImpClass.getDeclaredField("mOuterContext");
mOuterContextFileId.setAccessible(true);
mOuterContextFileId.set(baseContext, delegate);
Field mMainThreadFieId = contextImpClass.getDeclaredField("mMainThread");
mMainThreadFieId.setAccessible(true);
Object mMainThread = mMainThreadFieId.get(baseContext);
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication");
mInitialApplicationField.setAccessible(true);
mInitialApplicationField.set(mMainThread, delegate);
Field mAllApplicationsFieId = activityThreadClass.getDeclaredField("mAllApplications");
mAllApplicationsFieId.setAccessible(true);
ArrayList<Application> mAllApplications = (ArrayList<Application>) mAllApplicationsFieId.get(mMainThread);
mAllApplications.remove(this);//把代理的Application移除
mAllApplications.add(delegate);
Field mPackageInfoFieId = contextImpClass.getDeclaredField("mPackageInfo");
mPackageInfoFieId.setAccessible(true);
Object mPackageInfo = mPackageInfoFieId.get(baseContext);
Class<?> loadApkClass = Class.forName("android.app.LoadedApk");
Field mApplicationFieId = loadApkClass.getDeclaredField("mApplication");
mApplicationFieId.setAccessible(true);
mApplicationFieId.set(mPackageInfo, delegate);
//修改className
Field mApplicationInfoFieId = loadApkClass.getDeclaredField("mApplicationInfo");
mApplicationInfoFieId.setAccessible(true);
ApplicationInfo mApplicationInfo = (ApplicationInfo) mApplicationInfoFieId.get(mPackageInfo);
mApplicationInfo.className = app_name;
delegate.onCreate();
isReplace = true;
}
以上就是Apk加固的原理分析全部过程了,如果在大家看到有哪里搞错了欢迎指正,毕竟个人能力有限。
网友评论