加密算法很简单,只是对每个字节进行异或一下 。
这里是为了简单,所以就用了很简单的加密算法,其实为了增加破解难度,我们应该使用更高效的加密算法,同时最好将加密操作放到native层去做 。
这里需要两个输入文件:
- 源程序APK文件:SourceApk.apk
- 壳程序的DEX文件:SourceApk.dex
第一个文件就是源程序项目编译之后的APK文件,第二个文件是下面要讲的第三个项目:壳程序项目中的classes.dex文件,修改名称之后得到 。3.壳程序项目:PackApk

文章插图
先来了解一下壳程序项目的工作:
- 通过反射置换android.app.ActivityThread中的mClassLoader为加载解密出APK的DexClassLoader,该DexClassLoader一方面加载了源程序,另一方面以原mClassLoader为父节点,这就保证即加载了源程序,又没有放弃原先加载的资源与系统代码 。关于这部分内容不了解的可以看一下Android动态加载之免安装运行程序这篇文章 。
- 找到源程序的Application,通过反射建立并运行 。这里需要注意的是,我们现在是加载一个完整的APK,让他运行起来 。一个APK运行的时候都是有一个Application对象的,这个也是一个程序运行之后的全局类,所以我们必须找到解密之后的源程序APK的Application类,运行它的onCreate方法,这样源程序APK才开始它的运行生命周期 。后面会说如何得到源程序APK的Application类:使用meta标签进行设置 。
下面看一下整体流程:

文章插图
下面看一下代码: ProxyApplication.java
- 得到壳程序APK中的DEX文件,然后从这个文件中得到源程序APK进行解密、加载
// 这是context赋值@Overrideprotected void attachBaseContext(Context base) { super.attachBaseContext(base); try { // 创建两个文件夹payload_odex、payload_lib,私有的,可写的文件目录 File odex = this.getDir("payload_odex", MODE_PRIVATE); File libs = this.getDir("payload_lib", MODE_PRIVATE); odexPath = odex.getAbsolutePath(); libPath = libs.getAbsolutePath(); apkFileName = odex.getAbsolutePath() + "/payload.apk"; File dexFile = new File(apkFileName); Log.i("demo", "apk size:"+dexFile.length()); if (!dexFile.exists()) { dexFile.createNewFile(); //在payload_odex文件夹内,创建payload.apk // 读取程序classes.dex文件 byte[] dexdata = https://www.isolves.com/it/cxkf/ydd/Android/2019-09-04/this.readDexFileFromApk();// 分离出解壳后的apk文件已用于动态加载 this.splitPayLoadFromDex(dexdata); } // 配置动态加载环境 Object currentActivityThread = RefInvoke.invokeStaticMethod( "android.app.ActivityThread", "currentActivityThread", new Class[] {}, new Object[] {});//获取主线程对象String packageName = this.getPackageName();//当前apk的包名 ArrayMap mPackages = (ArrayMap) RefInvoke.getFieldOjbect( "android.app.ActivityThread", currentActivityThread, "mPackages"); WeakReference wr = (WeakReference) mPackages.get(packageName); // 创建被加壳apk的DexClassLoader对象 加载apk内的类和本地代码(c/c++代码) DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath, libPath, (ClassLoader) RefInvoke.getFieldOjbect( "android.app.LoadedApk", wr.get(), "mClassLoader")); //把当前进程的mClassLoader设置成了被加壳apk的DexClassLoader RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader", wr.get(), dLoader);Log.i("demo","classloader:"+dLoader); try{ Object actObj = dLoader.loadClass("com.example.sourceapk.MainActivity"); Log.i("demo", "actObj:"+actObj); }catch(Exception e){ Log.i("demo", "activity:"+Log.getStackTraceString(e)); } } catch (Exception e) { Log.i("demo", "error:"+Log.getStackTraceString(e)); e.printStackTrace(); }}这里需要注意的一个问题,就是我们需要找到一个时机,就是在壳程序还没有运行起来的时候,来加载源程序的APK,执行它的onCreate方法,那么这个时机不能太晚,不然的话,就是运行壳程序,而不是源程序了 。查看源码我们知道 。Application中有一个方法:attachBaseContext这个方法,它在Application的onCreate方法执行前就会执行了,所以我们的工作就需要在这里进行 。A) 从APK中获取到DEX文件
/** * 从apk包里面获取dex文件内容(byte) * @return * @throws IOException */private byte[] readDexFileFromApk() throws IOException { ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream(); ZipInputStream localZipInputStream = new ZipInputStream( new BufferedInputStream(new FileInputStream( this.getApplicationInfo().sourceDir))); while (true) { ZipEntry localZipEntry = localZipInputStream.getNextEntry(); if (localZipEntry == null) { localZipInputStream.close(); break; } if (localZipEntry.getName().equals("classes.dex")) { byte[] arrayOfByte = new byte[1024]; while (true) { int i = localZipInputStream.read(arrayOfByte); if (i == -1) break; dexByteArrayOutputStream.write(arrayOfByte, 0, i); } } localZipInputStream.closeEntry(); } localZipInputStream.close(); return dexByteArrayOutputStream.toByteArray();}
推荐阅读
-
白岩松又出金句,60到80是最好的年龄!惊醒千万老人!
-
体检|雄安新区:“未来之城”拔节生长 “智慧蓝图”轮廓渐明
-
冰变成水最快的方法是什么打一数字 冰变成水最快的方法是什么
-
中国新说唱■从《中国新说唱》到《说唱听我的》,这一次,该他们“火”了
-
大S|85岁马玉琴公园和老头热舞,李玉成反应惹争议,网友:占有欲真强
-
现代快报|返程小高峰来了!江苏高速车多缓行累计超110公里
-
社交障碍|美方考虑关停一些中方社交软件?中国外交部:不要选择性设置障碍
-
-
-
武神 美军一架战机突然坠毁,俄:这不是巧合,伊朗下令舰队逼近美本土
-
「」清明前,钓鱼用2滴,10分钟上鱼,农村大哥靠这个钓鱼能装两大筐
-
梅西|只差8球了!梅西即将打破球王尘封46年纪录,C罗或将成为背景板!
-
微软|日本网友反对微软收购抖音,理由令中国人没想到!
-
湖北首次出现8个0|湖北首次出现8个0!加油!坚持!
-
-
LCK|S10淘汰赛对阵分析:LPL和LCK各凭实力,胜者为王!
-
此间少年|是一种幸福”,简安颜创始人简练:“成为自己想成为的人
-
-
ZAKER精选|那潜力新星王泉泽呢?林书豪晒出了1大好消息!,张镇麟在CBA大放异彩
-