电商网站的费用怎么做帐,深圳市住房和建设局工程交易平台,西宁网络推广与营销,正品二手手表交易网一、APP启动流程(结合源码分析)
当我们点击APP图标#xff0c;到APP运行启动#xff0c;中间经历了怎样的过程#xff1f;可以用一张图来概括#xff1a;
首先启动Activity/Service#xff0c;(Activity、Service是什么#xff1f;四大组件#xff1a;Activity、Serv…一、APP启动流程(结合源码分析)
当我们点击APP图标到APP运行启动中间经历了怎样的过程可以用一张图来概括
首先启动Activity/Service(Activity、Service是什么四大组件Activity、Service、BroadCast Recevicer、Content provider)通知system_server进程然后以Binder的方式通知Zygote进程最终进入ActivityThread.main()开始进入APP世界的大门。
我们打开http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/app/ActivityThread.java对ActivityThread进行源码分析了解启动流程。
ActivityThread是单例创建sCurrentActivityThread是全局创建的ActivityThread实例。其中currentActivityThread()是静态方法可以返回我们当前创建的ActivityThread。 ActivityThread.main()函数是java中的入口main函数这里会启动主消息循环创建ActivityThread实例之后调用thread.attach(false)完成一系列初始化准备工作。之后主线程进入消息循环(bindleMessage函数)等待接收来自系统的消息。
当收到系统发送来的bindapplication的进程间调用时调用handlebindapplication来处理该请求。
还有ArrayMap类型的mPackages变量需要注意下这是加载APP存放的内容LoadApk函数如下 我们获取mPackages和包名就可以获取动态加载的APP包内容这后面会用到。
接下来我们看下handleBindApplication函数内容比较多。 学习寒冰大佬的说法这个函数主要完成以下的任务。
private void handleBindApplication(AppBindData data) {//step 1: 创建LoadedApk对象data.info getPackageInfoNoCheck(data.appInfo, data.compatInfo);...//step 2: 创建ContextImpl对象;final ContextImpl appContext ContextImpl.createAppContext(this, data.info);//step 3: 创建InstrumentationmInstrumentation new Instrumentation();//step 4: 创建Application对象;在makeApplication函数中调用了newApplication在该函数中又调用了app.attach(context)在attach函数中调用了Application.attachBaseContext函数Application app data.info.makeApplication(data.restrictedBackupMode, null);mInitialApplication app;//step 5: 安装providersListProviderInfo providers data.providers;installContentProviders(app, providers);//step 6: 执行Application.Create回调mInstrumentation.callApplicationOnCreate(app);在handleBindApplication函数中第一次进入了app代码世界该函数启动了一个application并把apk组件等相关信息绑定到application里在创建完application对象后接着调用了application的attachBaseContext方法之后调用了application的onCreate函数。
正常APP启动过程
由此可见attachBaseContext和onCreate是最先获取代码执行权的这也是为什么各家的加固工具主要逻辑都是替换app入口Application并自实现这两个函数。这也是为什么在这两个地方进行脱壳的原因。
加壳APP运行流程
加壳APP运行过程 壳要做的工作有
1、要对原先APP的dex进行解密
2、初始化自定义类加载器
3、替换LoadApk中的加载器为自定义加载器。
上一篇文章讲述了如何调用加载其他dex内的方法那么如果我想调用dex内的其他Activity能不能用同样的方法能不能行得通呢
上代码截图
然后build提取APK的classes.dexadb push到手机上
adb push classes.dex /sdcard/4.dex然后新建工程赋予读写存储卡权限写入 调用读取4.dex的TestActivity方法那么很快啊就会显示报错无法调用。
究其原因是什么呢因为Activity不像是上篇文章中的函数方法Activity具有生命周期和相关组件信息只有当classloader被修正后才能正确加载被解密后的dex类和方法。顺便提一点壳在函数attachBaseContext和onCreate中完成对加密的dex文件的解密。
修复classloader
如何修正呢
有两种方法
方法一通过层层反射拿到mPackage内容然后根据报名通过LoadApk获取APP内的类加载器最终使用自定义类加载器进行替换。方法二利用双亲委派机制在BootClassloader和PathClassloader中插入我们自定义的类加载器完成修复。
方法一 根据java的反射和开源的java代码进行一步步反射。(可对照androidxref逐步理解以下代码)
然后在原先的基础上调用replaceClassloader即可。 方法二 public void startTestActivitySecondMethod(Context context,String dexfilepath){File optfilecontext.getDir(opt_dex,0);File libfilecontext.getDir(lib_path,0);ClassLoader pathClassloaderMainActivity.class.getClassLoader();ClassLoader bootClassloaderMainActivity.class.getClassLoader().getParent();//这里的改变MainActivity.class.getClassLoader()变成bootClassloader意思是这里的DexClassLoader直接向BootClassLoader汇报的DexClassLoader dexClassLoadernew DexClassLoader(dexfilepath,optfile.getAbsolutePath(),libfile.getAbsolutePath(),bootClassloader);try {Field parentFieldClassLoader.class.getDeclaredField(parent);parentField.setAccessible(true);//把pathclassloader插入我们的dexClassLoaderparentField.set(pathClassloader,dexClassLoader);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}
/*
* this:dalvik.system.PathClassLoader[DexPathList[[zip file /data/app/com.kanxue.loaddex-8_fCxispeBuExjw1ryrRZg/base.apk],nativeLibraryDirectories[/data/app/com.kanxue.loaddex-8_fCxispeBuExjw1ryrRZg/lib/arm64, /system/lib64, /vendor/lib64]]]--parent:dalvik.system.DexClassLoader[DexPathList[[dex file /sdcard/6.dex],nativeLibraryDirectories[/data/user/0/com.kanxue.loaddex/app_lib_path, /system/lib64, /vendor/lib64]]]
this:dalvik.system.DexClassLoader[DexPathList[[dex file /sdcard/6.dex],nativeLibraryDirectories[/data/user/0/com.kanxue.loaddex/app_lib_path, /system/lib64, /vendor/lib64]]]--parent:java.lang.BootClassLoaderfd4323d
root:java.lang.BootClassLoaderfd4323d*//** PathClassLoader DexClassLoader BootClassLoader* */ClassLoader tmpClassloaderpathClassloader;ClassLoader parentClassloaderpathClassloader.getParent();while(parentClassloader!null){Log.i(kanxue,this:tmpClassloader--parent:parentClassloader);tmpClassloaderparentClassloader;parentClassloaderparentClassloader.getParent();}Log.i(kanxue,root:tmpClassloader);Class? clazznull;try {clazz dexClassLoader.loadClass(com.kanxue.test02.TestActivity);} catch (ClassNotFoundException e) {e.printStackTrace();}context.startActivity(new Intent(context,clazz));}壳工作方式
而第一种方式是加壳厂商经常会用的方式也就是通过自定义dexclassloader对原先的类加载器进行替换修复。
这里还分为两种情况一种是原始的APP没有自定义Application子类那么这种情况比较简单直接替换壳的Application即可。
另一种情况是原始APP定义了Application子类那么壳Application的工作就不仅仅是进行解密、类加载器修复等工作了还有对解密后的DEX原始的Application的方法和类重新进行处理保证整个过程运行顺畅。
我们可以看AndroidManifest.xml内的主Application是否被替换为壳Application入口就可以了解到同时观察壳Application的汇编代码会发现进行了大量的修复。
Reference
https://bbs.pediy.com/thread-252630.htm