示例#1
0
 def build_manifest_from_apk(file: File, extended_processing: bool, apk_path: str) -> AndroidManifest:
     apk = Aapt.get_apk_info(apk_path)
     activities = []
     services = []
     receivers = []
     if extended_processing:
         manifest = Aapt.get_manifest_info(apk_path)
         activities = [AppActivity(name=activity) for activity in manifest["activities"]]
         services = [AppService(name=service) for service in manifest["services"]]
         receivers = [AppBroadcastReceiver(name=receiver) for receiver in manifest["receivers"]]
     return AndroidManifest(
         filename=file.get_file_name(),
         size=file.get_size(),
         md5hash=file.get_md5(),
         sha1hash=file.get_sha1(),
         sha256hash=file.get_sha256(),
         sha512hash=file.get_sha512(),
         package_name=apk["package_name"],
         version=AppVersion(code=apk["version"]["code"], name=apk["version"]["name"]),
         sdk=AppSdk(
             target_version=apk["sdk"]["target"],
             min_version=apk["sdk"]["min"],
             max_version=apk["sdk"]["max"]
         ),
         permissions=Aapt.get_app_permissions(apk_path),
         activities=activities,
         services=services,
         receivers=receivers
     )
示例#2
0
    def test_get_apk_info(self, mock_popen):
        dump_badging = b"package: name='com.example.app' versionCode='1' versionName='1.0' platformBuildVersionName='4'\n" \
                       b"sdkVersion:'10'\n" \
                       b"maxSdkVersion:'20'\n" \
                       b"targetSdkVersion:'15'"
        mock_popen.return_value = any_popen(dump_badging)

        apk = Aapt.get_apk_info("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual(
            {
                "package_name": "com.example.app",
                "version": {
                    "code": 1,
                    "name": "1.0"
                },
                "sdk": {
                    "max": "20",
                    "min": "10",
                    "target": "15"
                }
            },
            apk
        )
