def __init__(self, apk): self.apk = apk self.zip_file = get_zip_file(apk) self.validate() self.axml = AXMLPrinter(self.zip_file.read('AndroidManifest.xml')) self.xml = self.axml.get_xml_obj() self.arsc = ARSCParser(self.zip_file.read('resources.arsc'))
def test_app_name_extraction(): axml_file = os.path.join(test_apk, "AndroidManifest.xml") axml = AXMLPrinter(open(axml_file, "rb").read()).xml_object app_name_hex = axml.findall(".//application")[0].get(NS_ANDROID + "label") appnamehex = "0x" + app_name_hex[1:] rsc_file = os.path.join(test_apk, "resources.arsc") rsc = ARSCParser(open(rsc_file, "rb").read()) app_name = rsc.get_string( rsc.first_package_name, rsc.get_id(rsc.first_package_name, int(appnamehex, 0))[1], ) assert app_name == ["app_name", "Evie"]
def test_app_name_extraction(): axml_file = os.path.join(test_apk, 'AndroidManifest.xml') axml = AXMLPrinter(open(axml_file, 'rb').read()).get_xml_obj() app_name_hex = axml.findall(".//application")[0].get(NS_ANDROID + "label") appnamehex = '0x' + app_name_hex[1:] rsc_file = os.path.join(test_apk, 'resources.arsc') rsc = ARSCParser(open(rsc_file, 'rb').read()) app_name = rsc.get_string( rsc.get_packages_names()[0], rsc.get_id(rsc.get_packages_names()[0], int(appnamehex, 0))[1]) assert app_name == ['app_name', 'Evie']
class APK: def __init__(self, apk): self.apk = apk self.zip_file = get_zip_file(apk) self.validate() self.axml = AXMLPrinter(self.zip_file.read('AndroidManifest.xml')) self.xml = self.axml.get_xml_obj() self.arsc = ARSCParser(self.zip_file.read('resources.arsc')) def validate(self): zip_files = set(self.zip_file.namelist()) required_files = {'AndroidManifest.xml', 'resources.arsc'} assert required_files.issubset(zip_files) @property def application(self): app_name_hex = self.xml.getElementsByTagName( "application")[0].getAttribute("android:label") if not app_name_hex.startswith('@'): return app_name_hex _pkg_name = self.arsc.get_packages_names()[0] app_name = self.get_resource(app_name_hex, _pkg_name) if app_name: return app_name return self.package @property def version_name(self): version_name = getxml_value(self.xml.documentElement, "versionName") if not version_name.startswith("@"): return version_name rsc = self.get_resource(version_name, self.package) if rsc: version_name = rsc return version_name def get_resource(self, key, value): try: key = '0x' + key[1:] hex_value = self.arsc.get_id(value, int(key, 0))[1] rsc = self.arsc.get_string(value, hex_value)[1] except: rsc = None return rsc @property def version_code(self): version_code = getxml_value(self.xml.documentElement, "versionCode") return version_code @property def package(self): return self.xml.documentElement.getAttribute("package") @property def icon_info(self): icon_type, icon_name = None, None app = self.xml.getElementsByTagName('application')[0] app_icon = app.getAttribute('android:icon')[1:] if app_icon: icon_id = int('0x' + app_icon, 0) icon_data = self.arsc.get_id(self.package, icon_id) if icon_data: icon_type, icon_name = icon_data[0], icon_data[1] return icon_type, icon_name @property def icon_data(self): icon_type, icon_name = self.icon_info if not icon_name: return if icon_type and 'mipmap' in icon_type: search_path = 'res/mipmap' else: search_path = 'res/drawable' for filename in self.zip_file.namelist(): if filename.startswith(search_path): if icon_name in filename.split('/')[-1].rsplit('.', 1): icon_data = self.zip_file.read(filename) return icon_data
class APK: def __init__(self, apk): self.apk = apk self.zip_file = get_zip_file(apk) self.validate() self.axml = AXMLPrinter(self.zip_file.read('AndroidManifest.xml')) self.xml = self.axml.get_xml_obj() self.arsc = ARSCParser(self.zip_file.read('resources.arsc')) def validate(self): zip_files = set(self.zip_file.namelist()) required_files = {'AndroidManifest.xml', 'resources.arsc'} assert required_files.issubset(zip_files) def get_element(self, tag_name, attribute, **attribute_filter): """ Return element in xml files which match with the tag name and the specific attribute :param tag_name: specify the tag name :type tag_name: string :param attribute: specify the attribute :type attribute: string :rtype: string """ tag = self.xml.findall('.//' + tag_name) if len(tag) == 0: return None for item in tag: skip_this_item = False for attr, val in list(attribute_filter.items()): attr_val = item.get(NS_ANDROID + attr) if attr_val != val: skip_this_item = True break if skip_this_item: continue value = item.get(NS_ANDROID + attribute) if value is not None: return value return None def _format_value(self, value): """ Format a value with packagename, if not already set :param value: :return: """ if len(value) > 0: if value[0] == ".": value = self.package + value else: v_dot = value.find(".") if v_dot == 0: value = self.package + "." + value elif v_dot == -1: value = self.package + "." + value return value def get_main_activity(self): """ Return the name of the main activity This value is read from the AndroidManifest.xml :rtype: str """ x = set() y = set() activities_and_aliases = self.xml.findall(".//activity") + \ self.xml.findall(".//activity-alias") for item in activities_and_aliases: # Some applications have more than one MAIN activity. # For example: paid and free content activityEnabled = item.get(NS_ANDROID + "enabled") if activityEnabled is not None and \ activityEnabled != "" and activityEnabled == "false": continue for sitem in item.findall(".//action"): val = sitem.get(NS_ANDROID + "name") if val == "android.intent.action.MAIN": x.add(item.get(NS_ANDROID + "name")) for sitem in item.findall(".//category"): val = sitem.get(NS_ANDROID + "name") if val == "android.intent.category.LAUNCHER": y.add(item.get(NS_ANDROID + "name")) z = x.intersection(y) if len(z) > 0: return self._format_value(z.pop()) return None @property def application(self): """ Return the appname of the APK This name is read from the AndroidManifest.xml using the application android:label. If no label exists, the android:label of the main activity is used. If there is also no main activity label, an empty string is returned. :rtype: :class:`str` """ app_name = self.get_element('application', 'label') if not app_name: main_activity_name = self.get_main_activity() app_name = self.get_element('activity', 'label', name=main_activity_name) if app_name is None: # No App name set # TODO return packagename instead? return self.package if app_name.startswith("@"): res_id = int(app_name[1:], 16) res_parser = self.arsc try: app_name = res_parser.get_resolved_res_configs( res_id, ARSCResTableConfig.default_config())[0][1] except Exception as e: warn("Exception selecting app name: %s" % e) app_name = self.package return app_name @property def version_name(self): version_name = self.xml.get(NS_ANDROID + "versionName") if not version_name.startswith("@"): return version_name rsc = self.get_resource(version_name, self.package) if rsc: version_name = rsc return version_name def get_resource(self, key, value): try: key = '0x' + key[1:] hex_value = self.arsc.get_id(value, int(key, 0))[1] rsc = self.arsc.get_string(value, hex_value)[1] except Exception as e: warn(str(e)) rsc = None return rsc @property def version_code(self): version_code = self.xml.get(NS_ANDROID + "versionCode") return version_code @property def package(self): return self.xml.get("package") @property def icon_info(self): icon_type, icon_name = None, None app = self.xml.findall('.//application')[0] app_icon = app.get(NS_ANDROID + 'icon')[1:] if app_icon: icon_id = int('0x' + app_icon, 0) icon_data = self.arsc.get_id(self.package, icon_id) if icon_data: icon_type, icon_name = icon_data[0], icon_data[1] return icon_type, icon_name @property def icon_data(self): max_dpi = 65536 main_activity_name = self.get_main_activity() app_icon = self.get_element('activity', 'icon', name=main_activity_name) if not app_icon: app_icon = self.get_element('application', 'icon') if not app_icon: res_id = self.arsc.get_res_id_by_key(self.package, 'mipmap', 'ic_launcher') if res_id: app_icon = "@%x" % res_id if not app_icon: res_id = self.arsc.get_res_id_by_key(self.package, 'drawable', 'ic_launcher') if res_id: app_icon = "@%x" % res_id if not app_icon: # If the icon can not be found, return now return None if app_icon.startswith("@"): res_id = int(app_icon[1:], 16) res_parser = self.arsc candidates = res_parser.get_resolved_res_configs(res_id) app_icon = None current_dpi = -1 try: for config, file_name in candidates: dpi = config.get_density() if current_dpi < dpi <= max_dpi: app_icon = file_name current_dpi = dpi except Exception as e: warn("Exception selecting app icon: %s" % e) return self.zip_file.read(app_icon) @property def get_min_sdk_version(self): return self.get_element("uses-sdk", "minSdkVersion") @property def get_max_sdk_version(self): return self.get_element("uses-sdk", "maxSdkVersion") @property def get_target_sdk_version(self): return self.get_element("uses-sdk", "targetSdkVersion") @property def get_effective_target_sdk_version(self): """ Return the effective targetSdkVersion, always returns int > 0. If the targetSdkVersion is not set, it defaults to 1. This is set based on defaults as defined in: https://developer.android.com/guide/topics/manifest/uses-sdk-element.html :rtype: int """ target_sdk_version = self.get_target_sdk_version if not target_sdk_version: target_sdk_version = self.get_min_sdk_version try: return int(target_sdk_version) except (ValueError, TypeError): return 1
""" Usage: python get_app_name.py /path/to/extracted/apk/dir """ import sys from pyaxmlparser.arscparser import ARSCParser from pyaxmlparser.axmlprinter import AXMLPrinter app_root = sys.argv[1] xml = AXMLPrinter( open("{}/AndroidManifest.xml".format(app_root), 'rb').read()).get_xml_obj() rsc = ARSCParser(open("{}/resources.arsc".format(app_root), "rb").read()) app_name_hex = xml.getElementsByTagName("application")[0].getAttribute( "android:label") app_name = '0x' + app_name_hex[1:] app_name = rsc.get_string( rsc.get_packages_names()[0], rsc.get_id(rsc.get_packages_names()[0], int(app_name, 0))[1]) print('App name is "{}"'.format(app_name[1]))
if len(sys.argv) < 2: print("Usage:\npython get_app_name.py /path/to/extracted/apk/dir") exit(1) xml = None rsc = None app_name = None manifest_path = os.path.join(sys.argv[1], "AndroidManifest.xml") if os.path.exists(manifest_path): with open(manifest_path, "rb") as manifest_file: xml = AXMLPrinter(manifest_file.read()).xml_object resources_path = os.path.join(sys.argv[1], "resources.arsc") if os.path.exists(resources_path): with open(resources_path, "rb") as resources_file: rsc = ARSCParser(resources_file.read()) if xml and rsc: attribute = "android:label" attribute_ns = "{{http://schemas.android.com/apk/res/android}}android:label" app_name_hex = None for element_item in xml.findall(".//application"): value = None if element_item.get(attribute) is not None: value = element_item.get(attribute) elif element_item.get(attribute_ns) is not None: value = element_item.get(attribute_ns) if value is not None: app_name_hex = value break if app_name_hex: app_name = "0x" + app_name_hex[1:]