你的位置:首页 > 操作系统

[操作系统]浅谈Android应用保护(二):Anti


本文内容翻译自国外文献,原文链接请参看文章底部

 

之前讲到过,应用开发者为了保护自己的应用不被别人分析和篡改,会将应用的安全性寄托在某个(些)机制上。可以被用来保护应用的机制有很多,效果和实现难度也是各有特点。有这样一类应用保护方法,叫做针对逆向工具的对抗(Anti-Analysis)。

 

针对逆向工具的对抗,简单来讲就是利用逆向工具自身的缺陷或者是Android特有的机制,使应用逆向分析工具在工作过程中失效或者报错崩溃,分析过程无法继续实施。从而达到保护应用的目的。

 

这种保护应用的方式的优点就是实现简单,不需要触及应用自身的代码,只需加入简单的“恶意”代码即可实现崩溃逆向调试工具的目的。同时作为一种非常规的应用保护方法,思路灵活,经常可以产生意想不到的效果。缺点也很明显,逆向工具会在新版本中修复这些漏洞和缺陷,研究人员也可以很容易分析出其实现方法,进而进行有针对性的破除。

 

下面介绍几种通过“攻击”逆向工具来保护应用免于被逆向的方法。

 

一、恼人的“伪加密”

Android平台应用文件.apk文件,本质上来说就是一个zip压缩包。所以一般的应用逆向分析者都是把.apk文件修改后缀为.zip,通过工具解压缩其中的lib文件和dex文件,再进行进一步分析。但是突然有一天,解压zip文件的时候,突然发现,apk文件被加密了。

 

此时,很多人就会觉得非常奇怪,没办法了,不知道下一步怎么办,甚至想到去爆破密码,爆破失败后就放弃了分析。从而应用就达到了某称程度上的安全保护。

 

这个的实现原理是这样的:修改zip的头,把文件的加密标志设置为ture,但不真正的对包里面的数据进行加密。还原就把加密标志设置为false.利用了Android处理zip文件不判断头里的加密信息,其他压缩软件,java默认实现的zip api都有检测zip头中的加密信息。对于这种方法进行保护的APK,直接用bluebox的这个脚本即可搞定。

https://github.com/blueboxsecurity/DalvikBytecodeTampering/blob/master/unpack.py

 

二、借鉴已知的JAR hack方法

由于APK本质上就是zip/jar包,所以我们也可以利用已知的JAR hack方法。

JAR对文件名的长度是没有现在的,但是操作系统要求文件名不能大于255;我们可以通过构建大于255字符的长类名来达到反逆向的目的。

 

我们可以根据对DEX Class Def Item的格式的学习,实现.

 

我们可以通过以下方式构建大于255的长类名:

1、在源代码中添加大于255的字符串A。

2、编译源代码,修改DEX文件头,修改Class descriptor_id为字符串A的String_idx。

 

效果如下:

 

受影响的工具有:IDA,Dex2jar, Androguard , Baksmali 

 

三、插入无效字节码指令或者无效指针引发逆向工具崩溃

1.插入无效指令  

由于大部分逆向工具都是线性读取字节码并解析,当遇到无效字节码时,就会引起反编译工具字节码解析失败,如果逆向工具没有考虑到这一点,没有对报出的错误进行合理的处理,就会直接崩溃。

 

我们可以插入无效字节码到DEX文件,但要保证该无效字节码永远不会被执行。实现方法:

把类似于这样的代码:

 

插入到应用中我们不关心的类中,再重新编译生成APK。

效果如下:

 

Baksmali被崩溃了(已在2f81aec886d2 7/28 版本中修复)。

 

Dex2jar也崩溃了。(这个修复起来也很容易,只不过目前的公开版本里没有修复)

 

动态分析工具 Androguard 也崩溃了。(新版本已经修复)。

 

IDA未受影响,可以正常使用。这是因为IDA并没有使用线性扫描的方式对DEX文件进行解析,而是使用了某种程度上更“先进”的递归下降反汇编方式。

 

2.插入无效数据指针

这个方法和方法1差别不大,主要原理就是插入可以分析工具崩溃的代码、数据、指针。然后由应用开发者保证恶意的代码、数据处在永远不会执行的区域即可。

 

这种方法的影响的逆向工具包括 Baksmali、Dex2jar、Androguard、IDA(部分有效)。插入无效指针比插入无效指令更实用的一个地方在于,这个无效指针可以更紧密地和代码结合在一起,可以巧妙地插在会被执行的代码中去,进而导致使用递归沉降反汇编的IDA也中招。

 

