阅读Android应用程序的ApplicationManifest使用.NET(APK) [英] Read ApplicationManifest of Android Application (apk) using .NET

查看:150
本文介绍了阅读Android应用程序的ApplicationManifest使用.NET(APK)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I'm工作,管理Android应用程序包(APK),程序的应用程序(使用.NET框架开发)具有为阅读ApplicationManifest.xml 驻留在APK内。从提取的APK清单文件是没有问题的,因为我可以使用标准ZIP工具从一个APK中提取的所有文件。

但是读取ApplicationManifest是不可能的。我预计它包含原始XML数据,但它以某种方式加密或EN codeD。

有没有使用.NET Framework的BCL来读取ApplicationManifest XML数据的方法吗?或者是有.NET框架读取ApplicationManifest库?

解决方案

我不建议使用上述apktool,因为它是不安全的自动解码 - 我用它出于同样的原因,你做了,但是它失败的情况。

有像 axml2xml 一些工具这是一家专业的Andr​​oid EN codeD XML文件或其他工具,如 Android的资产打包工具(AAPT)。您也可以code你自己脱codeR。

axml2xml是不完美的,所以我会建议运行的 AAPT (包含在Android SDK中)在您的APK,因为它打印了大量的信息,您可以解析: AAPT升-a< your.apk>

如果你想实现code解析清单自己,看看核糖的社区维基条目:

  // DECOM pressXML  - 解析Android的XML文档的COM pressed'二进制形式
//如的Andr​​oidManifest.xml中的apk文件
公共静态INT endDocTag = 0x00100101;
公共静态INT开始标记= 0x00100102;
公共静态INT结束标记= 0x00100103;
公共无效DECOM pressXML(byte []的XML){
//的COM pressed XML文件/字节,24X字节的数据开始,
在小尾数顺序// 9 32位字(LSB在前):
//第0个字是03 00 08 00
//第3个字似乎是:在胶印然后STRINGTABLE的
// 4个字是:在字符串表中的字符串数
//警告:有时我indiscriminently显示或引用字
//小端存储格式,或以整数形式(即高位在前)。
INT numbStrings = LEW(XML,4 * 4);

// StringIndexTable开始于偏移24倍,32位LE偏移量的数组
在STRINGTABLE长度/串数据//。
INT sitOff = 0X24; //偏移StringIndexTable的开始

// STRINGTABLE,每个字符串psented有16位小尾重$ P $
//字符数,其次是16号位(LE)(单面code)字符的。
INT STOFF = sitOff + numbStrings * 4; // STRINGTABLE如下StrIndexTable

// XMLTags,经过一些不知名的内容之后的XML标签树开始
// STRINGTABLE。还有就是STRINGTABLE后,一些未知的数据,扫描
从这个角度来标志一个XML开始标记的开始//前进。
INT xmlTagOff = LEW(XML,3 * 4); //开始从偏移在第3个字。
//扫描着,直到我们找到的字节:0x02011000(x00100102正常INT)
为(中间体二= xmlTagOff; II蛋白酶xml.length-4;ⅱ+ = 4){
  如果(LEW(XML,ⅱ)==开始标记){
    xmlTagOff =二;打破;
  }
} //结束黑客攻击,扫描第一个开始标记开始

// XML标签和属性:
//每个XML开始和结束标记由6个32位字:
//第0个字:02011000的开始标记和03011000的结束标记
//第1个字:一个标志?像3800
//第2个字:条线的这个标记出现在原始的源文件中
//第3个字:FFFFFFFF?
//第4个字:StringIndex的命名空间名称,或者FFFFFFFF缺省NS
//第5个字:的元素名称StringIndex
//(注:在第0字01011000装置的XML文档的末尾,endDocTag)

//开始标签(没有结束标记),包含3个字:
//第6个字:14001400意思?
// 7字:按照这个标签的属性数量(按照字8日)
//第8个字:00000000意思?

//属性包括5个字:
//第0个字:StringIndex属性名称的命名空间,或FFFFFFFF
//第1个字:StringIndex的属性名称
//第2个字:StringIndex属性值,或者FFFFFFF如果RESOURCEID使用
//第3个字:旗?
//第4个字:ATTR价值海峡IND一次,或价值RESOURCEID

// TMP,转储字符串表TR进行调试
//tr.addSelect("strings,NULL);
//对于(中间体二= 0; II蛋白酶numbStrings;ⅱ++){
// //长度字符串的开始于STRINGTABLE加上StrIndTable偏移
//字符串str = compXmlString(XML,sitOff,STOFF,二);
// tr.add(将String.valueOf(ii)中,STR);
//}
//tr.parent();

//通过XML树元素标记和属性步骤
诠释关闭= xmlTagOff;
INT缩进= 0;
INT startTagLineNo = -2;
而(关< xml.length){
  INT tag0 = LEW(XML,关闭);
  // INT标签1 = LEW(XML,关+ 1 * 4);
  INT lineNo的= LEW(XML,关+ 2 * 4);
  // INT TAG3 = LEW(XML,关+ 3 * 4);
  INT nameNsSi = LEW(XML,关闭+ 4 * 4);
  INT nameSi = LEW(XML,关+ 5 * 4);

  如果(tag0 ==开始标记){// XML开始标记
    INT tag6 = LEW(XML,关+ 6 * 4); //预计为14001400
    INT numbAttrs = LEW(XML,关+ 7 * 4); //属性数跟随
    // INT tag8 = LEW(XML,关+ 8 * 4); //预计为00000000
    关闭+ = 9 * 4; //跳过6 + 3个字的开始标记数据
    字符串名称= compXmlString(XML,sitOff,STOFF,nameSi);
    //tr.addSelect(name,NULL);
    startTagLineNo = lineNo的;

    //查找属性
    StringBuffer的SB =新的StringBuffer();
    为(中间体二= 0; II蛋白酶numbAttrs;ⅱ++){
      INT attrNameNsSi = LEW(XML,关闭); // AttrName命名空间海峡工业,或FFFFFFFF
      INT attrNameSi = LEW(XML,关+ 1 * 4); // AttrName字符串索引
      INT attrValueSi = LEW(XML,关+ 2 * 4); // AttrValue海峡工业,或FFFFFFFF
      INT attrFlags = LEW(XML,关+ 3 * 4);
      INT attrResId = LEW(XML,关闭+ 4 * 4); // AttrValue RESOURCEID或DUP AttrValue StrInd
      关闭+ = 5 * 4; //跳过了5个字的属性

      字符串attrName = compXmlString(XML,sitOff,STOFF,attrNameSi);
      字符串attrValue = attrValueSi!=  -  1
        ? compXmlString(XML,sitOff,STOFF,attrValueSi)
        :RESOURCEID 0X+ Integer.toHexString(attrResId);
      sb.append(+ attrName += \+ attrValue +\);
      //tr.add(attrName,attrValue);
    }
    prtIndent(缩进,<+姓名+ SB +>中);
    缩进++;

  }否则,如果(tag0 ==结束标记){// XML结束标记
    indent--;
    关闭+ = 6 * 4; //跳过6个字的结束标记数据
    字符串名称= compXmlString(XML,sitOff,STOFF,nameSi);
    prtIndent(缩进,&所述; /+名称+>(线+ startTagLineNo + - + lineNo的值+));
    //tr.parent(); //退一步了NobTree

  }否则,如果(tag0 == endDocTag){//结束XML文档标签
    打破;

  } 其他 {
    PRT(无法识别的标签code'+ Integer.toHexString(tag0)
      +偏移量+关闭);
    打破;
  }
中} //结束while循环扫描标签和XML树的属性
PRT(结束偏移量+关闭);
DECOM pressXML的} //结束


