package parser.axml; import org.apache.commons.io.IOUtils; import pxb.android.arsc.ArscDumper; import pxb.android.arsc.ArscParser; import pxb.android.arsc.Pkg; import pxb.android.axml.AxmlParser; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Created by acgmohu on 14-7-1. * <p/> * Parse AndroidManifest.xml and resources.arsc */ public class Parser { private HashMap<String, String> resources; private ManifestInfo manifestInfo = null; public Parser(File pFile) throws IOException { ZipFile zipFile = new ZipFile(pFile); InputStream aXMLInputStream; InputStream arscInputStream; ZipEntry zipEntry = zipFile.getEntry("resources.arsc"); if (zipEntry != null) { arscInputStream = zipFile.getInputStream(zipEntry); readArsc(IOUtils.toByteArray(arscInputStream)); } zipEntry = zipFile.getEntry("AndroidManifest.xml"); if (zipEntry != null) { aXMLInputStream = zipFile.getInputStream(zipEntry); readAxml(IOUtils.toByteArray(aXMLInputStream)); } zipFile.close(); } /** * Notice : axml not NULL. * * @param axmlBytes It's not null. * @param arscBytes resource.arsc * @throws IOException */ public Parser(byte[] axmlBytes, byte[] arscBytes) throws IOException { if (axmlBytes == null) { throw new IOException(); } if (arscBytes != null) { readArsc(arscBytes); } readAxml(axmlBytes); } public ManifestInfo getManifestInfo() { return manifestInfo; } private void readArsc(final byte[] arsc) throws IOException { List<Pkg> pkgs = new ArscParser(arsc).parse(); resources = ArscDumper.dumpResource(pkgs); } /** * example to read an axml * * @param androidManifestData The content of AndroidManifest.xml inside apk * @throws java.io.IOException */ private void readAxml(final byte[] androidManifestData) throws IOException { manifestInfo = new ManifestInfo(); String key = null; AxmlParser parser = new AxmlParser(androidManifestData); final byte FLAG_DEFAULT = -1; final byte FLAG_ACTIVITY = 0; final byte FLAG_RECEIVER = 1; byte flag = FLAG_DEFAULT; out: while (true) { int event = parser.next(); switch (event) { case AxmlParser.START_FILE: break; case AxmlParser.END_FILE: break out; case AxmlParser.START_TAG: String tagName = parser.getName(); switch (tagName) { case "manifest": parseTagManifest(parser); break; case "application": parseTagApplication(parser); break; case "uses-permission": parseTagPermission(parser); break; case "activity": case "activity-alias": key = parseTagActivity(parser); if (key != null) { flag = FLAG_ACTIVITY; } else { flag = FLAG_DEFAULT; } break; case "service": parseTagService(parser); break; case "receiver": key = parseTagReceiver(parser); if (key != null) { flag = FLAG_RECEIVER; } else { flag = FLAG_DEFAULT; } break; case "action": if (flag == FLAG_ACTIVITY) { parseTagAction(parser, manifestInfo.activities.get(key)); } else if (flag == FLAG_RECEIVER) { parseTagAction(parser, manifestInfo.receivers.get(key)); } break; case "category": if (flag == FLAG_ACTIVITY) { parseTagCategory(parser, manifestInfo.activities.get(key)); } else if (flag == FLAG_RECEIVER) { parseTagCategory(parser, manifestInfo.receivers.get(key)); } break; case "meta-data": parseTagMetaData(parser); break; } case AxmlParser.END_TAG: } } // end of while ArrayList<String> permArr = new ArrayList<>(manifestInfo.permissions); Collections.sort(permArr); manifestInfo.requestedPermissions = permArr; Collections.sort(manifestInfo.services); } /** * get value from resource.arsc * * @param obj integer * @return value */ private String getValue(Object obj) { String value; if (obj instanceof Integer) { value = resources.get(obj.toString()); if (value == null) { value = obj.toString(); } } else { value = obj.toString(); } return value; } private void parseTagMetaData(AxmlParser parser) { String name = null; String value = null; for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = getValue(parser.getAttrValue(i)); if (attrName.contains("name")) { name = attrValue; } else if (attrName.contains("value") || attrName.contains("resource")) { value = attrValue; } } if (name != null) { manifestInfo.metaData.put(name, value); } } private void parseTagCategory(AxmlParser parser, ArrayList<String> arrayList) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = parser.getAttrValue(i).toString(); if (attrName.contains("name")) { arrayList.add(attrValue); break; } } } private String parseTagActivity(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = getValue(parser.getAttrValue(i)); if (attrName.equals("name")) { manifestInfo.activities.put(attrValue, new ArrayList<String>()); return attrValue; } } return null; } private void parseTagAction(AxmlParser parser, ArrayList<String> arrayList) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = parser.getAttrValue(i).toString(); if (attrName.contains("name")) { arrayList.add(attrValue); break; } } } private String parseTagReceiver(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = getValue(parser.getAttrValue(i)); if (attrName.equals("name")) { manifestInfo.receivers.put(attrValue, new ArrayList<String>()); return attrValue; } else if ("".equals(attrName)) { manifestInfo.receivers.put(attrValue + "[NOT Default AXML!]", new ArrayList<String>()); return attrValue + "[NOT Default AXML!]"; } } return null; } private void parseTagService(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = getValue(parser.getAttrValue(i)); if (attrName.equals("name")) { manifestInfo.services.add(attrValue); } else if ("".equals(attrName)) { // <service ="service_name"> manifestInfo.services.add(attrValue + "[NOT Default AXML!]"); } } } private void parseTagApplication(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = getValue(parser.getAttrValue(i)); if (attrName.contains("label")) { String tmp = resources.get(attrValue); if (tmp != null) { manifestInfo.label = tmp; } else { manifestInfo.label = attrValue; } break; } } } private void parseTagManifest(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = parser.getAttrValue(i).toString(); if (attrName.contains("versionName")) { manifestInfo.versionName = attrValue; } else if (attrName.contains("versionCode")) { manifestInfo.versionCode = attrValue; } else if (attrName.contains("package")) { manifestInfo.packageName = attrValue; } } } private void parseTagPermission(AxmlParser parser) { for (int i = 0; i != parser.getAttributeCount(); ++i) { String attrName = parser.getAttrName(i); String attrValue = parser.getAttrValue(i).toString(); if (attrName.contains("name")) { manifestInfo.permissions.add(attrValue); break; } } } }