新书上市《深入解析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 解压zip文件
  2. Android SD卡创建文件和文件夹失败
  3. Android自定义字体样式Typeface的三种技术方案:Java代码的setType
  4. 【Android】“存储”之普通文件存储(内部存储空间)
  5. Android JNI 使用的数据结构JNINativeMethod详解 ||建立Android
  6. Android ActionBar的源代码分析(二)
  7. Android通过加载其他应用的Dex文件破解关键数据
  8. android中javah生成jni头文件报错问题

随机推荐

  1. [gitbook] Android框架分析系列之Android
  2. Android LinearLayout属性
  3. android中四大组件之间相互通信
  4. 转:listview android:cacheColorHint,andr
  5. Android对话框里面的输入值获取不到,空指
  6. Android统计图表MPAndroidChart
  7. MotionLayout入门
  8. Netty多语言(Java、Android 、C#、WebSock
  9. android 自定义按钮样式
  10. Android 各种音量的获取和设置