本文主要目的是讲述各种保护的手段及发展历程,还请不要对时间线太过在意。
太易
在 Android 刚开始起步的时候,大概在 2010 年之前,别说注重 APP
的安全,甚至 Android 系统本身的安全都未被受到重视。
毕竟,世界的主角,还是 PC
和 WEB
。
不过,世界是相对公平的,虽然没有什么安全措施,但是也没有什么破解需求。一个新生平台能做好手机操作系统应有的功能就已经不错了,至于其他第三方应用也很少会有收费应用,当时的移动网络环境与现在完全是天差地别。
太初
对 Android 安全最关注的人,应当属黑客 and 黑产了。
毕竟,饭还是要恰,病毒还是要写。。
2009 年,smali/baksmali
横空出世,这应该是第一款公开的 DEX 汇编/反汇编器,大部分人的安卓破解之路、安卓逆向之路、安卓病毒分析之路、安卓**之路,也从这里开始。
于是在 2010 年,卡巴斯基拦截到了第一枚 Android 病毒...
同年,开始出现各种针对 Android 病毒分析、 Android 安全的技术论文,例如基于 smali
的静态分析、基于沙箱的动态分析等。
同年,dex2jar
, apktool
等优秀的 Android 逆向分析工具陆续开始开发,开源。后面几年,基于这两款工具的黑产行业愈加繁荣...
太始
2010 年,可以说是 Android 安全飞速发展的开始。
在没有保护的情况下想要破解一个软件,只要使用 apktool
, dex2jar
等工具,就可以清楚且完整的看到一款产品的原始代码逻辑,再加上坚持不懈的毅力,以及一定的逆向思维就可以搞定。
虽然当时还没有像如今一键式的 APP 加固服务,但代码保护技术并不是新生儿,套路照搬下来也是能用。
最常用的保护方法之一是:代码混淆
例如 Google
自带的就是混淆器 ProGuard
, ProGuard
唯一的功能,就是修改类名、方法名、字段名。主要有两个好处,一个是符号混淆,把原本的 XXXActivity
改成 a
,让你不好猜到这个类的用处。另一个好处是压缩文件大小,毕竟动辄几千几万各类,符号字符串在 dex 文件中的字节占比并不小。
另外有代表性的是 DexGuard
,与 ProGuard
是同一个开发者的另一款产品。区别在于功能更加丰富,并且是卖钱的商业软件,而 ProGuard
是个免费软件,供所有开发者白嫖。Dexguard
的混淆功能更加强大,支持比如字符串加密、花指令、资源加密等功能。发展到现在, DexGuard
的功能更加丰富,甚至还有一些运行时的防护,已经不是一个单纯的混淆器了。
常用的保护方法还有:动态加载
将需要保护的代码单独编译出来,将其进行加密后在程序运行的过程中对其进行解密,并使用 ClassLoader
来动态的进行加载。这是 PC 上保护代码的常见套路,也是后来第一代壳的基础。
最硬核的保护:Native 开发
使用 NDK 编写应用,直接生成 native 代码
嗯,这是现在 java2cpp
技术的基础。。。
最现代化的保护:核心数据、功能云端化。
将重要的功能、数据,全部放到云端运算,客户端能只作展示用就只作展示用。嗯,这个勉强算是现在风控的基础。。。
所以说,现在移动端大部分的代码保护方法,都是在前人的基础上进行不断的升级,适配。
太素
如果说保护是站在巨人的肩膀上,那么破解就是站在上帝的肩膀上。
既然静态分析无法入手,那么攻击方还可以以上帝视角来进行动态分析。
关于动态分析, 我专门写过一篇《Android 动态分析攻防小结》讲过一些套路,可以到公众号历史消息查阅。
面对动态分析,原本最直接有效低成本的动态加载也变成最脆弱的一种保护方式。
通常只需要附加进程做一个内存漫游搜索 dex.035
或者甚至直接看 Segment
名称就能在内存中找到动态加载的 dex
文件并 dump下来
,发展到 2020 年,这个办法依然对大部分加固的一代保护有效。
当然,还有更多的手动挡,比如在 dvmDexFileOpenPartial
之类的关于加载代码的函数打断点,做 Hook
,就可以轻而易举的找到解密后的 dex
文件。
这便是 Android 加固初号机的脱壳方法。
因为光有单纯的动态加载压根挡不住人,这时候应用保护大概还有其他几条发展路线:
对抗调试器
这部分已经在 公众号(虎克老湿基)
发表过的 《Android 动态分析攻防小结》
文中讲过很多了,可以参阅。
当然并不是一开始就有很多方法,而是经过各方不断的摸索,竞品分析,社区分享得来的。
对抗反编译器
通过寻找各种反编译器、反汇编器的漏洞、BUG,将 Payload
插入到需要保护的 DEX
或者资源文件中, 让工具崩溃导致无法正常运行。
不过,这条路显然是一条断头路。随着各种工具的不断维护,兼容性变得越来越强,能找到这种可以直接 Bypass
的 BUG 并不容易,就算有也会被迅速的修复。
典型的例子有 Black Hat USA 2012 - Dex Education: Practicing Safe Dex
,以及 360 加固之前也带有一些这样的保护。
对抗人:恶心流
代码保护千万道,唯有恶心人是王道。
所以这条路的责任是将混淆的精髓:"恶心",发扬光大。
比如:
-
符号混淆升级版:
之前是将类名方法名字段名换成 abcd, 后来开始使用混淆字典,字典里包括各种小语种符号、不可见符号。就用这些字典里的符号来生成新的类名、方法名、字段名,最终效果就是看起来是乱码或者一片空白。
当然也有很多应对之策,比如开源反编译器
Jadx
的反混淆功能就支持自动重命名符号,换成abcd
的无意义名称;再比如另一个反混淆功能,是从 DEX 文件里读出
sourcefile
属性来还原真正的类名,不过这个东西只是一个调试信息,所以很多混淆器也会直接将这个字段剔掉。所以对抗此类混淆最有效的工具还是:人
-
字符串加密加强版:
最开始的字符串加密很多都比较单调,一般都是有个解密方法接受一个加密的字符串或者
byte[]
然后返回一个字符串。这种当然很容易被针对,只要把先使用dex2jar
然后动态加载 Jar 包反射调用解密方法就可以得到明文字符串。于是后来就出现了很多变异方法,大概以下几种:
1. 游击队打法,将字符串分组使用多种算法加密,不再仅依赖唯一的一个方法解密,而是每个解密方法对应不同的算法,让你没法一网打尽。
2. 自卫队打法,在初始化解密算法时检查运行环境,或者依赖上下文环境,增加调用的难度。
3. 使用 native 解密,并且使用对 SO 进行保护。 -
Native 保护
对于 Native 的恶心流保护,最火也最有效的当属
OLLVM
了。OLLVM 是 13 年以后才出现的一个东西,内容可能也比较多,这个后面再讲。至于其他
Native
保护,最开始基本上只有两种套路:1. 破坏 ELF 文件结构,甚至定制 linker 加载自定义的SO。
2. 加密代码段,运行时解密,也就是跟 Dex 动态加载类似。或者直接套用 UPX 之类的传统 ELF 壳。虽然动态 DUMP 内存就可以得到真正的代码,但如果无法修复完整的文件结构则会缺少很多可以帮助于分析的东西。
-
其他混淆:
之前看到有能做到 APK 包里除了必须的
manifest
之外一个正常的文件都没有,将assert
,lib
,dex
,res
全部做了保护(包括上面所说的一些手段),先不说兼容性或者性能如何,反正恶心是真的恶心...
太极
2010 年,是 Android 应用安全创世纪的一年,而发展到大约 2013 年,Android 应用的各种代码保护技术基本已经有了雏形,上述的技术大部分已经得到了稳定的实现。
可以说,2009 年到 2012 年,是 Android 应用安全从无极到太极、开创新纪元的一段时期。
在这段时间内,Android 已经盘下了大部分的手机市场。
2013 年,Android 手机的全球市场占有率高达 80%, 大量的用户、开发者涌入。
Google 的安卓帝国,势不可挡。
同时,Android 应用安全市场的春天也跟着来了。
预知后事如何,请长按下方二维码,关注虎克老湿基,听下回分解...
相关阅读
原文始发于微信公众号(秃头的逆向痴想):Android App 保护那些事儿 (一)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论