最近刚开始接触Andorid加固,是从姜维前辈在2015年的一些帖子开始学习的,同时也从个别恶意样本中学到了其他的加固手段。
虽然本帖子涉及到的知识大概都是第一代或者第二代加固,对于大佬们来说已经是“陈年旧识”了,但对于本菜鸡来说,依旧还是一个新世界~
在进入这个新世界的时候,虽然有姜维前辈的帖子为导,但总有一些不适用的地方,比如其加固so文件的section帖子对Android7不完全使用的问题等,so文件的大小端问题;
且由于本人学习过程中未完全照搬姜维前辈的代码,故过程中也遇到了些问题,如加固后可成功运行原apk的组件但依旧显示壳信息等问题;
同时,对于姜维前辈一笔带过或者没解释的知识点,我在学习过程中也进行了些补充。
具体的,都会在下面呈现出来。
(看姜维前辈的帖子,感悟最深的就是“万物皆可二进制”。。。)
目录:
1、在java层为.apk文件进行加固
1.0、学习资料
1.1、Android壳原理
1.1.1、 Dex文件基础知识
1.2、加固
1.2.1、 原理
1.2.2、 操作
1.3、实践
1.3.1、 基础操作
准备待加壳apk
加壳程序
脱壳程序
合体操作流程
1.3.2、 注意事项
2、在native层为.dex文件进行加固
2.1、壳原理
2.1.1、 大致流程
2.2、 样本分析
3、在native层为.so文件进行加固
3.0、学习资料
3.1、加密so的section
3.1.1、 原理
3.1.2、 实践
3.2、加密so的函数
3.2.1、原理
3.2.2、 实践
3.3、两者比较
4、3者比较
《Android加固原理研究》:https://blog.csdn.net/jiangwei0910410003/article/details/48415225
需补充前期知识:
(1)《动态加载技术解读》:https://blog.csdn.net/jiangwei0910410003/article/details/17679823
(2)《Java高新技术第一篇:类加载器详解》:https://blog.csdn.net/jiangwei0910410003/article/details/17733153
(3)《类加载器分析》:http://blog.csdn.net/jiangwei0910410003/article/details/41384667
(4)《资源加载问题(换肤原理解析)》:http://blog.csdn.net/jiangwei0910410003/article/details/47679843
(5)《动态加载Activity(免安装运行程序)》:http://blog.csdn.net/jiangwei0910410003/article/details/48104455
1、 学习资料:
(1)《Android加固原理研究》:https://juejin.im/entry/5a5c55426fb9a01c9f5b65ed
1、学习资料:
(1)《Android中的Apk的加固(加壳)原理解析和实现》:https://blog.csdn.net/jiangwei0910410003/article/details/48415225
2、加固原理图:
3、加固的核心:
如何将源Apk和壳Apk进行合并成新的Dex。
4、核心原理:
只要关注上面红色标记的三个部分:
(1) checksum
文件校验码 ,使用alder32 算法校验文件除去 maigc ,checksum 外余下的所有文件区域 ,用于检查文件错误 。
(2) signature
使用 SHA-1 算法 hash 除去 magic ,checksum 和 signature 外余下的所有文件区域 ,用于唯一识别本文件 。
(3) file_size
Dex 文件的大小 。
(4)原因:
要将一个文件(加密之后的源Apk)写入到脱壳Dex中,那么需要修改脱壳Dex的文件校验码(checksum).因为它是检查文件是否有错误。那么signature也是一样,也是唯一识别文件的算法。还有就是需要修改脱壳dex文件的大小。此外,还需要一个操作,就是标注一下加密的Apk的大小,因为在脱壳的时候,需要知道加密后的源Apk的大小,才能正确的得到加密后的源Apk。这个值直接放到文件的末尾就可以了。这样,就生成了一个壳dex文件。(脱壳dex追加源apk、源apk大小,并修改脱壳dex头部,从而生成了壳dex文件。)
即:修改Dex的三个文件头,将源Apk的大小追加到壳dex的末尾就可以了。
修改之后得到新的Dex文件样式如下:
对应涉及到三个工程:
(1)源程序项目(需要加密的Apk)
(2)脱壳项目(解密源Apk和加载Apk)
(3)对源Apk进行加密和脱壳项目的Dex的合并
1、代码流程:
(1)编写源程序项目,该项目需含有application类,生成origin.apk;
(2)编写脱壳程序项目,以生成“脱壳dex文件”:
(a)原理:通过反射置换android.app.ActivityThread 中的mClassLoader为加载解密出APK的DexClassLoader,该DexClassLoader一方面加载了源程序、另一方面以原mClassLoader为父节点,这就保证了即加载了源程序又没有放弃原先加载的资源与系统代码。随后找到源程序的Application,通过反射建立并运行。这里需要注意的是,我们现在是加载一个完整的Apk,让他运行起来,那么我们知道一个Apk运行的时候都是有一个Application对象的,这个也是一个程序运行之后的全局类。所以我们必须找到解密之后的源Apk的Application类,运行的他的onCreate方法,这样源Apk才开始他的运行生命周期。这里我们如何得到源Apk的Application的类呢?从源Apk的Androidmanifest.xml文件的meta标签获取源程序apk中的application对象。
(b)操作:从脱壳程序apk中找到源程序apk,并进行解密操作;从源程序apk中获取dex文件、so文件;在脱壳程序的application中的oncreate方法中执行操作,找到源程序的application程序,让其运行;需在脱壳程序的AndroidManifest.xml中声明一下源程序中的Activity。
(3)编写加壳程序项目:
(a)以二进制形式读取origin.apk文件形成数据流dataA,并获取该文件的大小sizeA;
(b)以二进制形式读取脱壳dex文件形成数据流dataB,并获取该文件的大小sizeB;
(c)采用自定义的加密方法,对数据流dataA进行加密,即加密origin.apk文件,形成数据流dataC;
(d)设置壳dex的大小sizeC=sizeA+sizeB+4;
(e)申请一个新的byte数组newdex,大小为sizeC;
(f)将dataC拷贝到newdex的头部,紧随其后放置dataB的数据,在newdex的最后4个字节放置sizeA;
(g)修改newdex中的file_size字段,即修改脱壳dex的file_size字段:对newdex计算其长度length,将该值替换掉newdex的file_size字段,即将newdex的第32-35共4个字节的地方修改成length。
(h)修改newdex中的signature 字段,即修改脱壳dex的signature 字段:对newdex计算其sha1的值,将该值替换掉newdex的signature 字段,即将newdex的第12-31共20个字节的地方修改成sha1计算后的值。
(i)修改newdex中的checksum 字段,即修改脱壳dex的checksum 字段:调用Adler32类,利用该类的实例对newdex计算其adler值,将该值替换掉newdex的checksum字段,即将newdex的第8-11共4个字节的地方修改成adler计算后的值。
1、 程序存放地址:\AndroidStudioProjects\testAppName
2、 程序名称:testAppName
3、 该apk最好具有application类;
4、 在该apk的application类与mainActivity内,均打印出用于识别的信息;
5、 生成apk(在Andorid Studio里build的话,应该是直接用test来签名了)。
6、 Apk的包名为com.example.testappname,将该apk命名为A.apk;
7、 A.apk运行成功时,将会输出以下信息,即在application类中输出当前的包名,在mainActivity类中输出当前组件的名称:
运行界面将提示此时为testAppName:
1、 程序存放地址:\AndroidStudioProjects\shellTool(等脱壳dex生成后,再生成加壳apk的dex)
2、 程序名称:shellTool
3、 该程序仅用于将A.apk拼接在壳dex文件后部。
4、 将“准备待加壳apk”步骤中生成的A.apk文件,“脱壳程序”步骤中生成的B.dex文件放置在Assets目录下,用二进制形式将两者拼接在一起,B.dex在前,A.apk在中间,尾部是A.apk的大小,生成tmp.dex文件。
5、 修改tmp.class文件头部的fileSize字段、签名字段、checksum字段(这三个字段原先存放的都是B.dex的数据),生成classes.dex文件,保存在/sdcard/目录下。
1、 程序存放地址:\AndroidStudioProjects\dumpShell\app,脱壳dex文件在\AndroidStudioProjects\dumpShell\app\build\outputs\apk\debug\ app-debug.apk内部
2、 程序名称:dumpShell
3、 该apk应该含有application类,且不能含有其他组件。
4、 在dumpShell的application类中,重写attachBaseContext方法,目的:
* 1、解密源apk;
* 2、初始化自定义类加载器
* 3、利用反射,设置LoadedApk中加载器对象为自定义加载器
5、 在dumpShell的application类中,重写onCreate方法,目的:
* 1、获取源apk的Application名称;
* 2、利用反射,生成正确的Application对象
* 3、利用反射,设置ActivityThread中的Application信息。(ActivityThread为当前主线程)
* 4、调用源apk的application对象的oncreate方法。
6、 编译并build出dumpShell.apk,用7-zip对其进行解压,将classes.dex重命名为B.dex并将由“加壳程序”进行处理,并将“加壳程序”的输出结果classes.dex(与dumpShell.apk的原classes.dex不同)放置在该解压后的目录下,同时删除签名文件,将此时目录下的所有文件压缩到一个zip文件中,并对其进行签名得到最终的apk文件。此时的apk文件是本次“加固”的最终成果。
1、 编译运行testAppName程序,生成源apk,并将其命名为A.apk;
2、 编译运行dumpShell程序,生成dumpShell.apk,从dumpShell.apk中提取classes.dex,并将其命名为B.dex,其作为脱壳dex;
3、 将A.apk与B.dex放置在shellTool项目的Assets目录下,编译运行shellTool项目,该项目将在/sdcard/目录下生成classes.dex文件,利用adb将其拷贝到PC端;
4、 用7-zip解压dumpShell.apk,删除里面的签名文件与classes.dex,并将步骤3得到的classes.dex文件放置到该文件夹下。将该文件夹下的所有文件一起压缩到dumpShell.zip文件,并对该文件进行签名成apk文件,安装运行该apk。
将原始apk的.dex文件进行加密后,放在apk的资源路径下,随后通过native代码重新对该.dex文件进行解密、加载,从而执行原始.dex文件。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-10-30 14:35
被顺利毕业编辑
,原因: