文档章节

【C#】【APK】APK文件解析AXML-层层深入APK文件解析之一

Parser7
 Parser7
发布于 2015/02/14 18:13
字数 1660
阅读 3026
收藏 126

APK解析是很久以前想完成的一件事,但是因为一些事情搁下了。

当时使用Iteedee的代码在200多个APK文件中有将近四分之一的文件是无法成功解析AXML的。Iteedee下称I

因此,本文的代码基于I的代码修改,效果基本接近于APKTOOL(https://code.google.com/p/android-apktool/)

毋庸置疑的是,在解析的时候,会遇到各种奇葩的编码问题,首先会遇到文件的压缩解压缩码流问题,不得不说SharpZip的性能还是可以的,注意APK使用的Zip压缩格式是非固实压缩,虽然压缩性能(Performance of Compression ,BenchMark)降低了,但是对于文件寻址来说还是很方便的。

常用的APK解析读取APK信息的方法有很多种:

1、AAPT工具、2、apkTool工具、3、AXMLPrinter2工具、4、自带ZIP解压引擎纯字节流解码分析、5、其它...

这里要讲的就是第四种,是基于开源库SharpZipLib的。

‍‍下面言归正传,谈谈个中遇到的一些问题:

1、关于怎么解压zip可以看这个问题的某层回答:

http://bbs.csdn.net/topics/390421494

注意GZip和Zip不一样,Gzip在HTTP请求中比较常见

使用到的sharp库到如下网站去找

http://icsharpcode.github.io/SharpZipLib/

2、zip版本问题(788):

大部分文件的解压版本都是0x14,而个别文件出现0x0314,因此抛出了异常,具体原因无法考究,解决方案是在SharpZipLib源码中加入代码过滤掉,影响应该不大:

 if (extractVersion==788)
{
    extractVersion &= 0xff; 
}

记得备案,免得那天遇到问题了不知道这一茬。


3、文本编码问题:

从I那儿下载的代码经过测试后还是存在不少问题的,这里说的文本编码就是一个典型的例子。

I使用的是UTF8编码格式进行转码

通过 http://tool.chinaz.com/Tools/URLEncode.aspx  查了下"赶集"两字的UTF8的码流形式为:%e8%b5%b6%e9%9b%86 .

 然而,把解析之前的AndroidManifest.xml在程序里dump出来发现实际上是这样的:

那么问题就来了,通过http://tool.chinaz.com/Tools/Unicode.aspx 查了一下unicode码流(unicode的编码据说没有一个统一的标准,所以才出现了UTF8\16\32等编码),给出的结果是:\u8d76\u96c6\u7b80\u6613\u5730\u56fe。

原因真的就找到了吗,有时候人真的是聪明反被聪明误啊,博主考虑了大小端的问题,于是字节换序、去00字节、重返UTF8(为什么再使用UTF8也是基于很多原因)各种方法试过皆无果之后,探究了下Unicode编码在c#中实现的具体码流:

            byte[] bytes = Encoding.Unicode.GetBytes(textBox1.Text);
            for (int ii = 0; ii < bytes.Length; ii++)
            {
                textBox2.Text += string.Format("{0:x2} ", bytes[ii]);
            }

结果如下:

显然字序跟AXML中的是一模一样,注意00字节,可见AXML和c#中的unicode都使用了双字节对齐的(这不废话么),那么修复了编码Bug之后的某个子函数是这样的:

 private String compXmlStringAt(byte[] arr, int strOff)
        {
            int strLen = arr[strOff + 1] << 8 & 0xff00 | arr[strOff] & 0xff;
            byte[] chars = new byte[strLen<<=1 ];
            for (int ii = 0; ii < strLen ; ii++)
            {
                chars[ii] = arr[strOff + 2 + ii];
            }
            return Encoding.Unicode.GetString(chars);//Change to Unicode of Encoding by Parser7
        }

如此而来,就成功支持了中文/多语言了。然而让我郁闷的是,通篇的注释都在说Unicode,只字未提UTF8,代码的原作者居然赫然在目地写着错误的代码,令人费解的注释


4、TEXT事件类型的处理:

I写的代码,只对startTag之类的事件做了处理,然而XmlPullParser使用了五类事件,但是I对未知事件的处理是直接break了,这样会造成manifest等元素在流中未关闭的问题,严重的致命/FATOL ERROR。

由于此处对TEXT内容并不关心,所以使用对offset简单处理防止死循环的方法跳过。后面有空了再来细细研究这个东西。有需要的朋友可以一起交流下。

XmlPullParser的源码我估计可能就在这个网站http://www.xmlpull.org/ ,找到的记得发我一份,先谢谢了。

相关资料:

http://blog.csdn.net/andyhuabing/article/details/8036340

5、size=0问题导致无法正确读到androidmanifest.xml:

I使用了如下的方法遍历每一个压缩包中的文件

 while ((item = zip.GetNextEntry()) != null)
{...}

在某个APK的解析中发现出现size=0导致未能成功读取androidmanifest.xml文件。

跟踪了size读写器所有的过程后,发现在ZipFile构造函数中已经能够获得所有的ZipEntry,而I的代码这里调用GetNextEntry方法显然不仅是画蛇添足而且还引入了Bug,废话少说,使用迭代器轻松搞定:

PZipFile = new ZipFile(fsStream);
 foreach (ZipEntry entry in PZipFile )
 {    ...    }

小结:

至此,已经能成功解析1021个文件的AXML,但还有35个文件不能成功解析。

经检验,有21个文件已经损坏,但还有14个文件可以成功打开压缩包,具体原因还在分析中。

6、XmlException抛出的EntityName解析错误:并指出在35行51列

I的代码似乎没有实现将decompressXML之后的result转为XMLDocument,这里是我自己加了相应的代码,但是却出现这样的问题。

dump出解析的xml内容后发现在指定位置出现了xml非法字符'&',将非法字符转义处理就行了。

下面就是很直接、赤裸裸的代码了:

public static string HandleInvalidCharAtXMLDoc(string filename)
{
 return filename.Replace("<", "&lt;").Replace(">", "&gt;").Replace("&", "&amp;").Replace("'", "&apos;").Replace("\"", "&quot;");
}


7、压缩包签名头问题:

apktool解不开,winrar能看到目录结构,从压缩档中拖拽文件貌似可以解压AXML,但是会提示文件损坏,将解压出来的AXML文件放入成功解析的APK后能正确解析出AXML明文内容。

经过一些实验后,发现dump出来的字节流跟能解析出来的字节流不一样,说明可能是entry索引出了问题,或者内容被破坏了。根据上文描述,明显问题出在entry索引问题,或者是其它问题(不是788等版本问题)

© 著作权归作者所有

共有 人打赏支持
Parser7
粉丝 23
博文 16
码字总数 21280
作品 1
杭州
程序员
加载中

评论(4)

Parser7
Parser7

引用来自“yujiff”的评论

涉及编码,就应该弄清unicode与utf8,utf16,utf32等等的关系。
是的,一般的系统unicode好像都是16位实现,其实就是宽char吧,之前因为解析过sqlite,对编码接触也不多,所以绕了一大弯。
y
yujiff
涉及编码,就应该弄清unicode与utf8,utf16,utf32等等的关系。
Parser7
Parser7

引用来自“FlashCHen”的评论

这是所谓的反编译的意思吗?

只是解析了AXML,反编译的一部分。
FlashCHen
FlashCHen
这是所谓的反编译的意思吗?
OSChina 技术周刊第二十二期 —— DUBBO配置规则详解

每周技术抢先看,总有你想要的! 移动开发 【翻译】为你的 Android 应用增加本地搜索功能 前端开发 【软件】AngularJS 的剪贴板扩展 ngClip 【软件】国际化和本地化 JavaScript 库 Globaliz...

OSC编辑部
2015/02/16
1K
0
OSChina 技术周刊第二十二期 —— DUBBO 配置规则详解

每周技术抢先看,总有你想要的! 移动开发 【翻译】为你的 Android 应用增加本地搜索功能 前端开发 【软件】AngularJS 的剪贴板扩展 ngClip 【软件】国际化和本地化 JavaScript 库 Globaliz...

OSC编辑部
2015/02/16
0
0
转载分享:Android APP二次打包操作步骤介绍

看到好的技术教程就想转载一下,不喜勿喷!谢谢配合,仅供菜鸟学习研究,不要做坏事哦(^o^)/~ 关于Android APP 二次打包现象已经屡见不鲜,为何“打包党”就吃准了Android平台,二次打包的操...

科技创造
2015/08/26
1K
2
Android apk仿反编译套路(一)

反编译Apk时你是否遇到过下图中的错误,反编译进行到就报错了,然后就没有然后了。 pic001.png 这是因为该apk的文件被特殊处理过,导致在反编译时报错。 我们知道是以AXML格式存在于apk中的,...

hellsam
03/22
0
0
APK安装流程详解16——Android包管理总结

APK安装流程系列文章整体内容如下: APK安装流程详解0——前言 APK安装流程详解1——有关"安装ing"的实体类概述 APK安装流程详解2——PackageManager简介 APK安装流程详解3——PackageManage...

隔壁老李头
2017/12/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Linux环境搭建 | VMware下共享文件夹的实现

在进行程序开发的过程中,我们经常要在主机与虚拟机之间传递文件,比如说,源代码位于虚拟机,而在主机下阅读或修改源代码,这里就需要使用到 「共享文件」 这个机制了。本文介绍了两种共享文...

良许Linux
58分钟前
4
0
JUC锁框架——AQS源码分析

JUC锁介绍 Java的并发框架JUC(java.util.concurrent)中锁是最重要的一个工具。因为锁,才能实现正确的并发访问。而AbstractQueuedSynchronizer(AQS)是一个用来构建锁和同步器的框架,使用A...

长头发-dawn
今天
1
0
docker中安装了RabbitMQ后无法访问其Web管理页面

在官网找了"$ docker run -d --hostname my-rabbit --name some-rabbit -p 8080:15672 rabbitmq:3-management"这条安装命令,在docker上安装了RabbitMQ,,结果输入http://localhost:8080并不......

钟然千落
今天
4
1
spring-cloud | 分布式session共享

写在前面的话 各位小伙伴,你们有福了,这一节不仅教大家怎么实现分布式session的问题,还用kotlin开发,喜欢kotlin的小伙伴是不是很开心! 以前在写Android的时候,就对客户端请求有一定的认...

冯文议
今天
3
0
c语言之内存分配笔记

先看一个数组: short array[5] = {1,2} // 这儿定义的一个int类型的数组,数组第1和第2个元素值是1和2.其余后面默认会给值为0; 或者 short array[] = {1,2};//这儿数组第1和第2个元素,数组...

DannyCoder
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部