根据apk链接获取apk包名应用名
最近有个需求,根据apk链接获取apk的包名和应用名。
正常手段是这样,下载完整的apk,然后利用apktool解压分析,完事。这样的操作,一方面需要大量时间下载,一方面也浪费磁盘空间(需要解压)。
进一步的思路是,不利用apktool解压。因为apk文件是zip压缩格式,于是我们可以根据zip格式来分析apk二进制文件(不需要解压了)。
现在基本上apk都支持流下载,那么我们也可以做个流解压提取我们的信息。
查阅apk和zip压缩格式,主要得到以下几个信息。
zip压缩格式:
本地文件头1
文件数据1
数据描述符1
以上重复若干次
本地文件头 n
文件数据 n
数据描述符n
archive decryption header(EFS)
archive extra data record (EFS)
中央目录
zip64的中央目录记录结束
zip64的中央目录定位结束
中央目录记录结束
本地文件头的格式如下:
本地文件头签名   4个字节(0x04034b50)
需要提取的版本   2个字节
通用位标志   2个字节
压缩方法   2个字节
最后的mod文件时间   2个字节
最后的mod文件日期   2个字节
crc-32   4个字节
压缩大小   4个字节
解压缩大小   4个字节
文件名长度   2个字节
额外字段长度   2个字节
由上述信息,我们知道了,对二进制数据,找到文件头标签即可判断这是个文件开头。注意这是小端存放,因此用 (b’\x50\x4b\x03\x04’)来判定寻找文件头。并且文件的压缩大小也给出了,结合上面的字段既可找到下一个文件的开头,不断循环即可。这样利用requests库的流下载,既可做到迭代寻找下一个新文件对其操作。设置个chunk即可。
上面的方法只是解决了不需要解压的问题,如果我们想要的文件在apk存放在靠后位置,依然会浪费比较多的时间,有没有一个更好的方案呢?
肯定有,找到如下资料
Central directory structure:
[file header 1] . . . [file header n] [digital signature] File header: central file header signature 4 bytes (0x02014b50) version made by 2 bytes 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 comment length 2 bytes disk number start 2 bytes internal file attributes 2 bytes external file attributes 4 bytes relative offset of local header 4 bytes file name (variable size) extra field (variable size) file comment (variable size)
总结:
- 可以看出这样就有了文件的起始字段和文件压缩大小,既可以从http请求头部直接定义字段,取到自己需要的文件即可。
- 通常情况下AndroidManifest.xml和resources.arsc是我们需要的文件
- apktool解压出来有个string文件,里面有apk的应用名称,通过看apk源码我们可知,是由resource.arsc提取。这两个文件中都含有package name,所以目标找到resource.arsc文件处于的字节段即可。
- 方法就有了,我们先发一个请求url链接后1M的数据,拿到中央目录,找到resource.arsc文件对于的url中的位置。这里需要注意一下,找到的起始位置是文件头开始,会有额外字段,因此compressed size需要加个1kb。
- 代码整理后另外上传吧 (做成分2部分 1流式下载apk 2根据url提取名称)