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)中。
4. 如何实施攻击
要改变一个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内容。