android漏洞收集2-classes.dex重名、extra filed length溢出

1.classes.dex重名

  漏洞原理

漏洞的关键点在于,Android假设一个APK包中的文件是不会重名的。可实际上Zip格式是允许一个Zip文件包含具有相同文件命的文件。(注意,这里的文件名,包括这个文件在Zip包里的相对路径)。

Android在安装应用时,会抽取APK包中每个文件,进行签名验证。但如果碰到了相同文件名的文件,则只会校验第二个文件,而忽略第一个文件。

另外在应用运行前会释放classes.dex到/data/dalvik-cache/目录生成优化过的odex文件,然后再运行。这个阶段如果APK里有两个classes.dex,就只会抽取第一个classes.dex进行优化,而忽略第二。

好了,说到这,相信读者应该明白怎么利用这个漏洞了吧。 

 攻击分析

如果我们将一个APK包中放入两个classes.dex文件。第一个classes.dex是被我们篡改过的恶意dex文件;第二个classes.dex是原来这个APK中的classes.dex文件。那么在签名验证时,就会验证原来的classes.dex,因此通过验证;而执行时,却执行了被篡改过的第一个classes.dex。 

攻击步骤

a)       找个你想攻击的APK,抽取出其classes.dex保存

b)       反编译 classes.dex,修改之,重新生成新的classes.dex,更名为classes.dey

c)       用7z打开原APK包,删除其中的classes.dex,保存退出7z。

d)       依次将classes.dey和保存的classes.dex,通过7z塞入APK,然后保存退出7z

e)       用UltraEdit编辑修改过的APK,查找“classes.dey”,修改为“classes.dex”(共有两处),然后保存。

f)        大功告成。 

总结

a)       这个漏洞可以攻击几乎所有的APK应用。利用该漏洞修改过的APK,能依然保留原签名,可以通过Android的签名验证,并能执行恶意代码

b)       如果手机里的一些应用是APK + odex形式存在的。很不幸,这个漏洞无法攻击这部手机上的这些应用。因为这个APK里没有classes.dex,无法借尸还魂。

c)       如果手机里有Settings.apk(非APK + odex形式),取出来修改下,再安装覆盖,就能拿到System权限。因为Settings是system uid。


2.extra file length溢出

在讲这个漏洞之前,首先需要搞明白java里short类型转int类型的问题。要理解这个漏洞,必须明白这个技术点。

public class JavaTest {

    public static void main(String[] args) {

        short a = (short)0xFFFF;

        int b;

        b = a;

        System.out.println(b);

        b = a & 0xFFFF;

        System.out.println(b);

    }

}

 

 Zip文件格式

在每个Zip文件中都有一个Central directory,Central directory中的每一项是一个File header。这个File header的结构对应到Android代码的类就是ZipEntry。File header结构中有一个偏移量指向local file header,local file header后面就紧跟着file data。接下来我们详细看一下local file header的结构。

        local file header signature     4 bytes  (0x04034b50)

        version needed to extract       2 bytes

        general purpose bit flag        2 bytes

        compression method              2 bytes

        last mod file time              2 bytes

        last mod file date              2 bytes

        crc-32                          4 bytes

        compressed size                 4 bytes

        uncompressed size               4 bytes

        file name length                2 bytes

        extra field length              2 bytes

        file name (variable size)

        extra field (variable size)

可以看到,除最后2个域以外,local file header的其他域都是定长的。而这两个变长域的长度是由file name length和extra field length所确定。再次说明,紧跟在extra field后面的就是文件的数据file data了。

 

 Android如何进行apk校验

Android在进行apk文件校验时,会调到ZipFile的public InputStream getInputStream(ZipEntry entry)函数。这函数中,有这么一段:

            RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28);

            DataInputStream is = new DataInputStream(rafstrm);

            int localExtraLenOrWhatever = Short.reverseBytes(is.readShort());

            is.close();

 

            // Skip the name and this "extra" data or whatever it is:

            rafstrm.skip(entry.nameLength + localExtraLenOrWhatever);

            rafstrm.mLength = rafstrm.mOffset + entry.compressedSize;

            if (entry.compressionMethod == ZipEntry.DEFLATED) {

                int bufSize = Math.max(1024, (int)Math.min(entry.getSize(), 65535L));

                return new ZipInflaterInputStream(rafstrm, new Inflater(true), bufSize, entry);

            } else {

                return rafstrm;

            }

注意:上述代码中红色部分。localExtraLenOrWhatever就是local file header结构中的extra field length。回想一下我们第一部分将的技术点,如果这里的extra filed length的大小是大于2^15,会怎么样?

没错,localExtraLenOrWhatever将会是负值。因此接下来,rafstrm.skip(entry.nameLength + localExtraLenOrWhatever); 这句将无法真正跳过变长域file name (variable size) 和extra field (variable size)。反而有可能呢会跳到file name (variable size)中,甚至file name (variable size)之前。当然为了攻击方便,我们还是期望它跳到file
name (variable size)中。

 

如何实施攻击

要改变一个apk的行为,显然攻击的目标就是apk里的classes.dex文件。对于classes.dex文件在apk文件中的local file header结构,其file name (variable size)域的内容肯定就是“classes.dex”了。注意,这里的后缀名dex,正好和dex文件开头的三个字节完全相同(不理解的,参见dex文件格式)。

a)       利用这一点,从file name (variable size)域“classex.dex”的“.”之后开始我们可以写入一个完整的dex文件。这个dex文件必须是原apk里的classes.dex文件。只有这样才能绕过签名验证

b)       修改extra field length,使之为0xFFFD。因为这个值刚好为-3。根据漏洞,rafstrm.skip(entry.nameLength + localExtraLenOrWhatever); 这句就会跳到file name (variable size)域中的“.”之后。也就是一个dex文件的开始,这里必须是原dex文件内容。

c)       修改local file header之后的file data数据。在这里写入带有攻击代码的classes.dex内容。

d)       以上的修改会带来apk文件一些结构上的调整,比如扩充extra field域,调整file data大小等。

具体攻击模型,如下图。

 

总结

总的来说该攻击手段,首先利用了Android在签名验证过程中,对Zip文件相应16位域的读取时,没有考虑到大于2^15的情况。(因为java的int , short, long都是有符号数,而不像C/C++里有无符号数)。

其次利用了Zip文件中的local file header结构的extra field域来存放原classes.dex。但这个域的大小最多只能是2^16-1,因此被攻击的Apk里的classes.dex大小必须在64K以内。否则,就无法对其进行攻击。这算是这种攻击方式的一个限制。

最后还有一个问题补充说明:之所以这种攻击方式能成功,还在于在运行时,系统抽取的是hacked classes.dex,而在签名校验时,验证的是extra域里的classes.dex。前者是在libdex.so中实现,后者在Java层实现。是由Java层跟Native层不一致导致。

原文链接:http://www.xuebuyuan.com/1935195.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值