公共字符串compXmlString(byte []的XML,INT sitOff,诠释STOFF,诠释strInd){
  如果(strInd℃下)返回NULL;
  INT strOff = STOFF + LEW(XML,sitOff + strInd * 4);
  返回compXmlStringAt(XML,strOff);
}


公共静态字符串空间=;
公共无效prtIndent(INT缩进,字符串str){
  PRT(spaces.substring(0,Math.min(缩进* 2,spaces.length()))+ STR);
}


// compXmlStringAt  - 返回的存储在STRINGTABLE格式字符串
//偏移strOff。此偏移指向16位串长度,这
//后面是一些16位(统一code)字符。
公共字符串compXmlStringAt(byte []的编曲,诠释strOff){
  INT STRLEN =改编[strOff + 1];&所述8安培;为0xFF00 | ARR [strOff]放大器; 0xFF的;
  byte []的字符=新的字节[strlen的]。
  为(中间体二= 0; II蛋白酶strlen的;ⅱ++){
    字符[Ⅱ] =改编[strOff + 2 +二* 2];
  }
  返回新的字符串(字); //哈克,只需用8个字节的字符
} // compXmlStringAt结束


// LEW  - 小端32位字从字节数组返回值
//在抵消掉。
公众诠释LEW(byte []的改编,整数关){
  返回ARR [关+ 3]<< 24安培; 0xff000000 | ARR [关+ 2]其中;< 16安培,为0xFF0000
    |改编[关+ 1];&所述8安培;为0xFF00 | ARR [关闭]放大器; 0xFF的;
} // LEW结束
 

  

此方法读取AndroidManifest到byte []进行处理:

 公共无效getIntents(字符串路径){
  尝试 {
    jar文件JF =新的jar文件(路径);
    InputStream的是= jf.getInputStream(jf.getEntry(AndroidManifest.xml中));
    byte []的XML =新的字节[is.available()];
    INT BR = is.​​read(XML);
    //树TR = TrunkFactory.newTree();
    DECOM pressXML(XML);
    // PRT(XML \ N+ tr.list());
  }赶上(例外前){
    的console.log(getIntents,如:+前); ex.printStackTrace();
  }
} // getIntents结束
 

在最后,我会建议解析 AAPT 输出(你可以和你的应用程序捆绑在一起的话)。

I´m working on an application (developed with .NET Framework) that manages Android Application packages (apk) and the program has to read the ApplicationManifest.xml that resides inside the apk. Extracting the Manifest file from the apk is no problem, because I can use standard zip tools to extract all files from an apk.

But reading the ApplicationManifest is not possible. I expected that it contains raw XML data, but it's somehow encrypted or encoded.

Is there a way using the BCL of the .NET Framework to read the XML data from the ApplicationManifest? Or is there a library for the .NET Framework to read the ApplicationManifest?

解决方案

I would not recommend using the mentioned apktool, as it is not safe for automated decoding - I used to use it for the same reason as you did, but it failed in some cases.

There are some tools like axml2xml that are specialized in Android encoded XML files or other tools like Android Asset Packaging Tool (aapt). You can also code a decoder on your own.

axml2xml is not perfect, so I would recommend running aapt (included in Android SDK) on your apk, as it print a lot of information you can parse: aapt l -a <your.apk>

If you want to implement code to parse the Manifest yourself, have a look at ribo's community wiki entry:

// decompressXML -- Parse the 'compressed' binary form of Android XML docs 
// such as for AndroidManifest.xml in .apk files
public static int endDocTag = 0x00100101;
public static int startTag =  0x00100102;
public static int endTag =    0x00100103;
public void decompressXML(byte[] xml) {
// Compressed XML file/bytes starts with 24x bytes of data,
// 9 32 bit words in little endian order (LSB first):
//   0th word is 03 00 08 00
//   3rd word SEEMS TO BE:  Offset at then of StringTable
//   4th word is: Number of strings in string table
// WARNING: Sometime I indiscriminently display or refer to word in 
//   little endian storage format, or in integer format (ie MSB first).
int numbStrings = LEW(xml, 4*4);

// StringIndexTable starts at offset 24x, an array of 32 bit LE offsets
// of the length/string data in the StringTable.
int sitOff = 0x24;  // Offset of start of StringIndexTable

// StringTable, each string is represented with a 16 bit little endian 
// character count, followed by that number of 16 bit (LE) (Unicode) chars.
int stOff = sitOff + numbStrings*4;  // StringTable follows StrIndexTable

// XMLTags, The XML tag tree starts after some unknown content after the
// StringTable.  There is some unknown data after the StringTable, scan
// forward from this point to the flag for the start of an XML start tag.
int xmlTagOff = LEW(xml, 3*4);  // Start from the offset in the 3rd word.
// Scan forward until we find the bytes: 0x02011000(x00100102 in normal int)
for (int ii=xmlTagOff; ii<xml.length-4; ii+=4) {
  if (LEW(xml, ii) == startTag) { 
    xmlTagOff = ii;  break;
  }
} // end of hack, scanning for start of first start tag

// XML tags and attributes:
// Every XML start and end tag consists of 6 32 bit words:
//   0th word: 02011000 for startTag and 03011000 for endTag 
//   1st word: a flag?, like 38000000
//   2nd word: Line of where this tag appeared in the original source file
//   3rd word: FFFFFFFF ??
//   4th word: StringIndex of NameSpace name, or FFFFFFFF for default NS
//   5th word: StringIndex of Element Name
//   (Note: 01011000 in 0th word means end of XML document, endDocTag)

// Start tags (not end tags) contain 3 more words:
//   6th word: 14001400 meaning?? 
//   7th word: Number of Attributes that follow this tag(follow word 8th)
//   8th word: 00000000 meaning??

// Attributes consist of 5 words: 
//   0th word: StringIndex of Attribute Name's Namespace, or FFFFFFFF
//   1st word: StringIndex of Attribute Name
//   2nd word: StringIndex of Attribute Value, or FFFFFFF if ResourceId used
//   3rd word: Flags?
//   4th word: str ind of attr value again, or ResourceId of value

// TMP, dump string table to tr for debugging
//tr.addSelect("strings", null);
//for (int ii=0; ii<numbStrings; ii++) {
//  // Length of string starts at StringTable plus offset in StrIndTable
//  String str = compXmlString(xml, sitOff, stOff, ii);
//  tr.add(String.valueOf(ii), str);
//}
//tr.parent();

// Step through the XML tree element tags and attributes
int off = xmlTagOff;
int indent = 0;
int startTagLineNo = -2;
while (off < xml.length) {
  int tag0 = LEW(xml, off);
  //int tag1 = LEW(xml, off+1*4);
  int lineNo = LEW(xml, off+2*4);
  //int tag3 = LEW(xml, off+3*4);
  int nameNsSi = LEW(xml, off+4*4);
  int nameSi = LEW(xml, off+5*4);

  if (tag0 == startTag) { // XML START TAG
    int tag6 = LEW(xml, off+6*4);  // Expected to be 14001400
    int numbAttrs = LEW(xml, off+7*4);  // Number of Attributes to follow
    //int tag8 = LEW(xml, off+8*4);  // Expected to be 00000000
    off += 9*4;  // Skip over 6+3 words of startTag data
    String name = compXmlString(xml, sitOff, stOff, nameSi);
    //tr.addSelect(name, null);
    startTagLineNo = lineNo;

    // Look for the Attributes
    StringBuffer sb = new StringBuffer();
    for (int ii=0; ii<numbAttrs; ii++) {
      int attrNameNsSi = LEW(xml, off);  // AttrName Namespace Str Ind, or FFFFFFFF
      int attrNameSi = LEW(xml, off+1*4);  // AttrName String Index
      int attrValueSi = LEW(xml, off+2*4); // AttrValue Str Ind, or FFFFFFFF
      int attrFlags = LEW(xml, off+3*4);  
      int attrResId = LEW(xml, off+4*4);  // AttrValue ResourceId or dup AttrValue StrInd
      off += 5*4;  // Skip over the 5 words of an attribute

      String attrName = compXmlString(xml, sitOff, stOff, attrNameSi);
      String attrValue = attrValueSi!=-1
        ? compXmlString(xml, sitOff, stOff, attrValueSi)
        : "resourceID 0x"+Integer.toHexString(attrResId);
      sb.append(" "+attrName+"=\""+attrValue+"\"");
      //tr.add(attrName, attrValue);
    }
    prtIndent(indent, "<"+name+sb+">");
    indent++;

  } else if (tag0 == endTag) { // XML END TAG
    indent--;
    off += 6*4;  // Skip over 6 words of endTag data
    String name = compXmlString(xml, sitOff, stOff, nameSi);
    prtIndent(indent, "</"+name+">  (line "+startTagLineNo+"-"+lineNo+")");
    //tr.parent();  // Step back up the NobTree

  } else if (tag0 == endDocTag) {  // END OF XML DOC TAG
    break;

  } else {
    prt("  Unrecognized tag code '"+Integer.toHexString(tag0)
      +"' at offset "+off);
    break;
  }
} // end of while loop scanning tags and attributes of XML tree
prt("    end at offset "+off);
} // end of decompressXML


