新书上市《深入解析Android 5.0系统》

以下内容节选自本书




Android的签名在理论上可以防止别人破坏了软件后(例如加入恶意代码)还能以你的名义发布。但是Android的签名机制最近接连暴露了两个漏洞,导致整个签名机制形同虚设。

第一个漏洞是由国外的安全公司BlueboxSecurity发现的,这个漏洞自Android 1.6以来就一直存在,号称对99%android设备造成影响。恶意软件制作者可以在不破坏原有APK签名的前提下,利用这个漏洞来修改APK的代码并绕开Android应用的签名验证机制。

这个漏洞的原理是安装APK文件时,若APK包中同时存在着两个classes.dex,解压时读到第二个classes.dex时会覆盖掉第一个。这样实际进行签名检验的是第二个classes.dex。但是在运行时又是执行的第一个classes.dex,所以只要设法在一个APK文件中放置两个classes.dex,并使它们按照恶意classes.dex在前,正常classes.dex在后的顺序出现在文件中,就可以绕开签名检验并安装成功。

这段出问题的代码位于libcore/luni/src/main/java/java/util/zip/ZipFile.java中,让我们一起看看下面这段从版本4.2.2中摘录的代码:

privatevoid readCentralDir() throws IOException {

......

//Seek to the first CDE and read allentries.

RAFStream rafs = new RAFStream(mRaf,centralDirOffset);

BufferedInputStream bin = new BufferedInputStream(rafs,4096);

byte[] hdrBuf = new byte[CENHDR]; // Reuse the same buffer for eachentry.

for(int i = 0; i < numEntries; ++i) {

ZipEntrynewEntry = new ZipEntry(hdrBuf, bin);

mEntries.put(newEntry.getName(),newEntry);

}

}

很明显,最后这段for循环的代码有问题,循环中读压缩包的内容并逐项加入到mEntries中,而mEntries是一个类型为LinkedHashMap的变量,调用put函数时如果有重名的项,会覆盖掉第一项。

下面再看看版本4.4.1中的代码,比较一下就知道Google是如何修复这个漏洞了。

private voidreadCentralDir() throws IOException{

......

RAFStream rafStream = new RAFStream(raf,centralDirOffset);

BufferedInputStream bufferedStream = newBufferedInputStream(rafStream,4096);

byte[] hdrBuf = new byte[CENHDR]; // Reuse the same buffer for eachentry.

for(int i = 0; i < numEntries; ++i){

ZipEntry newEntry = new ZipEntry(hdrBuf,bufferedStream);

if (newEntry.localHeaderRelOffset >= centralDirOffset){

throw new ZipException("Local file header offset isafter

centraldirectory");

}

String entryName =newEntry.getName();

if (entries.put(entryName, newEntry) != null){

throw new ZipException("Duplicate entry name: " +entryName);

}

}

}

新的代码中会先检查entries中是否已经有同名的项,如果有会抛出异常。

可能有人会感兴趣,如何制造一个这样的apk文件呢?其实很简单,这里就不细说了,毕竟这里不是在教大家制造恶意程序。当然检测这种恶意程序也很简单,只要发现一个apk中有两个classes.dex就可以判定,正常的apk文件不会包含两个classes.dex文件。

第二个Andorid签名漏洞最早由国内的安全team发现并提交给GoogleGoogle很快修复了该漏洞。这个漏洞利用了Android在签名验证过程中,对Zip文件中16位数的读取时,没有考虑到大于2^15的情况。因此在将short型表示的块大小转换成int型时,会把大于2^15的数转换成int型的负数。但是在native层执行时,并不会出错。因为javaint , short,long都是有符号数,而不像C/C++里还有无符号书。具体的漏洞原理就不分析了。


更多相关文章

  1. Android应用Preference相关及源码浅析(SharePreferences篇)
  2. android点滴(29) android中设置用户自定义的字体
  3. Android(安卓)init源代码分析(1)概要分析
  4. 转载:Android(安卓)解压zip文件
  5. [转]自己整理的android入门QA表,希望能帮到一些人
  6. Unity 与Android的交互(Android(安卓)studio)
  7. Android(安卓)adb中命令的运行
  8. Android从开机到打开第一个应用发生了什么?
  9. NPM 和webpack 的基础使用

随机推荐

  1. android dialog使用小结
  2. Android(安卓)- match_parent 和 fill_pa
  3. android:onClick attribute
  4. Writing an Android Sync Provider
  5. Android Cursor遍历
  6. pull解析和json编码
  7. appium启动APP配置参数:
  8. Android(安卓)Glide 4.0 以上设置出Glide
  9. Android 图片缩放,图片圆角处理
  10. 【Android代码片段之三】TabActivity实现