本文主要对早期的阿里加固方式进行了一些梳理
最近一直在分析安卓加固的方案,对很多知识都不太懂,一个偶然的机会在论坛上看到寒号鸟二代师傅的一篇仿ali加固一个早期的加固方案(https://bbs.pediy.com/thread-215078.htm),于是花了一段时间来分析这个项目实现流程,遂写下这篇文章,希望对学习jni编程和安卓dex文件运行流程的师傅们有帮助,同时也欢迎各位师傅们提出建议。
完成分析之后,我使用AS3.5的环境下编写了一个加固项目,项目地址如下:https://github.com/lzh18972615051/ShellCode1,Readme.md里面含有使用方法,欢迎各位Star和Fork
java层仅有有一个StubApplication.java类,该类加载的onCreate方法和attachBaseContext方法均放在了native层
首先自然是对attachBaseContext和onCreate进行了动态注册
阅读安卓相关源码可以知道,Application的attachBaseContext方法是早于onCreate方法执行的:
init_class与myFindClass结合初始化所有可能用到的变量,并对安卓虚拟机运行模式进行判断:
通过native层的反射,生成相关的文件夹,存放源apk所含有的所有文件,同时获取必要的apk包名等等,同时构建临时内存空间的字符串
该函数调用资源管理器对象,打开apk资源文件目录下的源dex文件,将其进行解密操作,并把解密后的dex文件存放到临时的目录中去
加载模式一共有两种art模式和dvm模式,详细原理将会在下面说明
在介绍完之后,我们在对attachBaseContext执行的流程和原理进行一次剖析
显然在加固的过程中由于attachBaseContext的加载早于各个组件的创建过程,因此我们会选择attachBaseContext作为加载源dex地方
首先为了能够顺利的加载源apk程序,我们需要创建apk文件对应的各种文件夹,在将相关的文件放入其中,然后分配一个临时的内存空间/data/data/<包名>/files/dump.dex,并将待加载的dex(已加密,存放在资源文件下)解密后,写入到该临时空间中
将dex文件解密之后,我们需要读取临时空间,将该空间中的dex文件映射到内存中进行加载,根据不同的安卓虚拟机,我们会采取不同的加载方式,例如dvm模式下,采用Dalvik_dalvik_system_DexFile_openDexFile_bytearray
函数,与其对应的还有一个函数Dalvik_dalvik_system_DexFile_openDexFileNative
二者同样都能实现dex文件的加载,然而我们却选择了前者,一个很重要的原因就是,Dalvik_dalvik_system_DexFile_openDexFile_bytearray
相较于后者不会暴露待加载dex文件所在的位置,通过其源码比较:
openDexFileNative:
bytearray:
二者最大的区别在于bytearray函数进行dex加载时,是对已经映射到内存中dex文件的字节数组进行的加载,而openDexFileNative会要求使用到dex文件的路径,这种操作对于早期的壳来说,时间十分致命的事情,破解者可以轻松的找到被解密的dex存放的路径,然后轻松的将其dump出来,大大的降低了软件壳的安全性,因此我们采用的是bytearray函数
而art模式下,由于安卓源码没有提供较好的加载方法,在加上贾荣祥等考虑,我们采用了其openDexFile函数来实现dex文件的加载,该函数在前面的初始化中已经获取了其ID值,现在只需要进行调用即可
一旦通过LoadedApk的马克Application方法创建Application对象Application app=(Application)clazz.newInstance();
,就一定会调用到Application方法中的attach()方法,进而就会调用到attachBaseContext()方法,因此只要在壳程序的Application类中重写这一个方法,并在此处解密源dex文件,再用DexClassLoader进行动态加载,然后替换跳LoadedApk中默认的类加载器为自定义的类加载器,那么就能使壳apk加载源dex了,而要想替换掉当前的类加载器,我们只需要替换掉其mCookie成员变量即可,
那么如何替换掉mCookie呢,我们再深挖安卓源码发现每一个Android应用启动后,都会有一个对应的ActivityThread对象实例来管理,dex文件都是以ClassLoader对象的实例被ActivityThread对象进行管理的,然后我们再剖析DexClassLoader源码发现,每一个DexClassLoader对象的实例都是通过DexPathList列表存储dex文件相关信息的,而其中一个含有一个重要的结构体DexFile,DexFile的成员变量之一就是mCookie,分析到这里,我们就找到了mCookie所在的地方
分析安卓源码发现在替换掉类加载器后,还需要替换掉一些对象,例如需要将待加载dex的application对象替换掉壳application对象
除了mApplication,我们还需要修改4处Application的实例对象的成员变量
为了修改该参数,我们通过分析源码找到了一个变量mPackages
mPackages是ActivityThread的一个非静态成员变量,在函数中的定义如下
我们通过获取该成员变量就能获取LoadedApk对象,进而就能获取到LoadedApk的非静态成员变量mApplication,最后将其替换成源dex文件的Application实例对象
修改壳apk应用的ActivityThread实例对象的成员变量mBoundApplication中的LoadApk非静态成员变量info实例对象的实例成员变量mApplication为源dex的Application对象
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!