public String compXmlString(byte[] xml, int sitOff, int stOff, int strInd) {
  if (strInd < 0) return null;
  int strOff = stOff + LEW(xml, sitOff+strInd*4);
  return compXmlStringAt(xml, strOff);
}


public static String spaces = "                                             ";
public void prtIndent(int indent, String str) {
  prt(spaces.substring(0, Math.min(indent*2, spaces.length()))+str);
}


// compXmlStringAt -- Return the string stored in StringTable format at
// offset strOff.  This offset points to the 16 bit string length, which 
// is followed by that number of 16 bit (Unicode) chars.
public String compXmlStringAt(byte[] arr, int strOff) {
  int strLen = arr[strOff+1]<<8&0xff00 | arr[strOff]&0xff;
  byte[] chars = new byte[strLen];
  for (int ii=0; ii<strLen; ii++) {
    chars[ii] = arr[strOff+2+ii*2];
  }
  return new String(chars);  // Hack, just use 8 byte chars
} // end of compXmlStringAt


// LEW -- Return value of a Little Endian 32 bit word from the byte array
//   at offset off.
public int LEW(byte[] arr, int off) {
  return arr[off+3]<<24&0xff000000 | arr[off+2]<<16&0xff0000
    | arr[off+1]<<8&0xff00 | arr[off]&0xFF;
} // end of LEW

This method reads the AndroidManifest into a byte[] for processing:

public void getIntents(String path) {
  try {
    JarFile jf = new JarFile(path);
    InputStream is = jf.getInputStream(jf.getEntry("AndroidManifest.xml"));
    byte[] xml = new byte[is.available()];
    int br = is.read(xml);
    //Tree tr = TrunkFactory.newTree();
    decompressXML(xml);
    //prt("XML\n"+tr.list());
  } catch (Exception ex) {
    console.log("getIntents, ex: "+ex);  ex.printStackTrace();
  }
} // end of getIntents

In conclusion, I would recommend parsing the aapt output (you could bundle it with your application).

这篇关于阅读Android应用程序的ApplicationManifest使用.NET(APK)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