示例#3
0
    def test_execute_dump_xmltree(self, mock_popen):
        mock_popen.return_value = any_popen(b"any-result")

        result = Aapt._execute_dump_xmltree("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual("any-result", result)
示例#4
0
    def test_extract_app_name_when_application_label_is_not_present_but_launchable_activity_label_is(
            self):
        app_name = Aapt._extract_app_name(
            "launchable-activity: name='com.example.app.HomeActivity'  label='Example2'"
        )

        self.assertEqual("Example2", app_name)
示例#5
0
    def test_get_app_permissions_when_dumb_permissions_fails(self, mock_popen):
        mock_popen.side_effect = RuntimeError()

        permissions = Aapt.get_app_permissions("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual([], permissions)
示例#6
0
    def test_get_app_name_when_dumb_badging_fails(self, mock_popen):
        mock_popen.side_effect = RuntimeError()

        app_name = Aapt.get_app_name("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual("", app_name)
示例#7
0
    def test_get_manifest_info(self, mock_popen):
        dump_xmltree = b"N: android=http://schemas.android.com/apk/res/android\n" \
                       b"  E: manifest (line=2)\n" \
                       b"    E: application (line=8)\n" \
                       b"      E: activity (line=9)\n" \
                       b"        A: android:name(0x01010003)=\"any-activity\" (Raw: \"any-activity\")\n" \
                       b"      E: activity (line=15)\n" \
                       b"        A: android:name(0x01010003)=\"any-other-activity\" (Raw: \"any-other-activity\")\n" \
                       b"      E: service (line=25)\n" \
                       b"        A: android:name(0x01010003)=\"any-service\" (Raw: \"any-service\")\n" \
                       b"      E: service (line=26)\n" \
                       b"        A: android:name(0x01010003)=\"any-other-service\" (Raw: \"any-other-service\")\n" \
                       b"      E: receiver (line=28)\n" \
                       b"        A: android:name(0x01010003)=\"any-receiver\" (Raw: \"any-receiver\")\n" \
                       b"      E: receiver (line=29)\n" \
                       b"        A: android:name(0x01010003)=\"any-other-receiver\" (Raw: \"any-other-receiver\")"
        mock_popen.return_value = any_popen(dump_xmltree)

        manifest = Aapt.get_manifest_info("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual(
            {
                "activities": ["any-activity", "any-other-activity"],
                "services": ["any-service", "any-other-service"],
                "receivers": ["any-receiver", "any-other-receiver"]
            }, manifest)
示例#8
0
    def test_get_app_name(self, mock_popen):
        mock_popen.return_value = any_popen(b"application: label='Example' icon='res/ic_launcher.png'\n")

        app_name = Aapt.get_app_name("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual("Example", app_name)
示例#9
0
    def parse(self, filepath: str, extended_processing: bool = True):
        """
        :param filepath: path of the APK file
        :param extended_processing: (optional) whether should parse all information or only a summary. True by default.
        :return: the parsed APK file
        :raise: ApkParsingError if cannot parse the file as an APK
        """
        self.logger.debug("Parsing APK file: filepath=\"%s\"", filepath)
        if not self.looks_like_apk(filepath):
            raise ApkParsingError

        file = self.file_parser.parse(filepath)
        cert = None
        manifest = None
        dex_files = []
        other_files = []

        with ZipFile(filepath) as apk:
            tmpdir = self.__create_temporary_directory(ApkParser.__TEMPORARY_DIR)
            for filename in apk.namelist():
                entry_filepath = apk.extract(filename, tmpdir)
                self.logger.debug("Extracting APK resource %s to %s", filename, entry_filepath)
                try:
                    if AndroidManifestParser.looks_like_manifest(filename):
                        self.logger.debug("%s looks like an AndroidManifest.xml file", filename)
                        manifest = self.manifest_parser.parse(entry_filepath, True, filepath, True)
                    elif CertParser.looks_like_cert(filename):
                        self.logger.debug("%s looks like a CERT file", filename)
                        cert = self.__parse_cert(entry_filepath, filename, extended_processing)
                    elif DexParser.looks_like_dex(filename):
                        self.logger.debug("%s looks like a dex file", filename)
                        dex = self.__parse_dex(entry_filepath, filename, extended_processing)
                        dex_files.append(dex)
                    else:
                        self.logger.debug("%s looks like a generic file", filename)
                        entry = self.__parse_file(entry_filepath, filename, extended_processing)
                        if entry is not None:
                            other_files.append(entry)
                except (AndroidManifestParsingError, CertParsingError, FileParsingError) as error:
                    self.__remove_directory(tmpdir)
                    raise ApkParsingError from error
            self.__remove_directory(tmpdir)

        if manifest is None or cert is None or not dex_files:
            raise ApkParsingError

        return APK(
            filename=file.get_file_name(),
            size=file.get_size(),
            md5hash=file.get_md5(),
            sha1hash=file.get_sha1(),
            sha256hash=file.get_sha256(),
            sha512hash=file.get_sha512(),
            app_name=Aapt.get_app_name(filepath),
            cert=cert,
            manifest=manifest,
            dex_files=dex_files,
            other_files=other_files
        )
示例#10
0
    def test_extract_app_name_when_application_label_is_present(self):
        dump_badging = "application-label:'Example0'\n" \
            "application: label='Example1' icon='res/drawable-mdpi-v4/ic_launcher.png'\n" \
            "launchable-activity: name='com.example.app.HomeActivity'  label='Example2' icon=''"

        app_name = Aapt._extract_app_name(dump_badging)

        self.assertEqual("Example1", app_name)
示例#11
0
    def test_extract_sdk_target_when_present(self):
        dump_badging = "sdkVersion:'10'\n" \
            "maxSdkVersion:'20'\n" \
            "targetSdkVersion:'15'"

        sdk_target = Aapt._extract_sdk_target_version(dump_badging)

        self.assertEqual("15", sdk_target)
示例#12
0
    def test_extract_sdk_max_version_when_present(self):
        dump_badging = "sdkVersion:'10'\n" \
            "maxSdkVersion:'20'\n" \
            "targetSdkVersion:'15'"

        max_version = Aapt._extract_sdk_max_version(dump_badging)

        self.assertEqual("20", max_version)
示例#13
0
    def test_get_app_permissions(self):
        for filename in self.files:
            # When:
            permissions = Aapt.get_app_permissions(self.files[filename])

            # Then:
            self.assertEqual(self.files_properties[filename]["permissions"],
                             permissions)
示例#14
0
    def test_get_app_name(self):
        for filename in self.files:
            # When:
            files = Aapt.get_app_name(self.files[filename])

            # Then:
            self.assertEqual(self.files_properties[filename]["app_name"],
                             files)
示例#15
0
    def test_get_manifest_info_when_dumb_xmltree_fails(self, mock_popen):
        mock_popen.side_effect = RuntimeError()

        manifest = Aapt.get_manifest_info("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual({
            "activities": [],
            "services": [],
            "receivers": []
        }, manifest)
示例#16
0
    def test_get_manifest_info(self):
        for filename in self.files:
            # When:
            manifest = Aapt.get_manifest_info(self.files[filename])

            # Then:
            self.assertEqual(self.files_properties[filename]["activities"],
                             manifest["activities"])
            self.assertEqual(self.files_properties[filename]["services"],
                             manifest["services"])
            self.assertEqual(self.files_properties[filename]["receivers"],
                             manifest["receivers"])
示例#17
0
    def test_get_apk_info(self):
        for filename in self.files:
            # When:
            apk = Aapt.get_apk_info(self.files[filename])

            # Then:
            self.assertEqual(self.files_properties[filename]["package_name"],
                             apk["package_name"])
            self.assertEqual(self.files_properties[filename]["version"],
                             apk["version"])
            self.assertEqual(self.files_properties[filename]["sdk"],
                             apk["sdk"])
示例#18
0
    def __init__(self, filepath: str, string_processing: bool = True):
        super(APK, self).__init__(filepath)

        if not self.looks_like_an_apk(filepath):
            raise APKParsingError

        self._files = []  # type: List
        self._extract_and_set_entries(string_processing)

        if len(self._files) == 0 or self._cert is None:
            raise APKParsingError

        self._app_name = Aapt.get_app_name(filepath)
示例#19
0
    def test_get_apk_info_with_invalid_version_code(self, mock_popen):
        mock_popen.return_value = any_popen(b"package: name='com.example.app' versionCode='A' versionName='1.0'\n")

        apk = Aapt.get_apk_info("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual(
            {
                "code": "",  # NOTE: None is converted into an empty string
                "name": "1.0"
            },
            apk["version"]
        )
示例#20
0
    def test_extract_activities(self):
        dump_badging = """N: android=http://schemas.android.com/apk/res/android
              E: manifest (line=2)
                E: application (line=8)
                  E: activity (line=9)
                    A: android:name(0x01010003)="com.example.app.HomeActivity" (Raw: "...")
                  E: activity (line=15)
                    A: android:name(0x01010003)="com.example.app.OtherActivity" (Raw: "...")
        """

        activities = Aapt._extract_activities(dump_badging)

        self.assertEqual(["com.example.app.HomeActivity", "com.example.app.OtherActivity"], activities)
示例#21
0
    def test_extract_services(self):
        dump_badging = """N: android=http://schemas.android.com/apk/res/android
              E: manifest (line=2)
                E: application (line=8)
                  E: service (line=25)
                    A: android:name(0x01010003)="com.example.app.ExampleService" (Raw: "...")
                  E: service (line=28)
                    A: android:name(0x01010003)="com.example.app.OtherService" (Raw: "...")
        """

        services = Aapt._extract_services(dump_badging)

        self.assertEqual(["com.example.app.ExampleService", "com.example.app.OtherService"], services)
示例#22
0
    def test_get_apk_info_when_dumb_badging_fails(self, mock_popen):
        mock_popen.side_effect = RuntimeError()

        apk = Aapt.get_apk_info("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual(
            {
                "package_name": "",
                "version": {
                    "code": "",
                    "name": ""
                },
                "sdk": {}
            }, apk)
示例#23
0
    def __init__(self, filepath: str, string_processing: bool = True, logger: Logger = logger):
        super(APK, self).__init__(filepath)

        self.logger = logger

        if not self.looks_like_an_apk(filepath):
            raise APKParsingError

        self._files = []  # type: List
        self._dex_files = []  # type: List[Dex]
        self._extract_and_set_entries(string_processing)

        if len(self._files) == 0 or not hasattr(self, "_cert") or self._cert is None:
            raise APKParsingError

        self._app_name = Aapt.get_app_name(filepath)
示例#24
0
    def test_extract_broadcast_receivers(self):
        dump_badging = """N: android=http://schemas.android.com/apk/res/android
              E: manifest (line=2)
                E: application (line=8)
                  E: receiver (line=38)
                    A: android:name(0x01010003)="com.example.app.ExampleBrodcastReceiver" (Raw: "...")
                  E: receiver (line=44)
                    A: android:name(0x01010003)="com.example.app.OtherBrodcastReceiver" (Raw: "...")
        """

        receivers = Aapt._extract_broadcast_receivers(dump_badging)

        self.assertEqual(
            ["com.example.app.ExampleBrodcastReceiver", "com.example.app.OtherBrodcastReceiver"],
            receivers
        )
示例#25
0
    def test_get_app_permissions(self, mock_popen):
        dump_permissions = b"package: com.example.app\n" \
                           b"uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'\n" \
                           b"uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED'\n" \
                           b"uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'\n" \
                           b"uses-permission: name='android.permission.INTERNET'"
        mock_popen.return_value = any_popen(dump_permissions)

        permissions = Aapt.get_app_permissions("any-file-path")

        assert_popen_called_once(mock_popen)
        self.assertEqual([
            "android.permission.INTERNET",
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.RECEIVE_BOOT_COMPLETED",
            "android.permission.WRITE_EXTERNAL_STORAGE"
        ], permissions)
示例#26
0
    def _extract_version_code_when_present(self):
        version_code = Aapt._extract_version_code("package: name='com.example.app' versionCode='1' versionName='1.0' platformBuildVersionName='4'")

        self.assertEqual(1, version_code)
示例#27
0
    def __init__(self, filepath: str, binary: bool = False, apk_path: str = ""):
        super(AndroidManifest, self).__init__(filepath, "AndroidManifest.xml")

        # Load the AndroidManifest.xml structure:
        with open(AndroidManifest.__MANIFEST_CONFIG_FILE, 'r') as config:
            cfg = json.load(config)

        with open(filepath, 'rb') as fp:
            try:
                if binary:
                    self._raw = AXMLPrinter(fp.read()).get_buff()
                    xml = minidom.parseString(self._raw)
                else:
                    xml = minidom.parse(filepath)
            except ExpatError:
                if apk_path != "":
                    apk = Aapt.get_apk_info(apk_path)
                    self._package_name = apk["package_name"]
                    self._version = apk["version"]
                    self._sdk = apk["sdk"]
                    self._permissions = Aapt.get_app_permissions(apk_path)
                    man = Aapt.get_manifest_info(apk_path)
                    self._activities = man["activities"]
                    self._services = man["services"]
                    self._receivers = man["receivers"]
                else:
                    raise AndroidManifestParsingError
            except IOError:
                raise AndroidManifestParsingError
            else:
                manifest = xml.documentElement

                # Extract the package info:
                self._package_name = manifest.getAttribute(cfg['package']['name'])
                self._version = {"code": "", "name": ""}
                try:
                    self._version['code'] = int(manifest.getAttribute(cfg['package']['version']['code']))
                except ValueError:
                    pass
                self._version['name'] = manifest.getAttribute(cfg['package']['version']['name'])

                # Extract the SDK info:
                sdk = self._parse_element_to_list_of_dict(manifest, cfg['uses-sdk'], "uses-sdk")
                if len(sdk) > 0:
                    self._sdk = sdk[0]
                else:
                    self._sdk = {}

                # Extract the permissions info:
                self._permissions = AndroidManifest._parse_element_to_simple_list(manifest,
                                                                                  "uses-permission",
                                                                                  cfg['uses-permission'][0])

                # Extract the application info:
                application = manifest.getElementsByTagName(cfg['application']['tag'])
                application = application[0]
                self._activities = AndroidManifest._parse_element_to_list_of_dict(application,
                                                                                  cfg['application']['activity'],
                                                                                  "activity")
                self._services = AndroidManifest._parse_element_to_list_of_dict(application,
                                                                                cfg['application']['service'],
                                                                                "service")
                self._receivers = AndroidManifest._parse_element_to_list_of_dict(application,
                                                                                 cfg['application']['receiver'],
                                                                                 "receiver")
示例#28
0
 def test_get_apk_info(self):
     for filename in self.files:
         apk = Aapt.get_apk_info(self.files[filename])
         self.assertEqual(apk["package_name"], self.files_properties[filename]["package_name"])
         self.assertEqual(apk["version"], self.files_properties[filename]["version"])
         self.assertEqual(apk["sdk"], self.files_properties[filename]["sdk"])
示例#29
0
 def test_get_manifest_info(self):
     for filename in self.files:
         man = Aapt.get_manifest_info(self.files[filename])
         self.assertEqual(man["activities"], self.files_properties[filename]["activities"])
         self.assertEqual(man["services"], self.files_properties[filename]["services"])
         self.assertEqual(man["receivers"], self.files_properties[filename]["receivers"])
示例#30
0
 def test_get_app_permissions(self):
     for filename in self.files:
         self.assertEqual(Aapt.get_app_permissions(self.files[filename]),
                          self.files_properties[filename]["permissions"])
示例#31
0
    def test_extract_sdk_target_when_missing(self):
        sdk_target = Aapt._extract_sdk_target_version("")

        self.assertEqual("", sdk_target)
示例#32
0
    def _extract_version_code_when_missing(self):
        version_code = Aapt._extract_version_code("")

        self.assertIsNone(version_code)
示例#33
0
    def _extract_version_code_when_invalid(self):
        version_code = Aapt._extract_version_code("package: name='com.example.app' versionCode='A' versionName='1.0' platformBuildVersionName='4'")

        self.assertIsNone(version_code)
示例#34
0
 def test_get_app_name(self):
     for filename in self.files:
         self.assertTrue(Aapt.get_app_name(self.files[filename]) == self.files_properties[filename]["app_name"])
示例#35
0
    def test_extract_version_name(self):
        version_name = Aapt._extract_version_name("package: name='com.example.app' versionCode='1' versionName='1.0' platformBuildVersionName='4'")

        self.assertEqual("1.0", version_name)