1.为什么做加固
因为不想辛辛苦苦做的东西,被别人拿去改成各种版,半路摘我的桃子。
2.怎么加固
2.1 简单的加固
三方加固,有些三方会有免费版本的加固服务
比如 腾讯加固
2.2 深度复杂加固,
为啥要深度复杂加固呢,因为三方的免费版的简单加固只会对代码进行加固,资源和so库还是一目了然的放在那里。
如果想将资源和so库加固,可以使用三方付费版,
当然也可以自己做
为啥要自己做呢?
因为贵啊,n * W/年/APP,一个应用一年就要几万。
3.自己做加固
花了些时间,参考各种资料,实现了代码APP加固。
3.1 主要原理
3.1.1 代码加固
Android能够使用apk文件或dex文件动态加载Classloader
实现原理:将代码dex加密,使用时解密,然后加载成Classloader使用。
/**
* 将dex注入dexElements数组中
* @param context
* @param str
* @throws ClassNotFoundException
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public static void changeAppClassLoader(Context context, String str) throws Throwable {
PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
PathClassLoader classLoader = new PathClassLoader(str,null,context.getClassLoader());
Object a = combineArray(getDexElements(getPathList(pathClassLoader)), getDexElements(getPathList(classLoader)));
Object a2 = getPathList(pathClassLoader);
setField(a2, a2.getClass(), "dexElements", a);
}
3.1.2 资源加固
Android同样提供了api,开发者能使用apk路径加载成resource
实现原理:将资源apk加密,使用时解密,然后加载成Resource使用
private Resources preloadResource(Context context, String apkFilePath) {
try {
Class<? extends AssetManager> AssetManagerClass = AssetManager.class;
AssetManager assetManager = AssetManagerClass.newInstance();
@SuppressLint("DiscouragedPrivateApi")
Method addAssetPathMethod = AssetManagerClass.getDeclaredMethod("addAssetPath", String.class);
addAssetPathMethod.setAccessible(true);
addAssetPathMethod.invoke(assetManager, apkFilePath);
Resources baseResources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
return baseResources;
} catch (Throwable e) {
}
return null;
}
3.1.3 so库加固
实现原理:将so加密,使用时解密。需要动态替换应用so路径为解密后的so路径
private void changeFilePath(Context context, String newSoPath) {
try {
Class<?> contextImplClass = classNamefor("android.app.ContextImpl");
Class<?> loadedApkClass = classNamefor("android.app.LoadedApk");
Object mPackageInfo = getFieldValue(contextImplClass, "mPackageInfo", context);
ApplicationInfo mApplicationInfo = null;
mApplicationInfo = (ApplicationInfo) getFieldValue(loadedApkClass, "mApplicationInfo", mPackageInfo);
mApplicationInfo.nativeLibraryDir = newSoPath;
} catch (Throwable emApplicationInfo) {
}
}
3.2 整体实现
将真实的apk(子包)进行加密,壳包启动时,动态根据子包apk解密,加载出Classloader和Resource,并获得so路径(可以将so库单独抽出来)
将系统的Classloader,Resource,so路径替换为生成的。
4 总结
目前已实现,并在多个包上使用这套技术。
5 联系作者
期待你的点赞和关注!如有疑问,联系作者。