(加固技术发展历程)
(开发阶段) 运行时加载部分(Loader)会先运行,释放出关键逻辑(Payload),然后java的动态加载技术进行加载,并转交控制权。
(启动流程)
(核心代码) 备注(multidex组件的加固原理): Android的DEX文件在设计之初程序普遍较小,所以在DEX文件设计时,只允许包含65535个函数引用。而随着Android应用的发展,大量的应用的代码已经超过了65535的限制,为了解决这个问题,Android5.0之后原生支持加载多个dex,而为了对旧版本的兼容,Android提供了multidex组件。该组件的实现原理与上面介绍的是一致的。 缺陷与对抗 第一代加固技术的缺陷是依赖Java的动态加载机制,而这个机制要求关键逻辑(Payload)部分必须解压,并且释放到文件系统,这就给了攻击机会去获取对应的文件。虽然可以通过关键逻辑(Payload)被加载后,被从文件系统删除,用于防止被复制,但是攻击者可以拦截对应的删除函数,阻止删除。 而关键逻辑(Payload)会被加密后保存,可用于对抗静态分析,但是攻击者可以通过自定义虚拟机,拦截动态加载机制所使用的关键函数,在这个函数内部,复制文件系统中的关键逻辑(Payload)文件。
(对开发零干扰的加固后启动流程) 另一方面,不落地加载技术是在第一代加固技术的基础上改进,主要解决第一代技术中Payload必须释放到文件系统(俗称落地)的缺陷,其主要的技术方案有两种: A.拦截系统IO相关的函数(如read、write),在这些函数中提供透明加解密。具体的流程是: 1)关键逻辑(Payload)以加密的方式存储在APK中。 2)运行时加载部分(Loader)将关键逻辑释(Payload)放到文件系统,此时关键逻辑(Payload)还处于加密状态。 3)加载部分拦截对应的系统IO函数(read,write等)。 4)加载部分(Loader)正常调用Java动态加载机制。由于虚拟机的IO部分被拦截,所以虚拟机读取到已经解密的关键逻辑(Payload)。
(透明加解密方案流程) B.直接调用虚拟机提供的函数进行不落地的加载,具体流程是: 1)关键逻辑(Payload)以加密的方式存储在APK中。 2)运行时加载部分(Loader)将关键逻辑释(Payload)放到内存。 3)加载部分调用虚拟机内部接口进行加载。
(不落地加载流程) 关键的系统函数如下:
兼容性 方案A透明加密方案由于其需要拦截系统的IO函数,这部分会使用inline hook或者got hook等技术,其会带来一定的兼容性问题 方案B的不落地加载方案由于其调需要调用系统内部的接口,而这个接口并不导出,各个厂商在实现时又有各自的自定义修改,导致该方案存在兼容性问题。 缺陷与对抗 第二代加固技术在应用启动时要处理大量的加解密加载操作,会造成应用长时间假死(黑屏),用户体验差。 在加固技术实现上没有本质区别,虽然能防止第一代加固技术文件必须落地被复制的缺陷,但是也可以从以下方面进行对抗: 例如内存中的DEX文件头会被清除,用于防止在dump文件中被找到;DEX文件结构被破坏,例如增加了一些错误的数据,提高恢复的成本。 但是Payload被加载之后,在内存中是连续的,利用gdb等调试工具dump内存后可以直接找到Payload,进行简单的处理之后可以恢复出100%的Payload文件。 和第一代加固技术的对抗方法一样,不落地加载也无法对抗自定义虚拟机。只需对上述的关键函数进行拦截然后将对应的内存段写出去,即可恢复Payload。注意,由于IO相关的函数被拦截,所以无法直接调用read/write等函数进行直接的读写,需要使用syscall函数进行绕过。 虽然厂商会自己实现可能上述函数,从而绕过上述函数的拦截。但是Android的类加载器必须能找到对于的结构体才能正常执行,攻击者可以以类加载器做为起点,找到对应的Payload在内存中的位置。
(发布阶段) 运行阶段将函数内容重新恢复到对应的函数体。恢复的时间点有几个方式: A.加载之后恢复函数内容到DEX壳所在的内存区域
(运行阶段) B.加载之后将函数内容恢复到虚拟机内部的结构体上:虚拟机读取DEX文件后内部对每一个函数有一个结构体,这个结构体上有一个指针指向函数内容(CodeItem),可以通过修改这个指针修改对应的函数内容。
C.拦截虚拟机内与查找执行代码相关的函数,返回函数内容。 兼容性 指令抽离技术使用了大量的虚拟内部结构与未被文档的特性,再加上Android复杂的厂商定制,带来大量的兼容性问题。 缺陷与对抗 指令抽离技术的某些方案与虚拟机的JIT性能优化冲突,无法达到最佳的运行性能。依旧使用了java虚拟机进行函数内容的执行。攻击者可以通过自定义Android虚拟机,在解释器的代码上做记录一个函数的内容(CodeItem)。接下来遍历触发所有函数,从而获取到全部的函数内容。最终重新组装成一个完整的DEX文件。目前已经有自动化工具可以指令抽离技术中脱壳。
(第三代加固DEX文件脱壳流程)
B.DEX文件内的函数被标记为native,内容被抽离并转换成自定义的指令格式,该格式使用自定义接收器执行,和A一样需要使用JNI和Android系统进行调用。
兼容性 第四代VMP加固技术一般配合第三代加固技术使用,所以第三代的所有兼容性问题,指令转换/VMP加固也存在。 缺陷与对抗 不论使用指令转换/VMP加固的A方案或者B方案,其必须通过虚拟机提供的JNI接口与虚拟机进行交互,攻击者可以直接将指令转换/VMP加固方案当作黑盒,通过自定义的JNI接口对象,对黑盒内部进行探测、记录和分析,进而得到完整DEX程序。
(第四代加固DEX文件恢复) 另外,第四代VMP加固技术只实现Java代码保护,没有做到使用VMP技术来保护C/C++等代码,安全保护能力有所欠缺。
(虚机源码保护加固流程) 生成的虚机源码保护拥有独特的可变指令集,极大的提高了指令跟踪、逆向分析的难度。同时,虚机源码保护还提供了反调试能力和监控能力。虚机源码保护可以通过自身的探针感知到环境的变化,实时探测到外界对本环境的调试、注入等非正常执行流程变化,将调试动作引入程序陷阱,并发出警报,进而进行实时更新,提高安全强度。 加固技术发展及其攻防对抗的更迭,伴随着互联网技术发展不断升级,我们深信邪不能胜正,而虚机源码保护加固作为当前领先的加固技术,在未来很长一段时间,能够为App提供足够强度的保护,为企业和开发者的业务发展保驾护航。 * 更多黑灰产对抗技术及案例分享,请关注顶象技术:https://www.dingxiang-inc.com/blog