@Test public void testGetDebuggableFromBinaryAndroidManifest() throws Exception { ByteBuffer manifest = getAndroidManifest("original.apk"); assertFalse(ApkUtils.getDebuggableFromBinaryAndroidManifest(manifest)); manifest = getAndroidManifest("debuggable-boolean.apk"); assertTrue(ApkUtils.getDebuggableFromBinaryAndroidManifest(manifest)); manifest = getAndroidManifest("debuggable-resource.apk"); try { ApkUtils.getDebuggableFromBinaryAndroidManifest(manifest); fail(); } catch (ApkFormatException expected) {} }
public static boolean getDebuggableFromBinaryAndroidManifest( ByteBuffer androidManifestContents) throws ApkFormatException { try { AndroidBinXmlParser parser = new AndroidBinXmlParser(androidManifestContents); int eventType = parser.getEventType(); while (eventType != AndroidBinXmlParser.EVENT_END_DOCUMENT) { if ((eventType == AndroidBinXmlParser.EVENT_START_ELEMENT) && (parser.getDepth() == 2) && ("application".equals(parser.getName())) && (parser.getNamespace().isEmpty())) { for (int i = 0; i < parser.getAttributeCount(); i++) { if (parser.getAttributeNameResourceId(i) == DEBUGGABLE_ATTR_ID) { int valueType = parser.getAttributeValueType(i); switch (valueType) { case AndroidBinXmlParser.VALUE_TYPE_BOOLEAN: case AndroidBinXmlParser.VALUE_TYPE_STRING: case AndroidBinXmlParser.VALUE_TYPE_INT: String value = parser.getAttributeStringValue(i); return ("true".equals(value)) || ("TRUE".equals(value)) || ("1".equals(value)); case AndroidBinXmlParser.VALUE_TYPE_REFERENCE: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute references a" + " resource. References are not supported for" + " security reasons. Only constant boolean," + " string and int values are supported."); default: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute uses" + " unsupported value type. Only boolean," + " string and int values are supported."); } } } return false; } eventType = parser.next(); } return false; } catch (AndroidBinXmlParser.XmlParserException e) { throw new ApkFormatException( "Unable to determine whether APK is debuggable: malformed binary resource: " + ANDROID_MANIFEST_ZIP_ENTRY_NAME, e); } }
ApkUtils { public static boolean getDebuggableFromBinaryAndroidManifest( ByteBuffer androidManifestContents) throws ApkFormatException { try { AndroidBinXmlParser parser = new AndroidBinXmlParser(androidManifestContents); int eventType = parser.getEventType(); while (eventType != AndroidBinXmlParser.EVENT_END_DOCUMENT) { if ((eventType == AndroidBinXmlParser.EVENT_START_ELEMENT) && (parser.getDepth() == 2) && ("application".equals(parser.getName())) && (parser.getNamespace().isEmpty())) { for (int i = 0; i < parser.getAttributeCount(); i++) { if (parser.getAttributeNameResourceId(i) == DEBUGGABLE_ATTR_ID) { int valueType = parser.getAttributeValueType(i); switch (valueType) { case AndroidBinXmlParser.VALUE_TYPE_BOOLEAN: case AndroidBinXmlParser.VALUE_TYPE_STRING: case AndroidBinXmlParser.VALUE_TYPE_INT: String value = parser.getAttributeStringValue(i); return ("true".equals(value)) || ("TRUE".equals(value)) || ("1".equals(value)); case AndroidBinXmlParser.VALUE_TYPE_REFERENCE: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute references a" + " resource. References are not supported for" + " security reasons. Only constant boolean," + " string and int values are supported."); default: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute uses" + " unsupported value type. Only boolean," + " string and int values are supported."); } } } return false; } eventType = parser.next(); } return false; } catch (AndroidBinXmlParser.XmlParserException e) { throw new ApkFormatException( "Unable to determine whether APK is debuggable: malformed binary resource: " + ANDROID_MANIFEST_ZIP_ENTRY_NAME, e); } } }
ApkUtils { public static boolean getDebuggableFromBinaryAndroidManifest( ByteBuffer androidManifestContents) throws ApkFormatException { try { AndroidBinXmlParser parser = new AndroidBinXmlParser(androidManifestContents); int eventType = parser.getEventType(); while (eventType != AndroidBinXmlParser.EVENT_END_DOCUMENT) { if ((eventType == AndroidBinXmlParser.EVENT_START_ELEMENT) && (parser.getDepth() == 2) && ("application".equals(parser.getName())) && (parser.getNamespace().isEmpty())) { for (int i = 0; i < parser.getAttributeCount(); i++) { if (parser.getAttributeNameResourceId(i) == DEBUGGABLE_ATTR_ID) { int valueType = parser.getAttributeValueType(i); switch (valueType) { case AndroidBinXmlParser.VALUE_TYPE_BOOLEAN: case AndroidBinXmlParser.VALUE_TYPE_STRING: case AndroidBinXmlParser.VALUE_TYPE_INT: String value = parser.getAttributeStringValue(i); return ("true".equals(value)) || ("TRUE".equals(value)) || ("1".equals(value)); case AndroidBinXmlParser.VALUE_TYPE_REFERENCE: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute references a" + " resource. References are not supported for" + " security reasons. Only constant boolean," + " string and int values are supported."); default: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute uses" + " unsupported value type. Only boolean," + " string and int values are supported."); } } } return false; } eventType = parser.next(); } return false; } catch (AndroidBinXmlParser.XmlParserException e) { throw new ApkFormatException( "Unable to determine whether APK is debuggable: malformed binary resource: " + ANDROID_MANIFEST_ZIP_ENTRY_NAME, e); } } private  ApkUtils(); }
ApkUtils { public static boolean getDebuggableFromBinaryAndroidManifest( ByteBuffer androidManifestContents) throws ApkFormatException { try { AndroidBinXmlParser parser = new AndroidBinXmlParser(androidManifestContents); int eventType = parser.getEventType(); while (eventType != AndroidBinXmlParser.EVENT_END_DOCUMENT) { if ((eventType == AndroidBinXmlParser.EVENT_START_ELEMENT) && (parser.getDepth() == 2) && ("application".equals(parser.getName())) && (parser.getNamespace().isEmpty())) { for (int i = 0; i < parser.getAttributeCount(); i++) { if (parser.getAttributeNameResourceId(i) == DEBUGGABLE_ATTR_ID) { int valueType = parser.getAttributeValueType(i); switch (valueType) { case AndroidBinXmlParser.VALUE_TYPE_BOOLEAN: case AndroidBinXmlParser.VALUE_TYPE_STRING: case AndroidBinXmlParser.VALUE_TYPE_INT: String value = parser.getAttributeStringValue(i); return ("true".equals(value)) || ("TRUE".equals(value)) || ("1".equals(value)); case AndroidBinXmlParser.VALUE_TYPE_REFERENCE: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute references a" + " resource. References are not supported for" + " security reasons. Only constant boolean," + " string and int values are supported."); default: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute uses" + " unsupported value type. Only boolean," + " string and int values are supported."); } } } return false; } eventType = parser.next(); } return false; } catch (AndroidBinXmlParser.XmlParserException e) { throw new ApkFormatException( "Unable to determine whether APK is debuggable: malformed binary resource: " + ANDROID_MANIFEST_ZIP_ENTRY_NAME, e); } } private  ApkUtils(); static ZipSections findZipSections(DataSource apk); static void setZipEocdCentralDirectoryOffset(
            ByteBuffer zipEndOfCentralDirectory, long offset); static ApkSigningBlock findApkSigningBlock(DataSource apk, ZipSections zipSections); static ByteBuffer getAndroidManifest(DataSource apk); static int getMinSdkVersionFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); static boolean getDebuggableFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); static String getPackageNameFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); }
