1 问题描述
众所周知,apk文件其实就是zip格式
如下图所示,apk文件末尾增加了comment(红线标记的范围内是文件尾,后面是comment),正常来说没有问题,但是comment里面还包含了504b0506这个zip文件尾的标识
使用jeb逆向可以正确解析,但是python自动化分析时,使用androguard库解析失败。
还有另外一种情况,如下,apk包含了2个格式合法的文件尾,依旧导致androguard解析报错
2 分析
2.1 第一种
androguard使用了python自带的zipfile库,第一种情况是因为zipfile库为了提高性能,是从文件末尾向前检查504b0506标记,导致出错。
下面是zipfile解析zip文件尾的部分代码(python3.8),里面注释说明了comment不能包含类似504b0506的zip文件尾标记;其方法就是从文件末尾向前找(64k+22) 个字节,其中64k是最大comment长度,22是文件尾长度。这样确实节省了查找时间,但是遇到恶意插入comment的样本就会报错,解决办法就是直接把data.rfind() 改成data.find()
# Either this is not a ZIP file, or it is a ZIP file with an archive
# comment. Search the end of the file for the "end of central directory"
# record signature. The comment is the last item in the ZIP file and may be
# up to 64K long. It is assumed that the "end of central directory" magic
# number does not appear in the comment.
maxCommentStart = max(filesize - (1 << 16) - sizeEndCentDir, 0)
fpin.seek(maxCommentStart, 0)
data = fpin.read()
start = data.rfind(stringEndArchive)
2.2 第二种
导致错误的原因与第一种有点类似,因为python的zipfile库是从末尾向前读数据,读取顺序为:
end locator -> file entry -> file record
注:这里用的010编辑器模板的说法,还有其他说法如 file entry叫做 central directory
三种chunk的头部标记分别为50 4b 05 06、50 4b 01 02、50 4b 03 04.
由于从后向前读,第一个读到的就是最后面的end locator,而前面的一个end locator会被忽略掉。然后zipfile库其中有一句如下
# "concat" is zero, unless zip was concatenated to another file
# 翻译:"concat"为0,除非当zip文件还附带了另外的文件
concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
zipfile会检测zip文件的前面是否还附带了其他的数据(比如附带一个图片,然后把文件后缀改成jpg,一般人打开就是一张图,但是用winrar打开就是一个压缩文件)。
它的检测方法就是用end locator的首地址(从整个文件的开头开始算的地址)减去file entry的大小,再减去file entry的偏移地址(相对于zip头部的偏移,不是相对于整个文件开头的偏移,所以这个就相当于file record的大小)。
正常来说,这样减完后,刚好把zip文件部分全部剪掉了,如果还有数据,那就说明前面还附带了其他文件。但是这个例子里,zipfile读取的end locator与file entry之间还夹了一个end locator,这样就导致读取数据错位了
如果只用来分析apk,可以直接改源码,让concat=0就行