LBE安全大师张勇:软件加固技术浅析
9月12日,乌云安全峰会今日召开。来自LBE安全大师创始人兼CEO张勇带来了《软件加固技术浅析》演讲!以下是他的演讲全文:
非常感谢利用这样的机会能够在这样的会场跟大家来分享一些在移动应用安全相关的议题。我自我介绍一下,我是张勇,我是LBE安全大师的早期开发者,也是创始人之一,可能我现在挂着CEO名头,但是我还是一个纯粹的工程师,也是一个技术爱好者。
关于这个主题其实也是有些小的故事的,在一个月以前,乌云当时找到我们,希望我们能够做一个相关的演讲。我们就很快的想到这样一个话题,是因为我们对这个很感兴趣。半个月前我完成了大纲,大家看后觉得太水了,所以说在一周以前我就推倒重写了,我写的主题是单子上面的主题,前天晚上讨论之后觉得还是太水了,所以觉得干脆再推倒一次,就是再重写一份,熬了两夜,给大家带来这样的主题,就是主流移动应用加固产品攻防分析。
这个议题包含两部分:第一,我们跟大家简单介绍一下移动应用加固用户的需求,以及主流移动应用加固的方案和实现的核心细节。第二部分,我会列举市面上五款非常流行的应用加固的产品,来分析它加固的原理和它实现的方法。
同时我也会给出这五款产品如何对其进行破解和脱壳的核心的要点。我希望通过这样的PPT一方面让大家对移动应用加固有些更深的了解,另一方面,我也希望能够帮助一些,或者能够为一些在这个领域内进行研究的安全工作者带来一些资讯和一些信息。
为什么需要应用加固?这个问题很简单,在PC上就有,从发展了很多代,在安卓上面从2013年被大家提及,2014年成为非常热的热点。应用加固如此火热的原因有如下几点:首先,安全平台的应用核心代码都是以JAVA书写的,我们知道它很容易被反汇编的。
即便大部分开发者都对原码进行混淆,但是核心逻辑是可以通过一些函用关系看出来的。无论是登录也好,验证也好,有经验的工程师还是可以根据调用的关系来找到你的程序里面的核心的点,然后对它进行破解和修改。
第二,安卓是一个开放的系统,如果我没记错的话,安卓平台逆向工具应该是1.5时代,也就是三四年前已经发展,到现在非常非常成熟。
第三,为什么需要用加固?因为安卓平台淡化了进程的概念,应用是基于消息和事件来运行的,基于这样的情况,恶意代码的植入变得非常容易,想在PC时代植入代码,要对原有的代码进行反汇编,然后插入你的入口点。
在安卓根本不用动到原码,只需要在清单文件,增加一些事件的响应,像开机自启动,然后你在你的恶意代码中去接收这些事件响应就可以实现基本的注入。
最后,安卓平台,我相信特别是在国内,安卓平台大约有30%的安卓手续已经获得入权限,在这个情况下无论通过APPI或者修改值,都很容易实现注入。实现这样注入话,这样的功能也就在一方面恶化了安卓软件的生态的安全。
正是有这样的原因,市场上包括开发者都对于应用加固,都希望能有这样的一些产品来保证自己的软件不会被轻易地重打包,不会被轻易地注入,也不会被轻易地破解,正是有了这样的原因,才有了现在非常火热的应用加固市场。
我在国内选了五个比较主流的应用加固供应商。基本上目前国内主流的加固供应上有以下功能:防止恶意篡改,防止内存窃取,防止调试。而且目前的做法通常是用户上传一份已经修改好的APK,然后重打包,反馈给用户的是已经加固过的APK,这套流程背后技术的原理和技术的要点主要有哪些呢?
最主要的就是所谓的加壳技术,可PC不太相同的地方是,安卓应用的核心部分代码是JAVA语言书写的,针对很多DX这样的加壳技术应运而生了,在目前三种比较主流的加壳技术:
第一,对DX完整的加密。这种加密技术会在加固的时候将DX文件给完整做一次加密,然后保存在APK中,同时用加固方案商动态声明来代替掉原始的。在应用启动的时候,加固的脱壳代码就会自动运行起来,它会对已经加密的进行脱壳并且加载到系统中,同时它还会修改一些东西来运行组件。
随着攻防的增加,第二种方案也开始出现,我称为自节码变形方案。它的原理其实也非常显而易见,它在运行时修改文件,使得你从记忆 Dump中盗取的文件是不合法或者不完整,你无法对它进行重新分析和重打包。目前我们看到的像腾讯、360的加固主要采用这样的方案。
还有一种就是综合了加密和变形的两种的方案,就是百度应用加固方案,这些加固方案它的具体的实践原理和细节我会在后面的PPT中详细介绍。
除了DX加密之外,我们知道APX还有很多东西,像我们写的动态库,还有像资源文件,包括像很多加密方案商提供的防止动态调试,防止侏儒的功能,这些功能把很多加密方案也都有(卡尔)。
资源文件的防护通常针对APK中两个比较特殊的目录,一个是RES目录,还有ACS目录,进行保护,像音频、视频,还有图片及其他资源进行加密保存,然后壳代码通常会去确保这些资源在应用读取之前被解密,这个过程是透明的,所以对应用不需要做额外的工作。
但是这样的做法可能会有一些问题。首先,跨应用间跨进程可能会失败,影响性能,还有反二次打包,加固时记录APK内容Hash,运行时由壳进行检验。还有反Ptrace,防止注入,多进程相互Ptrace,还有一些厂商采用另外一个方法,就是在运行时不断地轮巡。
安卓是多进程系统,你无法保护所有的线程,即便保护了一些线程,其他线程也会被传上去,这样的话都不会很完全。所有安卓的进程都是通过一个叫做Zygote进程报出来的,对于注入者而言或者调试者而言,他根本不需要在你进程运行的时候才Tress,像很多安全软件,像360、腾讯,所谓的超强模式,主动防御其实都是基于这样的技术。
换句话说,安全软件可以这么做,恶意软件也好,修改器它们也是可以采用同样的做法。所以说反Tress基本上没有任何功能,从现实中来讲。
其实在刚才我列举的这些功能中,最为核心的一点就是Classes Dex加密方案的实现。首先,我想跟大家先介绍一下最标准的Classes Dex整包加密的思路,这个思路也是目前最为成熟和众多产品都应用的方式。
这样的方式其实会分两步运行,首先在加固的时候,当把APK传到服务器时会解析APK,它会动态地生成一个新的Classes Dex,来代替原先的,原始的会放在其他目录下面。
当程序运行的时候,因为在加固过程中壳已经替换掉了程序入口点,当运行的时候,壳代码首先运行起来,在几个函数中它会调起脱壳代码,通常是用C来写的,来进行脱壳操作。
在脱壳操作中会做这样的事情,首先它会把DEX文件加入到内存中,通过一些手段在MAX中看不见,这样可以避免一些非常简单的方法来定位到你脱壳后的Classes Dex下的DEX的内存中的地址。
第二,我们知道安卓平台有四大组件,这些组件它和PC是不一样的,安卓平台做应用你是无法真正控制你的代码是什么时候运行的,是系统认为你需要你运行的时候,系统会把你启动起来。
换句话说,系统负责来启动你的代码,但是在通常情况下,系统会假设所有代码都存在标准的Classes Dex文件中,但是在加固中你的代码已经挪到了另外一个包中,已经不在原始的里,如果试图构建你这些组件的时候不能实现,所以为了避免这个问题,所有的加固方案会去修改Classes Older,来确保系统构造组件的时候成功找到组件。
第二,它还会确保标准正常运作,在执行完这些操作的话,最后一步会做签名验证,然后才会真正调起目标进程的对象,并且对它进行初始化,最后完成脱壳操作话就会重新交给操作系统。对这样的方案有没有可壳的可能性呢?当然是肯定的。
因为我们知道安卓肯定不会支持任何的加密,或者任何变字节解码的,它只能接受也只能运行标准的解码。换句话说,任何基于Classes Dex整包加密的方案在程序运行之前必然会在内存中对字解码进行解码,然后才输入虚拟机中运行。
另外一个事实,因为Classes Dex非常的大,所以虚拟机会通常倾向采用记忆Dump方法来加载速度。并且Classes Dex也类似ERS,也类似PE,所以基于这样的一些方案,就以下的一些脱壳的方案,最基础的方法就是去查看MAX文件,从中找到Classes Dex的地址。
去年的年底的时候,当时的加入方案还非常的初级,我记得有好几家,名胜比较响亮的加密应用,可以直接看到解密后的Dex的地址,你可以把它CAP出来,就可以解密了,所以当时等于形同虚设。
随着技术的发展,现在的加固方案商都会采取一些手段来保护,比如从内存中直接加内存解码,或者在加载之后通过MAX调用,把文件映射给转化为文件共供血量的过程,在MAX中看不见文件映射的信息,很难找到MAX。
即使做到这样还是有机可乘的,第一,通常MAX文件比较大,需要连续的文件,所以在MAX中是能够找到一些蛛丝马迹的。其次,因为在加载DEX文件的时候会采取MAX方法,这决定了它是是和页对齐的,所以我们可以变异MAX的表象,读取它的每一个表象开头的四字节,判断它是否是MAX字位,如果是那它就是MAX,现在在网上也有类似的代码做这个事情。
今年五月份的时候,应该是百度的安全实验室的一个工程师,他做了一个项目,他可以实现包括对于不少通用加固方案的脱壳工作,这也是一种方案,以及我今天跟大家介绍的,如何通过反射的方法来获取DEX的方案。
下面我介绍一下五款常用加固产品的原理和脱壳的方法。
首先是这个行业的创始人在国内,就是梆梆加固,它应该是这个行业最早的倡导者,我相信它也有最多的用户量。针对梆梆的加固我准备了两个案例,第一个,就是梆梆的企业级用户,就是国美在线,第二个,就是我自己的一个上传的产品进行了加密。
梆梆实际上对企业用户和免费用户的提供的防护级别不同的,我稍候会向大家解释。目前,梆梆的代码是支持X86平台。对梆梆的分析过程中我发现一些问题,首先就是stub classes并非必须。
第二,梆梆为了支持Art,在内部装了一个东西,这个文件是来自于安卓4.4的。对于梆梆这样的产品,对它如何能够实现脱壳包括解密操作呢?我们知道企业版本和免费用户版本是有区别的。
对于企业版本梆梆使用了内存加DEX方法。被梆梆加固的应用没有做所谓的DEX OPX操作的,这样的话会导致一些程序加固后的行为有差异,或者性能变差。
这时企业版本,做了更多的防护,对于公开版本而言的话,梆梆使用了标准的开放方式,从文件中下载的方式,同时也没有将DEX下载地址往后,就是绕可四字节的方式,使用公开版本加固过后的产品,是可以通过MAX的方式找到加固后的代码。
另外,对梆梆分析过程中我们发现对应用的修改比较多,比如它会同时启动三个进程,相互之间tress,其实这是一个伪命题,所以我个人建议这个功能可以砍掉。
同时梆梆会在运行过程中会发送一些特殊的kust,这样会降低代码的可靠性。同时脱壳后的话,梆梆在加壳时在原始的文件中也插入了相应的代码,这个在脱壳中都要移除。
第二,基于Classes Dex加固方案是来自于爱加密。它的做法和梆梆大同小异,原始的Classes Dex会被加密后放在assets下。它的方案相对而言可能更加成熟一些,但是跟梆梆比也有劣势,它是不支持安卓L的,只支持ARM平台。
爱加密相对于梆梆在自我调控方面做了比较多的工作,在公开的版本,它在下载Dex时用了四个方法,在MAX中看不到任何痕迹的,一些关键的指针被它替换成错误的指针,这样的话使用标准的脱壳工具是很难对其直接进行脱壳的。如何来解决脱壳问题呢?
其实有一个办法,首先目标用户中选择随意的MAX方法,将其传递给GNI,获得内部的一个MAS对象,MAS有一个指针的地址,这个文件就在它所在的区域中,然后在PROMAX中寻找这个地址的页表象,然后真正的DEX就藏在这个地址中,然后用这个地址寻找起始,就能找到DEX,我们测试结果也是跟梆梆一样,使用了将DEX地址从4K对齐位向后偏移8个字节,这样就很好地避开那个。
第三个产品就是360。现在360应用中心推出了一款加固宝产品,它也是和梆梆、爱加密一样,是基于Classes Dex加固的这样一款产品,实验原理都是非常接近的。
我们在对比的时候,发现我们将360加固解包后和原始的APK有些须的差异,我们认为这是360对APK做了一些所谓的性能优化,包括像构造函数优化等等,这些都是在标准的ODS做的优化。360目前是支持X86,也能在安卓上运行。
上面就是最传统的Classes Dex加密方法的案例和分析,下面我想跟大家介绍的是基于字节码变形的实现,会更加有趣一些,这些方案的出现,其实它们为了解决一个问题,就是我刚才跟大家介绍的,对于任何Classes Dex加密的产品,一旦找到了地址之后,所有的加密都无所遁形,你可以轻易地下载出来,对它为所欲为。这就有了字节码变形加密方案,它本身是一个执行机密的脚本。
换句话说,虚拟机只要完成了对这个文件的加载,文件中很多部分的格式也好,数据也好,所以它只需要将这些格式破坏掉,记忆中下载不出来的Classes文件是非法文件,失效文件。为了实现这样的目的目前有两种方案:第一,在加固的时候,首先去蕴藏一些DEX中一些关键的代码,然后在加载的时候再由程序修复。
因为修复的过程不是发生在文件本身,即便我们轻易找到了DEX的加载地址,下载后还是不可执行的文件。我们有两个方法,一个,是加密的时候把JAVA的方法改成Lunix方法,将字节码进行隐藏,在运行的时候再将字节码恢复,这个是腾讯采用的方法。
第二,在加固的时候把DEX的BAD COAD改了,放在其他地方,这个方法是360的方法。第二种方案,在DEX加载后破坏内存中DEX镜像关键结构体,使得你下载出来的结构无法被静态分析工具或者其他工具来分析,包括像DEX,这个方法是目前百度采用的方法。
如何对其进行脱壳呢?首先单纯的记忆DUMP是无效的,单纯的对其脱壳的话,是对破坏的一方进行修复,对DEX TEDER在运行的时候将其破坏值在稍候计算出来的。对于像某些支持ARK的方案,还有比较独特的方案,就是劫持系统的DEX的 OAT,这样把原始的偷出来。
第二种,像腾讯和360对MAX进行处理,来隐藏其字节码方案,也有对应的方法,就是修复MAX。
下面我想跟大家分享一下我们对市面几款使用变形技术的加固产品的技术细节的分析。首先,就是腾讯,腾讯的加固产品应该说是,我个人认为是最别出心裁的,对于其他家的加固产品,通常是对应一个PK上去,加固一个回传过来,但是在腾讯中需要填写需要加固的函数名,为什么会有这样的情况,这跟它的做法是直接相关的。
因为腾讯的应用加固方案在加固的时候会将真正的函数的类型从JAVA函数改为linux函数,将关键的结构体给清空,让静态分析工具认为这个函数是没有任何字节码的,就可以跳过,对于未加固的函数没有任何变化。
我们注意到腾讯的加固其实并没有真正把字节码藏起来,给放到其他地方,字节码其实还在这个DEX文件中,只不过它修改了函数到字节码的指针,让静态分析工具和虚拟机认为这个函数是不需要字节码的,解密的时候也是同样的做法,找到函数和字节码的对应,恢复就好了。
这个是打开了一个腾讯应用加固方案后的,一个被加密的伪函数,这个函数里设置了AK了,它的代码属性被设成NO,就是没有代码。我们打开DEX文件本身,我们发现字节码还保存着,只是你们不知道如何将它和函数利用起来。
这个方案其实非常的有开创性,我个人觉得非常赞,但是最大的问题在于,由于ART原理,这个不可能支持ART的,因为在ART运行中,因为ART运行环境首先将DEX文件编译成本地代码,然后在这个过程中它生成的并非是DEX,而是ELF格式的一个本级代码,腾讯这种做法不可能在ART环境下,在运行时重新将这个函数指向另外一个地方,所以目前腾讯的方案仍然是完全不支持ART的,我觉得未来这个方案可能也无法支持ART。
解密其实非常简单,使用DVL的函数盖到MASCOAD的地址,计算出这个偏移量,然后就可以修复这个函数的类型。所以我个人认为这个方案是非常巧妙的。当然就像我PPT中写的,这个字节码是无法保存的,安全感会比较差一些。
最后一个方案,也就是最近刚刚百度发布的一个混合的方案。百度的方案是混合了Classes Dex加固以及Classes Dex字节码变形的两种方式的一个方案,应该说在目前是最为完善的。
百度的方案对于DEX加固这块,它和360,和梆梆和爱加密是完全相同的,也并无太多新意。但是另外一边,它是如何来隐藏DEX的内容呢?
当使用百度加固方案后,它会将很重要的DEX的头的重要的位置给清空,包括DEX TIDER,当你下载不出来的时候,这个文件实际上是无法识别,也无法做静态分析的。地可以看到DEX头全是零,包括后面的OPT信息全是零了。怎么样来实现脱壳?
脱壳方法相对而言也比较简单,既然百度将信息清空了,我们将其还原就是了。基于DEX的一些特性,它是连续的,并且不允许有空隙的,我们是可以根据Aseent的格式是固定的,而且百度没有将每个字段的长度给清零,所以我们只要算出来第一个Aseent的位置,然后Aseent加,把每个数字填起来就可以了。
后面后这个DEX可以成功地被其他的静态工具分析了。相对而言百度的加固我个人认为比较完善的,因为它结合了现在的两种方式,同时也有比较高的Dop难度,还支持X86和安卓平台。
但是百度加固会在原始DEX文件中插入很多百度代码,我个人比较不喜欢这样的行为,这是从我们自己工具里摘取出来的代码,它是来重构DEX TIDER。
最后我想提一下360早期版本,实际上360最新版本中已经使用了类似梆梆和爱加密的方法,在它早期的方法也是有创意的,这种方法破解难度很大,但是它在目前的版本上为什么没有延续,我觉得还是跟兼容性相关。因为目前来看的话,所有DEX字节码变形的方案和ART都存在着或多或少接入性问题。
最后,我最近做的一些研究的总结。首先,我们认为应用加固的产品本身技术也好,包括攻防也好,是高速发展,去年搜集这个关键词应该看不到太多的信息,今年搜加固可以搜到大量的信息,我们也看到随着早期的DEX文件加密的方式的成熟,现在其实也有更多更新的方式在重现,加壳的强度也会越来越高,据传言国内已经有一些厂商实现了类似PC上面的技术,能够进一步提升加固强度,但是目前没有看到在公开市场上有这样的案例。
第二,ART是安卓的未来,从安卓L开始。ART本质是在运行前将字节码编译为本地指令,任何试图将这个解码隐藏,都会导致使本地指令无法执行,这也是目前360和腾讯无法解决的。未来可能有其他的方式,像安卓MASS上面,有的人做的方案,能够未来对EOT进行PACH,我们认为ART在加固方面还有很多空间,目前还不是很成熟。
最后,应用加固它其实还是有很多兼容性问题的,在实际测试过程中我们也注意到,像不同的硬件平台,像不同版本的系统,甚至像不同厂商的手机,为什么会有这样的问题呢?
因为作加固中很多操作是需要通过反射来做的,还有很多操作是许多对结构体进行修改,我们知道安卓是开放系统,任何厂家都可以修改这些结构体,这就导致了在某些手机上面这个结构体的偏移量,或者位置、地址是不同的,这会影响它同其他设备兼容性的问题。
在最近一段时间我的很多朋友问我,对坚固问题怎么看?从目前来看,我认为加固并不是万能药,而且有很多脱壳工具。对开发者而言,一个完整的体系才是他所需要的,他需要多管齐下,才能真正解决APK安全问题,单纯加固肯定是不足够的。
文章来源:http://chenjava.blog.51cto.com/374566/1592770
相关文章
- 1条评论
- 闹旅只酷2022-05-28 09:24:53
- 合了现在的两种方式,同时也有比较高的Dop难度,还支持X86和安卓平台。 但是百度加固会在原始DEX文件中插入很多百度代码,我个人比较不喜欢这样的行为,这是从我们自己工具里摘取出来的代码,它是来重构DEX TIDER。 最后我想提一下360早期版本,实际上360最新版本中已经使用了类似