S1mba 发表于 2020-10-18 10:44

第一二代壳的编写中资源加载的问题

最近想学习写壳,在网上看了很多教程,但是他们的demo都没有提到资源加载的问题。我的demo运行后会出现找不到layout的问题。报错如下

然后我的加载资源代码如下:

资源在这里替换:

实际运行中看log发现原APK确实用的是我加载的资源,但就是无法找到layout

如图TAG是提示的是脱壳Application的log
TAG是demo的是原APK的log
可以看到资源应该已经被替换成功了啊
代码:

public class ProxyApplication extends Application {

    public String apkName;
    public String dexPath;
    public String libPath;

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void attachBaseContext(Context base) {
      super.attachBaseContext(base);
      Log.i("提示:", "进入attachBaseContext方法!");
      try {
//            File dex = this.getDir("payload_odex", MODE_PRIVATE);
//            File lib = this.getDir("payload_lib", MODE_PRIVATE);
//            dexPath = dex.getAbsolutePath();
//            libPath = lib.getAbsolutePath();
//            apkName = dex.getAbsolutePath() + "/shell.apk";
//            File dexFile = new File(apkName);
//            if (!dexFile.exists()) {
//                dexFile.createNewFile();
//                byte[] dexdata = this.readDexFileFromApk();
//
//                // 分离出解壳后的apk文件已用于动态加载
//                this.splitPayLoadFromDex(dexdata);
//            }

            String filesDir = this.getCacheDir().getAbsolutePath();
            Log.i("提示:", filesDir);
            apkName = filesDir + File.separator + "srcapk.apk";
//            String dexPath = filesDir + File.separator + "srcapk.dex";

            Object activityThreadObject = RefinvokeMethod.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
            String shellPackageName = this.getPackageName();
            ArrayMap mPackages = (ArrayMap) RefinvokeMethod.getField("android.app.ActivityThread", activityThreadObject, "mPackages");
            WeakReference wr = (WeakReference) mPackages.get(shellPackageName);
            ClassLoader oldCl = (ClassLoader) RefinvokeMethod.getField("android.app.LoadedApk", wr.get(), "mClassLoader");
            DexClassLoader dcl = new DexClassLoader(apkName, filesDir, null, oldCl);
            RefinvokeMethod.setField("android.app.LoadedApk", "mClassLoader", wr.get(), dcl);
            Log.i("提示:", "类加载已被替换成自定义的Dex加载器!");
            try {
                Object objectMain = dcl.loadClass("com.example.forceversion.MainActivity");
                Log.i("提示:", "MainActivity.java类加载完毕!");
            } catch (Exception e) {
            }
      } catch (Exception e) {
            Log.i("提示:", "load apk classloader error:" + Log.getStackTraceString(e));
      }
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onCreate() {
      super.onCreate();
      Log.i("提示:", "进入onCreate方法!");
      Log.i("提示:", "basecontext:" + this.getBaseContext());
      Log.i("提示:", "context:" + this.getApplicationContext());
      Log.i("提示:", "资源0:" + this.getApplicationContext().getResources());
      loadResources(apkName);
      String applicationName = "";
      ApplicationInfo ai = null;
      try {
            ai = this.getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
            applicationName = ai.metaData.getString("ApplicationName");
            Log.i("提示:", "成功获取到apk的application名称" + applicationName);
      } catch (Exception e) {
      }

      Object ActivityThreadObj = RefinvokeMethod.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
      Object mBoundApplication = RefinvokeMethod.getField("android.app.ActivityThread", ActivityThreadObj, "mBoundApplication");
      Object info = RefinvokeMethod.getField("android.app.ActivityThread$AppBindData", mBoundApplication, "info");

      RefinvokeMethod.setField("android.app.LoadedApk", "mApplication", info, null);
      Object minitApplication = RefinvokeMethod.getField("android.app.ActivityThread", ActivityThreadObj, "mInitialApplication");
      ArrayList<Application> mAllApplications = (ArrayList<Application>) RefinvokeMethod.getField("android.app.ActivityThread", ActivityThreadObj, "mAllApplications");
      mAllApplications.remove(minitApplication);
      ApplicationInfo mApplicationInfo = (ApplicationInfo) RefinvokeMethod.getField("android.app.LoadedApk", info, "mApplicationInfo");
      ApplicationInfo appInfo = (ApplicationInfo) RefinvokeMethod.getField("android.app.ActivityThread$AppBindData", mBoundApplication, "appInfo");

      mApplicationInfo.className = applicationName;
      appInfo.className = applicationName;

      Application app = (Application) RefinvokeMethod.invokeMethod("android.app.LoadedApk", "makeApplication", info, new Class[]{boolean.class, Instrumentation.class}, new Object[]{false, null});
      Context mBase = (Context) RefinvokeMethod.invokeMethod("android.app.Application","getBaseContext",app,new Class[]{}, new Object[]{});
      RefinvokeMethod.setField("android.app.ContextImpl","mResources",mBase,mResources);

      Log.i("提示:", "app: " + app);
      RefinvokeMethod.setField("android.app.ActivityThread", "mInitialApplication", ActivityThreadObj, app);

      ArrayMap mProviderMap = (ArrayMap) RefinvokeMethod.getField("android.app.ActivityThread", ActivityThreadObj, "mProviderMap");
      Iterator it = mProviderMap.values().iterator();

      while (it.hasNext()) {
            Object mProviderClientRecord = it.next();
            Object mLocalProvider = RefinvokeMethod.getField("android.app.ActivityThread$ProviderClientRecord", mProviderClientRecord, "mLocalProvider");
            RefinvokeMethod.setField("android.content.ContentProvider", "mContext", mLocalProvider, app);
      }

      Log.i("提示:", "反射application完成,准备拉起源apk!");


      Log.i("提示:", "context:" + this.getApplicationContext());
      Log.i("提示:", "资源1:" + this.getApplicationContext().getResources());
      app.onCreate();
      Log.i("提示:", "源apk成功拉起!脱壳完毕!");

    }

    protected AssetManager mAssetManager;
    protected Resources mResources;


    protected void loadResources(String dexPath) {
      try {
            Class cls = Class.forName("android.content.res.AssetManager");
            AssetManager assetManager = (AssetManager) cls.getConstructor().newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, dexPath);
            mAssetManager = assetManager;
            mResources = new Resources(assetManager, super.getResources().getDisplayMetrics(),
                  super.getResources().getConfiguration());

      } catch (Exception e) {
            Log.i("提示:", "loadResource error:" + Log.getStackTraceString(e));
            e.printStackTrace();
      }

      Log.i("提示:", "资源加载完毕!" + mResources);
    }
}


没有将APK写进dex是为了方便
页: [1]
查看完整版本: 第一二代壳的编写中资源加载的问题