首页
社区
课程
招聘
[求助]第一二代壳编写中的资源加载问题
发表于: 2020-10-18 10:47 3737

[求助]第一二代壳编写中的资源加载问题

2020-10-18 10:47
3737

最近想学习写壳,在网上看了很多教程,但是他们的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 {
 
            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里是为了方便


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
一个是AssetsManager,一个是Resource的cache,另外资源加密对动画无效(避免用动画)。不过这种落地资源加载,可以但没必要。
2020-10-19 08:05
0
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
另外Instrument需要替换成自己的,否则无法启动活动,Activity跟Service的attach可以用hook之类的方法使得attach的Application为真实application,否则一样崩溃。
2020-10-19 08:09
0
雪    币:
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
lhxdiao 一个是AssetsManager,一个是Resource的cache,另外资源加密对动画无效(避免用动画)。不过这种落地资源加载,可以但没必要。
可以详细一点吗?我在网上找的资料都是说自己弄一个资源替换上去即可。为什么没有必要加载资源呢?不加载一样运行不了呀。这方面有什么比较新的资料吗?我看网上的代码都是这个方法但我的就是运行不了。MainActivity可以进去就是不能setContentView。另外十分感谢您的回复!
2020-10-19 10:49
0
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
wx_Simba 可以详细一点吗?我在网上找的资料都是说自己弄一个资源替换上去即可。为什么没有必要加载资源呢?不加载一样运行不了呀。这方面有什么比较新的资料吗?我看网上的代码都是这个方法但我的就是运行不了。MainAc ...
简单一点的是代理packagemanager并createPackageContext(替换apk路径),里面设置include code。复杂一点的是我说的方法,同样都需要代理Instrument。代理package manager参考签名验证劫持破解的那种代理,参考https://blog.csdn.net/wangbole/article/details/22876179,很多插件化都是基于这种实现的。
2020-10-20 15:25
0
雪    币: 1636
活跃值: (653)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
这种活动需要在壳里面声明,不如就会提示activity没有注册
2021-3-31 17:18
0
雪    币: 5330
活跃值: (5464)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
这种,核心注意去加载资源的context
2021-3-31 17:54
0
游客
登录 | 注册 方可回帖
返回
//