这2种针对逆向工具“攻击“的修复方法都比较容易,一方面工具自身更新代码,对于非期望的输入做好过滤,一方面逆向分析者可以编写脚本,定点清除APK文件中的恶意代码。

 

3.一些技巧

既然是想要让逆向工具崩溃,那就应该让逆向工具崩溃的越早越好。如果把恶意字节码插在DEX文件末尾,那么分析工具崩溃前已经把工作做完了,就没有意义了。

 

虽然恶意字节码可以被定点清除,逆向工具也可以在遇到恶意字节码报错时不崩溃,直接绕过去处理后面的,导致还是有办法分析整个DEX文件的。但是包含恶意字节码的这一部分代码块是没有被分析的(要么被清除,要么被绕过)。所以,可以巧妙的在关键流程中嵌入这样的恶意字节码,即使不能保护整个DEX文件,保护几个关键函数,也还是很有意义的。

 

四、针对java反编译器缺陷进行攻击

无论有多么高科技的DEX反编译工具,最终从DEX字节码反编译回小白攻击者可读的Java代码,都不是那么完美的。主要是因为android 在打包的时候使用dx.jar 对初始class文件进行了优化,使得生成的dex文件不再是标准的jvm可执行文件,而是dvm的可执行文件。Dvm和Jvm在架构上一个是基于寄存器、一个是基于堆栈的。所以在转换的过程中,一定是有信息损失的。既然转换是不完美的,那么就有能为我们所用的地方。

 

Dex2jar+(JD-Gui或JAD) 组合工具是逆向分析经常使用的工具。dex2jar用于把DEX文件转换为java字节码JAR文件,JD-GUI或JAD用于把java字节码转化为java源代码。

 

我们可以针对JAVA JD-Gui或JAD工具缺陷来达到反逆向分析的目的。达到的效果如下图所示:

 

Dex2jar + jd-gui 已经不能正确分析Apk里对应的代码。

IDA对流程的分析也出现问题了。

 

参考资料1提出了一段类似于这样的代码,嵌入到任何方法中,都能在(dex2jar+jd-gui)上复现上面出现的ERROR。但是这段代码在另一个性能比较好的商业反编译器JEB中就没有生效了。 

 

同时,我也发现,只要在try-catch的try语句块中加入复杂的return语句,一般也能达到上述的ERROR。这大概是因为try-catch语句的实现和堆栈有关,而基于寄存器的DVM在转换的时候有一些特殊的操作。即使是JEB,在处理try-catch语句时也常常出问题。

 

五、Native库文件的Anti-Analysis

针对so文件的分析,是IDA的强项,特别是网上已经流传了有一段的时间的IDA6.5pro+F5的破解版,基本上一路F5下来,就能把一个so里面的代码逆的差不多了。所以针对IDA的反分析方法,也是非常有必要的。

 

在so文件的格式(即ELF文件格式)的头部,e_shoff字段是指节区(section)表格的偏移量, 以字节计算,如果没有的话,可以为0. 编译链接期,每一个segment包括(对应)哪几个section,链接器已经做好了,加载期间,linker只需要按照segment加载就OK了。所以真正so文件加载的时候,是不关心头部section相关的字段的。但是IDA,readelf和objdump这类so文件分析工具是会去解析这个字段的。如果给这个字段赋值一个错误数据,就会导致这些工具的报错甚至崩溃。

 

如图:

objdump 报错: file truncated

readelf 解析出来的全是ffffff

 

这种Anti-Analysis的方式是比较容易修复的,一方面IDA,objdump,readelf可以在新的版本中修复这样的问题。另一方面,分析者也可以手动修复so文件中sht相关的恶意数据,实现修复。

 

六、总结

上面介绍的Anti-analysis方法,都是一些很早就公开并且被很多应用使用过的方法。这个层面的攻防之所以没有进一步的发展,是因为这个层面的对抗意义并不是特别大,没有太多的“干货”。把保护应用不被逆向攻击的功能寄托在逆向工具的缺陷上,毕竟图样。知道原理之后,基本都可以秒破。按照Android平台应用攻防的发展来讲,这种层面的攻防已经不再受到太多人的关注了。现在人们更多把对抗的领域,拉到了代码的Dalvik层和native层。这两个层面的对抗,将会在下两篇文章中介绍。

 

浅谈Android应用保护系列回顾

浅谈Android应用保护(零):出发点和背景

浅谈Android应用保护(一):Android应用逆向的基本方法和演示

 

参考资料:

http://www.strazzere.com/papers/DexEducation-PracticingSafeDex.pdf

http://books.google.com.hk/books?id=-LZpAgAAQBAJ&printsec=frontcover&hl=zh-CN#v=onepage&q&f=false

 

更多技术干货,可访问阿里聚安全博客