ApkUtils { public static boolean getDebuggableFromBinaryAndroidManifest( ByteBuffer androidManifestContents) throws ApkFormatException { try { AndroidBinXmlParser parser = new AndroidBinXmlParser(androidManifestContents); int eventType = parser.getEventType(); while (eventType != AndroidBinXmlParser.EVENT_END_DOCUMENT) { if ((eventType == AndroidBinXmlParser.EVENT_START_ELEMENT) && (parser.getDepth() == 2) && ("application".equals(parser.getName())) && (parser.getNamespace().isEmpty())) { for (int i = 0; i < parser.getAttributeCount(); i++) { if (parser.getAttributeNameResourceId(i) == DEBUGGABLE_ATTR_ID) { int valueType = parser.getAttributeValueType(i); switch (valueType) { case AndroidBinXmlParser.VALUE_TYPE_BOOLEAN: case AndroidBinXmlParser.VALUE_TYPE_STRING: case AndroidBinXmlParser.VALUE_TYPE_INT: String value = parser.getAttributeStringValue(i); return ("true".equals(value)) || ("TRUE".equals(value)) || ("1".equals(value)); case AndroidBinXmlParser.VALUE_TYPE_REFERENCE: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute references a" + " resource. References are not supported for" + " security reasons. Only constant boolean," + " string and int values are supported."); default: throw new ApkFormatException( "Unable to determine whether APK is debuggable" + ": " + ANDROID_MANIFEST_ZIP_ENTRY_NAME + "'s" + " android:debuggable attribute uses" + " unsupported value type. Only boolean," + " string and int values are supported."); } } } return false; } eventType = parser.next(); } return false; } catch (AndroidBinXmlParser.XmlParserException e) { throw new ApkFormatException( "Unable to determine whether APK is debuggable: malformed binary resource: " + ANDROID_MANIFEST_ZIP_ENTRY_NAME, e); } } private  ApkUtils(); static ZipSections findZipSections(DataSource apk); static void setZipEocdCentralDirectoryOffset(
            ByteBuffer zipEndOfCentralDirectory, long offset); static ApkSigningBlock findApkSigningBlock(DataSource apk, ZipSections zipSections); static ByteBuffer getAndroidManifest(DataSource apk); static int getMinSdkVersionFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); static boolean getDebuggableFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); static String getPackageNameFromBinaryAndroidManifest(
            ByteBuffer androidManifestContents); static final String ANDROID_MANIFEST_ZIP_ENTRY_NAME; }