第一二代壳的编写中资源加载的问题
最近想学习写壳,在网上看了很多教程,但是他们的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]