Esempio n. 1
0
def extract_manifest(apk_file_path):
    """Extracts the AndroidManifest.xml file from an APK and write it in
    a new file.

    Parameters:
    -----------
    apk_file_path: str
        APK relative file path

    """

    apk = APK(apk_file_path)

    app_name = apk.get_app_name()
    axml = apk.get_android_manifest_axml()
    version = apk.get_androidversion_name()
    manifest = minidom.parseString(axml.get_buff()).toprettyxml()

    # Building filename
    app_name = app_name.replace(' ', '')
    version = version.replace(' ', '_')
    manifest_filename = "{}-{}.xml".format(app_name, version)

    manifest_path = os.path.join(config.DATA_FOLDER, manifest_filename)

    with open(manifest_path, 'w', encoding='utf8') as file:
        file.write(manifest)
    def testFrameworkResAPK(self):
        from androguard.core.bytecodes.apk import APK

        a = APK("examples/tests/lineageos_nexus5_framework-res.apk")

        self.assertEqual(a.get_app_name(), 'Android System')
        self.assertEqual(a.get_package(), 'android')
Esempio n. 3
0
    def get_apk_info(self):
        apk = APK(self.apk_file)
        app_icon_file = apk.get_app_icon()
        app_icon_data = apk.get_file(app_icon_file)

        size = (256, 256)

        buffered = BytesIO()
        im = Image.open(BytesIO(app_icon_data))
        im = im.resize(size, Image.ANTIALIAS)
        im.save(buffered, "PNG")

        app_icon_b64 = "data:image/png;base64," + base64.b64encode(
            buffered.getvalue()).decode('utf-8')

        self.package_name = apk.get_package()
        self.app_name = apk.get_app_name()

        self.report_saver.package_name = self.package_name
        self.report_saver.app_name = self.app_name
        self.report_saver.version = apk.get_androidversion_code()
        self.report_saver.app_icon = app_icon_b64

        permission_parser = PermissionParser(mode='groups')
        permission_values = permission_parser.transform(
            apk.get_permissions()).flatten().tolist()
        permission_labels = permission_parser.labels()
        self.report_saver.permissions_actual = {
            permission_labels[i]: bool(v)
            for i, v in enumerate(permission_values)
        }
Esempio n. 4
0
def get_apk_info(f, root=None):
    """
    获取apk信息
    :param root:
    :param f:
    :return:
    """
    if root:
        apk_path = os.path.join(root, f)
    else:
        apk_path = os.path.join(download_dir, f)

    apk_info = []
    try:
        apk = APK(apk_path)
        if apk.is_valid_APK():
            apk_info.append(f)
            apk_info.append(get_file_md5(apk_path))
            apk_info.append(apk.get_app_name())
            apk_info.append(apk.get_package())
            apk_info.append(get_cert_md5(apk))
            apk_info.append(apk.get_androidversion_name())
    except Exception as e:
        print(f + ' ->>', e)

    return apk_info
Esempio n. 5
0
class App(object):

    def __init__(self, app_path, root_path, app_name):
        print("Root path:"+root_path)
        assert app_path is not None
        self.logger = logging.getLogger(self.__class__.__name__)
        self.app_path = app_path

        from androguard.core.bytecodes.apk import APK
        self.apk = APK(self.app_path)
        self.package_name = self.apk.get_package()
        self.main_activity = self.apk.get_main_activity()
        self.permissions = self.apk.get_permissions()
        self.activities = self.apk.get_activities()
        if app_name is not None:
            self.app_name = app_name
        else:
            self.app_name = self.apk.get_app_name()
        print("Main activity:"+self.main_activity)
        print("Package name:"+self.package_name)
        self.output_path=root_path+self.package_name

    def get_package_name(self):
        """
        get package name of current app
        :return:
        """
        return self.package_name
Esempio n. 6
0
    def testAPKManifest(self):
        from androguard.core.bytecodes.apk import APK
        a = APK("examples/android/TestsAndroguard/bin/TestActivity.apk",
                testzip=True)

        self.assertEqual(a.get_app_name(), "TestsAndroguardApplication")
        self.assertEqual(a.get_app_icon(), "res/drawable-hdpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=120),
                         "res/drawable-ldpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=160),
                         "res/drawable-mdpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=240),
                         "res/drawable-hdpi/icon.png")
        self.assertIsNone(a.get_app_icon(max_dpi=1))
        self.assertEqual(a.get_main_activity(),
                         "tests.androguard.TestActivity")
        self.assertEqual(a.get_package(), "tests.androguard")
        self.assertEqual(a.get_androidversion_code(), '1')
        self.assertEqual(a.get_androidversion_name(), "1.0")
        self.assertEqual(a.get_min_sdk_version(), "9")
        self.assertEqual(a.get_target_sdk_version(), "16")
        self.assertIsNone(a.get_max_sdk_version())
        self.assertEqual(a.get_permissions(), [])
        self.assertEqual(a.get_declared_permissions(), [])
        self.assertTrue(a.is_valid_APK())
Esempio n. 7
0
    def testFrameworkResAPK(self):
        from androguard.core.bytecodes.apk import APK

        a = APK("examples/tests/lineageos_nexus5_framework-res.apk")

        self.assertEqual(a.get_app_name(), 'Android System')
        self.assertEqual(a.get_package(), 'android')
Esempio n. 8
0
def create_perm_vector(apk_file):
    try:
        a = APK(apk_file)
    except:
        return None

    apk_file_name = a.get_app_name()
    perms = a.get_permissions()

    perm_vector = [] * v
    for permission in PERMISSIONS:
        hit = 1 if permission in perms else 0
        perm_vector.append(hit)

    return apk_file_name, perms, list(perm_vector)
Esempio n. 9
0
    def testFallback(self):
        a = APK("examples/tests/com.teleca.jamendo_35.apk")

        # Should use the fallback
        self.assertEqual(a.get_app_name(), "Jamendo")
        res_parser = a.get_android_resources()

        res_id = int(a.get_attribute_value('application', 'label')[1:], 16)

        # Default Mode, no config
        self.assertEqual(len(res_parser.get_res_configs(res_id)), 2)
        # With default config, but fallback
        self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config())), 1)
        # With default config but no fallback
        self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config(), fallback=False)), 0)

        # Also test on resolver:
        self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id))), ["Jamendo", "Jamendo"])
        self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id, axml.ARSCResTableConfig.default_config()))), ["Jamendo"])
Esempio n. 10
0
def get_apk_information(_file):
    '''
    get apk information by androguard
    params:
    _file: apk file path

    return:
    1. apkname: apk name
    2. apkcode: apk version code, eg: 222, 333
    3. apkiconpath: get icon path
    '''
    apkinformation = APK(_file)

    apkname = apkinformation.get_app_name()
    apkcode = apkinformation.get_androidversion_code()
    apkiconpath = apkinformation.get_app_icon()
    # packagename = apkinformation.get_package()

    return apkname, apkcode, apkiconpath
Esempio n. 11
0
    def testFallback(self):
        a = APK("examples/tests/com.teleca.jamendo_35.apk")

        # Should use the fallback
        self.assertEqual(a.get_app_name(), "Jamendo")
        res_parser = a.get_android_resources()

        res_id = int(a.get_element('application', 'label')[1:], 16)

        # Default Mode, no config
        self.assertEqual(len(res_parser.get_res_configs(res_id)), 2)
        # With default config, but fallback
        self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config())), 1)
        # With default config but no fallback
        self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config(), fallback=False)), 0)

        # Also test on resolver:
        self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id))), ["Jamendo", "Jamendo"])
        self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id, axml.ARSCResTableConfig.default_config()))), ["Jamendo"])
Esempio n. 12
0
    def testAPKManifest(self):
        from androguard.core.bytecodes.apk import APK
        a = APK("examples/android/TestsAndroguard/bin/TestActivity.apk", testzip=True)

        self.assertEqual(a.get_app_name(), "TestsAndroguardApplication")
        self.assertEqual(a.get_app_icon(), "res/drawable-hdpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=120), "res/drawable-ldpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=160), "res/drawable-mdpi/icon.png")
        self.assertEqual(a.get_app_icon(max_dpi=240), "res/drawable-hdpi/icon.png")
        self.assertIsNone(a.get_app_icon(max_dpi=1))
        self.assertEqual(a.get_main_activity(), "tests.androguard.TestActivity")
        self.assertEqual(a.get_package(), "tests.androguard")
        self.assertEqual(a.get_androidversion_code(), '1')
        self.assertEqual(a.get_androidversion_name(), "1.0")
        self.assertEqual(a.get_min_sdk_version(), "9")
        self.assertEqual(a.get_target_sdk_version(), "16")
        self.assertIsNone(a.get_max_sdk_version())
        self.assertEqual(a.get_permissions(), [])
        self.assertEqual(a.get_declared_permissions(), [])
        self.assertTrue(a.is_valid_APK())
Esempio n. 13
0
    def get_apk_info(self):
        apk = APK(self.apk_file)
        app_icon_file = apk.get_app_icon()
        app_icon_data = apk.get_file(app_icon_file)

        size = (256, 256)

        buffered = BytesIO()
        im = Image.open(BytesIO(app_icon_data))
        im = im.resize(size, Image.ANTIALIAS)
        im.save(buffered, "PNG")

        app_icon_b64 = "data:image/png;base64," + base64.b64encode(
            buffered.getvalue()).decode('utf-8')

        self.package_name = apk.get_package()
        self.app_name = apk.get_app_name()

        self.report_saver.package_name = self.package_name
        self.report_saver.app_name = self.app_name
        self.report_saver.version = apk.get_androidversion_code()
        self.report_saver.app_icon = app_icon_b64
Esempio n. 14
0
def processCheck(apkPath,total,already):
    global rootdir
    unionFingerOutputPath = rootdir+'unionFingerOutput/'
    unionOutputPath = rootdir+'unionOutput/'
    fidoOutputPath = rootdir+'fidoOutput/'
    fidoPermissionOutputPath = rootdir+'fidoPermissionOutput/'
    failedPath=rootdir+'failed/'
    unionfs = r'cn.com.union.fido.ui.finger.FingerActivity'
    #unionfs = r'cn.com.union.fido.service.AuthenticatorService'
    unions = r'union.fido'
    fidos = r'fido'
    try:
        a = APK(apkPath)
    except:
        print('[{0}/{1}]Analysis Failed {2}'.format(already,total,apkPath))
        return
    activities = a.get_activities()
    name = a.get_app_name()
    find = False
    findstr = []
    for activity in activities:
        if activity==unionfs:
            find=True
            findstr.append('[ACTIVITY]'+activity)
    if find:
        print('[{0}/{1}]FIND unionFinger in {2}'.format(already,total,apkPath))
        copyTo(apkPath,unionFingerOutputPath,findstr,name)
        return 


    findstr.clear()
    find=False
    for activity in activities:
        if(re.search(unions,activity.lower())):
            find=True
            findstr.append('[ACTIVITY]'+activity)
    permissions = a.get_permissions()
    for permission in permissions:
        if re.search(unions,permission.lower()):
            find=True,
            findstr.append('[PERMISSION]'+permission)
    services = a.get_services()
    for service in services:
        if re.search(unions,service.lower()):
            find=True,
            findstr.append('[SERVICE]'+service)
    if find:
        print('[{0}/{1}]FIND union in {2}'.format(already,total,apkPath))
        copyTo(apkPath,unionOutputPath,findstr,name)
        return 

    findstr.clear()
    find=False
    for activity in activities:
        if(re.search(fidos,activity.lower())):
            find=True
            findstr.append('[ACTIVITY]'+activity)
    hasFidoPermission = False
    fidoPermission=[]
    for permission in permissions:
        if re.search(fidos,permission.lower()):
            find=True,
            hasFidoPermission=True
            findstr.append('[PERMISSION]'+permission)
            fidoPermission.append('[PERMISSION]'+permission)
    if hasFidoPermission:
        print('[{0}/{1}]FIND fido permission in {2}'.format(already,total,apkPath))
        copyTo(apkPath,fidoPermissionOutputPath,fidoPermission,name)

    for service in services:
        if re.search(fidos,service.lower()):
            find=True,
            findstr.append('[SERVICE]'+service)
    if find:
        print('[{0}/{1}]FIND fido in {2}'.format(already,total,apkPath))
        copyTo(apkPath,fidoOutputPath,findstr,name)
        return 
    print('[{0}/{1}]Nothing FOUND in {2}'.format(already,total,apkPath))
Esempio n. 15
0
class XAPK:
    def __init__(self, folder):
        self.folder = Path(folder)
        for x in self.folder.glob('*.apk'):
            self.apk_src = Path(x)
            break
        for x in self.folder.glob('*.obb'):
            self.obb_src = Path(x)
            break
        self.apk = APK(self.apk_src)
        self.manifest = self.make_manifest()
        self.icon = self.apk.get_file(self.apk.get_app_icon())

    def make_manifest(self):
        apk_size = self.apk_src.stat().st_size
        if self.obb_src:
            obb_size = self.obb_src.stat().st_size
        else:
            obb_size = 0
        total_size = apk_size + obb_size
        filename = self.apk.get_filename()

        manifest = {}
        manifest['xapk_version'] = 1
        manifest['package_name'] = self.apk.get_package()
        manifest['name'] = self.apk.get_app_name()
        # manifest['locales_name'] = {} # TODO
        manifest['version_code'] = self.apk.get_androidversion_code()
        manifest['version_name'] = self.apk.get_androidversion_name()
        manifest['min_sdk_version'] = self.apk.get_min_sdk_version()
        manifest['target_sdk_version'] = self.apk.get_target_sdk_version()
        manifest['permissions'] = self.apk.get_declared_permissions()
        manifest['total_size'] = total_size
        manifest['expansions'] = []

        if obb_size:
            main_obb = {}
            main_obb[
                'file'] = 'Android/obb/{package_name}/main.{version_code}.{package_name}.obb'.format(
                    **manifest)
            main_obb['install_location'] = 'EXTERNAL_STORAGE'
            main_obb[
                'install_path'] = 'Android/obb/{package_name}/main.{version_code}.{package_name}.obb'.format(
                    **manifest)
            manifest['expansions'].push(main_obb)

        return manifest

    def save(self):
        self.name = '{package_name}_v{version_name}.xapk'.format(
            **self.manifest)
        zip_path = self.folder.joinpath(self.name)

        zip_dir = tempfile.mkdtemp()
        try:
            print('copying apk to temp directory...')
            apk_name = '{package_name}.apk'.format(**self.manifest)
            apk_src = self.apk_src.resolve()
            apk_dest = PurePath(zip_dir).joinpath(apk_name)
            shutil.copy2(apk_src, apk_dest)
            print('apk: OK')

            if self.manifest.get('expansions'):
                print('copying obb to temp directory...')
                obb_name = self.manifest['expansions'][0]['install_path']
                obb_src = self.obb_src.resolve()
                obb_dest = PurePath(zip_dir).joinpath(obb_name)
                os.makedirs(Path(obb_dest).parent, exist_ok=True)
                shutil.copy2(obb_src, obb_dest)
                print('obb: OK')
            else:
                print('no obb found')

            print('creating icon in temp directory...')
            icon = self.icon
            icon_dest = PurePath(zip_dir).joinpath('icon.png')
            with open(icon_dest, 'wb') as iconfile:
                iconfile.write(icon)
            print('icon: OK')

            print('creating manifest in temp directory...')
            manifest_dest = PurePath(zip_dir).joinpath('manifest.json')
            with open(manifest_dest, 'w') as manifestfile:
                s = json.dumps(self.manifest, separators=(':', ','))
                manifestfile.write(s)
            print('manifest: OK')

            print('creating xapk archive...')
            with zipfile.ZipFile(zip_path,
                                 'w',
                                 compression=zipfile.ZIP_DEFLATED) as zfd:
                for root, dirs, files in os.walk(zip_dir):
                    for f in files:
                        filename = os.path.join(root, f)
                        zfd.write(filename, os.path.relpath(filename, zip_dir))
            print('xapk: OK')
        finally:
            print('cleaning up temp directory...')
            shutil.rmtree(zip_dir)
            print('cleanup: OK')
Esempio n. 16
0
class StaticAnalysis:
    def __init__(self, apk_path=None):
        self.apk = None
        self.apk_path = apk_path
        self.signatures = None
        self.compiled_tracker_signature = None
        self.classes = None
        self.app_details = None
        if apk_path is not None:
            self.load_apk()

    def _compile_signatures(self):
        """
        Compiles the regex associated to each signature, in order to speed up
        the trackers detection.
        :return: A compiled list of signatures.
        """
        self.compiled_tracker_signature = []
        try:
            self.compiled_tracker_signature = [
                re.compile(track.code_signature) for track in self.signatures
            ]
        except TypeError:
            print("self.signatures is not iterable")

    def load_trackers_signatures(self):
        """
        Load trackers signatures from the official Exodus database.
        :return: a dictionary containing signatures.
        """
        self.signatures = []
        exodus_url = "https://reports.exodus-privacy.eu.org/api/trackers"
        r = requests.get(exodus_url)
        data = r.json()
        for e in data['trackers']:
            self.signatures.append(
                namedtuple(
                    'tracker',
                    data['trackers'][e].keys())(*data['trackers'][e].values()))
        self._compile_signatures()
        logging.debug('{} trackers signatures loaded'.format(
            len(self.signatures)))

    def load_apk(self):
        """
        Load the APK file.
        """
        if self.apk is None:
            self.apk = APK(self.apk_path)

    def get_embedded_classes(self):
        """
        Get the list of Java classes embedded into all DEX files.
        :return: array of Java classes names as string
        """
        if self.classes is not None:
            return self.classes

        class_regex = re.compile(r'classes.*\.dex')
        with TemporaryDirectory() as tmp_dir:
            with zipfile.ZipFile(self.apk_path, "r") as apk_zip:
                class_infos = (info for info in apk_zip.infolist()
                               if class_regex.search(info.filename))
                for info in class_infos:
                    apk_zip.extract(info, tmp_dir)
            dexdump = which('dexdump')
            cmd = '{} {}/classes*.dex | perl -n -e\'/[A-Z]+((?:\w+\/)+\w+)/ && print "$1\n"\'|sort|uniq'.format(
                dexdump, tmp_dir)
            try:
                self.classes = subprocess.check_output(
                    cmd,
                    stderr=subprocess.STDOUT,
                    shell=True,
                    universal_newlines=True).splitlines()
                logging.debug('{} classes found in {}'.format(
                    len(self.classes), self.apk_path))
                return self.classes
            except subprocess.CalledProcessError:
                logging.error('Unable to decode {}'.format(self.apk_path))
                raise Exception('Unable to decode the APK')

    def detect_trackers_in_list(self, class_list):
        """
        Detect embedded trackers in the provided classes list.
        :return: list of embedded trackers
        """
        if self.signatures is None:
            self.load_trackers_signatures()

        def _detect_tracker(sig, tracker, class_list):
            for clazz in class_list:
                if sig.search(clazz):
                    return tracker
            return None

        results = []
        args = [(self.compiled_tracker_signature[index], tracker, class_list)
                for (index, tracker) in enumerate(self.signatures)
                if len(tracker.code_signature) > 3]

        for res in itertools.starmap(_detect_tracker, args):
            if res:
                results.append(res)

        trackers = [t for t in results if t is not None]
        logging.debug('{} trackers detected in {}'.format(
            len(trackers), self.apk_path))
        return trackers

    def detect_trackers(self, class_list_file=None):
        """
        Detect embedded trackers.
        :return: list of embedded trackers
        """
        if self.signatures is None:
            self.load_trackers_signatures()
        if class_list_file is None:
            return self.detect_trackers_in_list(self.get_embedded_classes())
        else:
            with open(class_list_file, 'r') as classes_file:
                classes = classes_file.readlines()
                return self.detect_trackers_in_list(classes)

    def get_version(self):
        """
        Get the application version name
        :return: version name
        """
        self.load_apk()
        return self.apk.get_androidversion_name()

    def get_version_code(self):
        """
        Get the application version code
        :return: version code
        """
        self.load_apk()
        return self.apk.get_androidversion_code()

    def get_permissions(self):
        """
        Get application permissions
        :return: application permissions list
        """
        self.load_apk()
        return self.apk.get_permissions()

    def get_app_name(self):
        """
        Get application name
        :return: application name
        """
        self.load_apk()
        return self.apk.get_app_name()

    def get_package(self):
        """
        Get application package
        :return: application package
        """
        self.load_apk()
        return self.apk.get_package()

    def get_libraries(self):
        """
        Get application libraries
        :return: application libraries list
        """
        self.load_apk()
        return self.apk.get_libraries()

    def get_icon_path(self):
        """
        Get the icon path in the ZIP archive
        :return: icon path in the ZIP archive
        """
        self.load_apk()
        return self.apk.get_app_icon()

    def get_application_details(self):
        """
        Get the application details like creator, number of downloads, etc.
        :param handle: application handle
        :return: application details dictionary
        """
        self.load_apk()

        if self.app_details is not None:
            return self.app_details

        details = get_details_from_gplaycli(self.get_package())
        if details is not None:
            self.app_details = details

        return details

    def _get_icon_from_details(self, path):
        """
        Get icon from applications details dictionary
        :param path: path where to write the icon file
        :return: icon path
        :raises Exception: if unable to find icon
        """
        details = self.get_application_details()
        if details is not None:
            for i in details.get('images'):
                if i.get('imageType') == 4:
                    f = requests.get(i.get('url'))
                    with open(path, mode='wb') as fp:
                        fp.write(f.content)
                    if os.path.isfile(path) and os.path.getsize(path) > 0:
                        return path

        raise Exception('Unable to download the icon from details')

    @staticmethod
    def _render_drawable_to_png(self, bxml, path):
        ap = axml.AXMLPrinter(bxml)
        print(ap.get_buff())

    def save_icon(self, path):
        """
        Extract the icon from the ZIP archive and save it at the given path
        :param path: destination path of the icon
        :return: destination path of the icon, None in case of error
        """
        try:
            icon = self.get_icon_path()
            if icon is None:
                raise Exception('Unable to get icon path')
            with zipfile.ZipFile(self.apk_path) as z:
                with open(path, 'wb') as f:
                    f.write(z.read(icon))
                with Image.open(path) as _:
                    logging.info('Get icon from APK: success')
                    return path
        except Exception:
            logging.warning('Unable to get the icon from the APK')
            return None

            # TODO: Set this back once details download is working again
            # logging.warning('Downloading icon from details')
            # try:
            #     saved_path = self._get_icon_from_details(path)
            #     logging.debug('Icon downloaded from application details')
            #     return saved_path
            # except Exception as e:
            #     logging.warning(e)

    def get_icon_phash(self):
        """
        Get the perceptual hash of the application icon
        :return: the perceptual hash, empty string in case of error
        """
        with NamedTemporaryFile() as ic:
            path = self.save_icon(ic.name)
            if path is None:
                logging.error('Unable to save the icon')
                return ''
            return self.get_phash(ic.name)

    @staticmethod
    def get_phash(image_name):
        """
        Get the perceptual hash of the given image
        :param image_name: name of the image file
        :return: the perceptual hash, empty string in case of error
        """
        dhash.force_pil()  # Force PIL

        try:
            image = Image.open(image_name).convert("RGBA")
            row, col = dhash.dhash_row_col(image, size=PHASH_SIZE)
            return row << (PHASH_SIZE * PHASH_SIZE) | col
        except IOError as e:
            logging.error(e)
            return ''

    @staticmethod
    def get_icon_similarity(phash_origin, phash_candidate):
        """
        Get icons similarity score [0,1.0]
        :param phash_origin: original icon
        :param phash_candidate: icon to be compared
        :return: similarity score [0,1.0]
        """
        diff = dhash.get_num_bits_different(phash_origin, phash_candidate)
        return 1 - 1. * diff / (PHASH_SIZE * PHASH_SIZE * 2)

    def get_application_universal_id(self):
        parts = [self.get_package()]
        for c in self.get_certificates():
            parts.append(c.fingerprint.upper())
        return sha1(' '.join(parts).encode('utf-8')).hexdigest().upper()

    def get_certificates(self):
        certificates = []

        def _my_name_init(self, oid, value, _type=_SENTINEL):
            if not isinstance(oid, ObjectIdentifier):
                raise TypeError(
                    "oid argument must be an ObjectIdentifier instance.")
            if not isinstance(value, six.text_type):
                raise TypeError("value argument must be a text type.")
            if len(value) == 0:
                raise ValueError("Value cannot be an empty string")
            if _type == _SENTINEL:
                _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)
            if not isinstance(_type, _ASN1Type):
                raise TypeError("_type must be from the _ASN1Type enum")
            self._oid = oid
            self._value = value
            self._type = _type

        NameAttribute.__init__ = _my_name_init

        signs = self.apk.get_signature_names()
        for s in signs:
            c = self.apk.get_certificate(s)
            cert = Certificate(c)
            certificates.append(cert)

        return certificates

    def get_apk_size(self):
        """
        Get the APK file size in bytes
        :return: APK file size
        """
        return os.path.getsize(self.apk_path)

    def get_sha256(self):
        """
        Get the sha256sum of the APK file
        :return: hex sha256sum
        """
        BLOCKSIZE = 65536
        hasher = sha256()
        with open(self.apk_path, 'rb') as apk:
            buf = apk.read(BLOCKSIZE)
            while len(buf) > 0:
                hasher.update(buf)
                buf = apk.read(BLOCKSIZE)
        return hasher.hexdigest()

    def save_embedded_classes_in_file(self, file_path):
        """
        Save list of embedded classes in file.
        :param file_path: file to write
        """
        with open(file_path, 'w+') as f:
            f.write('\n'.join(self.get_embedded_classes()))

    def print_apk_infos(self):
        """
        Print APK information
        """
        permissions = self.get_permissions()
        libraries = self.get_libraries()
        certificates = self.get_certificates()
        print("=== Information")
        print('- APK path: {}'.format(self.apk_path))
        print('- APK sum: {}'.format(self.get_sha256()))
        print('- App version: {}'.format(self.get_version()))
        print('- App version code: {}'.format(self.get_version_code()))
        print('- App UID: {}'.format(self.get_application_universal_id()))
        print('- App name: {}'.format(self.get_app_name()))
        print('- App package: {}'.format(self.get_package()))
        print('- App permissions: {}'.format(len(permissions)))
        for perm in permissions:
            print('    - {}'.format(perm))
        print('- App libraries:')
        for lib in libraries:
            print('    - {}'.format(lib))
        print('- Certificates: {}'.format(len(certificates)))
        for cert in certificates:
            print('    - {}'.format(cert))

    def print_embedded_trackers(self):
        """
        Print detected trackers
        """
        trackers = self.detect_trackers()
        print('=== Found trackers: {}'.format(len(trackers)))
        for t in trackers:
            print(' - {}'.format(t.name))
def meta_fetch(apk):
    app = APK(apk)
    return app.get_app_name(), app.get_target_sdk_version(), str(
        round(os.stat(apk).st_size / (1024 * 1024), 2)) + ' MB'
Esempio n. 18
0
def analyze(path):
    try:
        start = process_time()
        hashfunctions = dict(md5=hashlib.md5,
                             sha1=hashlib.sha1,
                             sha256=hashlib.sha256,
                             sha512=hashlib.sha512)
        a = APK(path)

        certs = set(
            a.get_certificates_der_v3() + a.get_certificates_der_v2() +
            [a.get_certificate_der(x) for x in a.get_signature_names()])

        for cert in certs:
            x509_cert = x509.Certificate.load(cert)

            issuer = {
                'commonName': None,
                'organizationName': None,
                'organizationalUnitName': None,
                'countryName': None,
                'stateOrProvinceName': None,
                'localityName': None
            }
            subject = {
                'commonName': None,
                'organizationName': None,
                'organizationalUnitName': None,
                'countryName': None,
                'stateOrProvinceName': None,
                'localityName': None
            }

            strIssuer = get_certificate_name_string(x509_cert.issuer,
                                                    short=False)
            strSubject = get_certificate_name_string(x509_cert.subject,
                                                     short=False)

            arrIssuer = strIssuer.split(',')
            for i in arrIssuer:
                if i.lstrip().split('=')[0] == 'commonName':
                    issuer['commonName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'organizationName':
                    issuer['organizationName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'organizationalUnitName':
                    issuer['organizationalUnitName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'countryName':
                    issuer['countryName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'stateOrProvinceName':
                    issuer['stateOrProvinceName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'localityName':
                    issuer['localityName'] = i.lstrip().split('=')[1]

            arrSubject = strSubject.split(',')
            for i in arrSubject:
                if i.lstrip().split('=')[0] == 'commonName':
                    subject['commonName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'organizationName':
                    subject['organizationName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'organizationalUnitName':
                    subject['organizationalUnitName'] = i.lstrip().split(
                        '=')[1]
                elif i.lstrip().split('=')[0] == 'countryName':
                    subject['countryName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'stateOrProvinceName':
                    subject['stateOrProvinceName'] = i.lstrip().split('=')[1]
                elif i.lstrip().split('=')[0] == 'localityName':
                    subject['localityName'] = i.lstrip().split('=')[1]

            for k, v in hashfunctions.items():
                if k == 'md5':
                    md5 = v(cert).hexdigest()
                elif k == 'sha1':
                    sha1 = v(cert).hexdigest()
                elif k == 'sha256':
                    sha256 = v(cert).hexdigest()
                elif k == 'sha512':
                    sha512 = v(cert).hexdigest()

        md5 = md5

        appName = a.get_app_name()
        fileSize = os.stat(a.get_filename()).st_size
        sha1 = sha1
        sha256 = sha256
        sha512 = sha512
        timestamp = time.time()
        dateTime = datetime.fromtimestamp(timestamp)
        timeOfSubmit = dateTime.strftime("%Y-%m-%d %H:%M:%S")
        package = a.get_package()
        androidversionCode = a.get_androidversion_code()
        androidversionName = a.get_androidversion_name()
        minSDKVersion = a.get_min_sdk_version()
        maxSDKVersion = a.get_max_sdk_version()
        targetSDKVersion = a.get_target_sdk_version()
        mainActivity = a.get_main_activity()

        attributes = {
            'validFrom':
            x509_cert['tbs_certificate']['validity']
            ['not_before'].native.strftime("%Y-%m-%d %H:%M:%S"),
            'validTo':
            x509_cert['tbs_certificate']['validity']
            ['not_after'].native.strftime("%Y-%m-%d %H:%M:%S"),
            'serialNumber':
            hex(x509_cert.serial_number),
            'hashAlgorithm':
            x509_cert.hash_algo,
            'signatureAlgorithm':
            x509_cert.signature_algo
        }

        certificateAttributes = json.dumps(attributes)
        certificateIssuer = json.dumps(issuer)
        certificateSubject = json.dumps(subject)

        declaredPermissions = json.dumps(a.get_declared_permissions())

        requestedPermissions = json.dumps(a.get_permissions())

        activities = json.dumps(a.get_activities())

        services = json.dumps(a.get_services())

        receivers = json.dumps(a.get_receivers())

        providers = json.dumps(a.get_providers())

        stop = process_time()
        analysisTime = stop - start

        connect = mysql.connect()
        cursor = connect.cursor()

        sql = "INSERT INTO tbl_apkinfo (md5, appName, fileSize, analysisTime, sha1, sha256, sha512, firstSubmission, lastSubmission, package, androidversionCode, androidversionName, minSDKVersion, maxSDKVersion, targetSDKVersion, mainActivity, certificateAttributes, certificateIssuer, certificateSubject,	declaredPermissions, requestedPermissions, activities, services, providers, receivers) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
        param = (md5, appName, fileSize, analysisTime, sha1, sha256, sha512,
                 timeOfSubmit, timeOfSubmit, package, androidversionCode,
                 androidversionName, minSDKVersion, maxSDKVersion,
                 targetSDKVersion, mainActivity, certificateAttributes,
                 certificateIssuer, certificateSubject, declaredPermissions,
                 requestedPermissions, activities, services, providers,
                 receivers)
        cursor.execute(sql, param)

        connect.commit()
        connect.close()

        androaxml_main(path,
                       os.path.join(app.config['OUTPUT_PATH'], md5 + '.xml'))
        return True
    except:
        return False
Esempio n. 19
0
class MyAPK:
    def __init__(self,
                 name_file,
                 conf,
                 file_log,
                 tag,
                 string_to_find,
                 logger,
                 api_monitor_dict=None,
                 network_dict=None,
                 dynamic_time=0,
                 use_smaliparser=True):

        self.name_apk = name_file
        self.name_only_apk = self.name_apk.split("/")[-1].rsplit(".", 1)[0]
        self.conf = conf
        self.apk = APK(name_file)
        self.app_name = self.apk.get_app_name()
        self.package_name = self.apk.get_package()
        self.target_sdk = self.apk.get_target_sdk_version()
        self.dalviks_format = None
        self.analysis_object = None
        self.dict_file_with_string = dict(
        )  # file che contengono la stringa ricercata
        self.string_to_find = string_to_find  # stringa da cercare
        self.is_contain_permission = False  # se contiene i permessi del file conf
        self.url_loaded = list()  # list url that has been loaded
        # se contiene i file ibridi --> probabilmente app ibrida
        self.is_contain_file_hybrid = False
        # pagine_html con iframe se contengono csp [True o False]
        self.find_csp = dict()
        # se contiene i metodi all'interno del file conf.json
        self.is_contains_all_methods = False
        self.zip = zipfile.ZipFile(self.name_apk)  # get zip object from apk
        self.list_file = self.zip.namelist()  # tutti i file all'interno
        self.html_file = FileAnalysis.find_html_file(self.list_file)
        self.file_log = file_log  # name to file log
        self.javascript_enabled = False
        self.internet_enabled = False
        self.file_vulnerable_frame_confusion = list()
        self.file_with_string_iframe = list()
        self.isHybrid = None
        # dict indexes with name method and get encoded methods where function was called
        self.method = dict()
        self.all_url = list()  # all url in the apk
        self.file_download_to_analyze = dict()
        self.search_tag = tag
        self.md5_file_to_url = dict(
        )  # dict with indexes with name and get url remote
        self.file_config_hybrid = None
        self.list_origin_access = list()
        self.logger = logger
        self.api_monitor_dict = api_monitor_dict
        self.network_dict = network_dict
        self.file_hybrid = list()
        self.javascript_interface = False
        self.javascript_file = FileAnalysis.find_js_file(self.list_file)
        self.src_iframe = dict()
        self.page_xss_vuln = dict()
        self.is_vulnerable_frame_confusion = False
        self.http_connection = list()
        self.http_connection_static = list()
        self.all_http_connection = list()
        self.url_dynamic = list()
        self.use_smaliparser = use_smaliparser
        self.use_analyze = not use_smaliparser
        self.method_2_value = dict()
        self.dynamic_javascript_enabled = False
        self.analysis_dynamic_done = api_monitor_dict is not None or network_dict is not None
        self.dynamic_javascript_interface = False
        self.dynamic_time = dynamic_time  # time execution analysis dynamic
        self.all_url_dynamic = list()
        self.load_url_dynamic = list()
        self.app_use_sandbox = False
        self.file_with_sandbox = dict()  # app use sandbox

    def read(self, filename, binary=True):
        with open(filename, 'rb' if binary else 'r') as f:
            return f.read()

    def check_permission(self, list_permission_to_find):
        """
            check permission hybrid app
        """
        use_permission_checker = True
        if not use_permission_checker:
            permission_find = list()
            for permission_to_check in list_permission_to_find:
                if permission_to_check in self.apk.get_permissions():
                    permission_find.append(True)  # contenere tutti i permessi
                    if permission_to_check == "android.permission.INTERNET":
                        self.internet_enabled = True

            # print(permission_to_check)
            self.logger.logger.info("[Permission declared Start]")
            for p in self.apk.get_permissions():
                self.logger.logger.info(p)
            self.logger.logger.info("[Permission End]\n")

            self.is_contain_permission = len(permission_find) == len(
                list_permission_to_find)
        else:

            if "PermissionChecker.jar" in os.listdir("."):
                dir_permission_checker = "PermissionChecker.jar"
            else:
                dir_permission_checker = os.path.join("FCDroid",
                                                      "PermissionChecker.jar")
            try:
                cmd_permission_checker = [
                    "java", "-jar", dir_permission_checker, self.name_apk
                ]
                process = subprocess.Popen(cmd_permission_checker,
                                           stdout=subprocess.PIPE)
                result = process.communicate()[0]
                # error here
                result = json.loads(result)
                # requiredAndUsed = result['requiredAndUsed']

                notRequiredButUsed = result['notRequiredButUsed']
                declared = result['declared']
                # requiredButNotUsed = result['requiredButNotUsed']
                list_permission = list(set().union(notRequiredButUsed,
                                                   declared))
                permission_find = list()
                for permission_to_check in list_permission_to_find:
                    if permission_to_check in list_permission:
                        permission_find.append(
                            True)  # contenere tutti i permessi
                        if permission_to_check == "android.permission.INTERNET":
                            self.internet_enabled = True

                self.logger.logger.info(
                    "[Permission declared and not required but used Start]")
                for p in list_permission:
                    self.logger.logger.info(p)
                self.logger.logger.info("[Permission End]\n")

                self.is_contain_permission = len(permission_find) == len(
                    list_permission_to_find)

            except Exception as e:
                permission_find = list()
                for permission_to_check in list_permission_to_find:
                    if permission_to_check in self.apk.get_permissions():
                        permission_find.append(
                            True)  # contenere tutti i permessi
                        if permission_to_check == "android.permission.INTERNET":
                            self.internet_enabled = True

                # print(permission_to_check)
                self.logger.logger.info("[Permission declared Start]")
                for p in self.apk.get_permissions():
                    self.logger.logger.info(p)
                self.logger.logger.info("[Permission End]\n")

                self.is_contain_permission = len(permission_find) == len(
                    list_permission_to_find)

    def is_hybird(self):
        """
            function to check se apk is hybrid,
            1) if contain file from conf.json (cordova/plugin/phonegap/config)
            2) if present permission internet (inutile)
        """
        if self.isHybrid is None:
            list_file_to_find = self.conf["file_to_check"]
            list_permission_to_find = self.conf["permissions_to_check"]

            self.is_contain_file_hybrid, self.file_hybrid = FileAnalysis.check_file_hybrid(
                self.list_file, list_file_to_find)

            if self.is_contain_file_hybrid:
                self.logger.logger.info("Hybrid file found are: " +
                                        str(self.file_hybrid))

            self.check_permission(list_permission_to_find)

            self.isHybrid = self.is_contain_permission and self.is_contain_file_hybrid

            # using apktool
            FNULL = open(os.devnull, 'w')
            print(bcolors.WARNING + "[*] Starting apktool " + bcolors.ENDC)
            self.logger.logger.info("Starting apktool")
            cmd = [
                "apktool", "d", "-o", "temp_dir_" + self.name_only_apk,
                self.name_apk, "-f"
            ]
            subprocess.call(cmd, stdout=FNULL, stderr=subprocess.STDOUT)

            try:
                if self.isHybrid:
                    # now can search file in temp_dir
                    if os.path.exists("temp_dir_{0}/res/xml/config.xml".format(
                            self.name_only_apk)):
                        file_xml = open(
                            "temp_dir_{0}/res/xml/config.xml".format(
                                self.name_only_apk))
                        file_data_xml = str(file_xml.read())
                        self.file_config_hybrid = file_data_xml
                        # parsing file config
                        self.check_whitelist()

            except OSError as e:
                print(
                    bcolors.FAIL +
                    "File config.xml not found, it is necessary to decompile the application first"
                    + bcolors.ENDC)
                # remove dir
                self.logger.logger.error(
                    "[ERROR file config.xmls] {0} \n".format(e))

        return self.isHybrid

    def check_whitelist(self):
        """
            function that obtain access origin from file 
            config.xml
        """

        # get xml_object ElementTree
        if self.file_config_hybrid is not None and self.isHybrid:
            self.list_origin_access = list()
            root = ET.fromstring(self.file_config_hybrid)

            xmlns = "{http://www.w3.org/ns/widgets}"  # default namespace

            # TODO aggiungere altri elementi della whitelist
            # 1) <allow-navigation href="http://*/*" />
            # Controls which URLs the WebView itself can be navigated to. Applies to top-level navigations only.
            # 2) <allow-intent href="http://*/*" />
            # Controls which URLs the app is allowed to ask the system to open. By default, no external URLs are allowed
            # 3) <access origin="http://google.com" />
            # Controls which network requests (images, XHRs, etc) are allowed to be made (via cordova native hooks).

            for child in root.findall(xmlns + "access"):
                # print( child.tag, child.attrib.get("origin"))
                self.list_origin_access.append(child.attrib.get("origin"))

            self.logger.logger.info("[INIT ACCESS ORIGIN LIST]")
            for value in self.list_origin_access:
                self.logger.logger.info("origin: %s", value)
            self.logger.logger.info("[END ACCESS ORIGIN LIST]\n")

    def analyze_xss_dom(self, file_name, file_content):
        """ 
            search static dom xss based on regex
        """
        # TODO se file_name end with js use TaintJS altrimenti usare questo
        # per usare taint js salvare il contenuto in una dir temporanea e usarlo
        # da li dentro
        try:
            print("file xss dom analyze {0}".format(file_name))

            if file_name.endswith(".js"):
                file_open_temp = "FCDroid/TaintJS/temp_file_to_analyze.js"
                file_to_write = open(file_open_temp, "w")
                file_to_write.write(file_content)
                file_to_write.close()
                cmd_node = [
                    "node", "--max-old-space-size=4096",
                    "FCDroid/TaintJS/app.js", file_open_temp
                ]
                process = subprocess.Popen(cmd_node,
                                           stdout=subprocess.PIPE,
                                           stderr=subprocess.PIPE)
                out, err = process.communicate()
                out = out.decode('utf-8').strip()
                err = err.decode('utf-8')
                os.remove(file_open_temp)
                # no error
                if err != '':  # no error
                    if out == 'true':  # is vuln
                        self.page_xss_vuln[file_name] = True
                else:

                    page_analyze = XSScanner(file_name, file_content)
                    page_analyze.analyze_page()
                    if len(page_analyze.sink) > 0 or len(
                            page_analyze.source) > 0:
                        self.page_xss_vuln[file_name] = page_analyze
            else:
                soup = BeautifulSoup(file_content, 'html.parser')
                scripts = soup.find_all("script")
                for script in scripts:
                    value = script.get_text().strip()
                    file_open_temp = "FCDroid/TaintJS/temp_file_to_analyze.js"
                    file_to_write = open(file_open_temp, "w")
                    file_to_write.write(value)
                    file_to_write.close()
                    cmd_node = [
                        "node", "--max-old-space-size=4096",
                        "FCDroid/TaintJS/app.js", file_open_temp
                    ]
                    process = subprocess.Popen(cmd_node,
                                               stdout=subprocess.PIPE,
                                               stderr=subprocess.PIPE)
                    out, err = process.communicate()
                    out = out.decode('utf-8').strip()
                    err = err.decode('utf-8')
                    os.remove(file_open_temp)
                    # no error
                    if err != '':  # no error
                        if out == 'true':  # is vuln
                            self.page_xss_vuln[file_name] = True
                    else:

                        page_analyze = XSScanner(file_name, file_content)
                        page_analyze.analyze_page()
                        if len(page_analyze.sink) > 0 or len(
                                page_analyze.source) > 0:
                            self.page_xss_vuln[file_name] = page_analyze
        except Exception:

            page_analyze = XSScanner(file_name, file_content)
            page_analyze.analyze_page()
            if len(page_analyze.sink) > 0 or len(page_analyze.source) > 0:
                self.page_xss_vuln[file_name] = page_analyze

    def find_string(self, file_to_search, remote=False, debug=False):
        """
            find string inside file of apk(html,xml,ecc..) (not yet decompiled)
        """
        debug = True
        # print(self.md5_file_to_url.keys())
        if remote:
            self.logger.logger.info("[START REMOTE FILE ANALYZE]")
        else:
            self.logger.logger.info("[START FILE ANALYZE]")
        for file_to_inspect, insideAPK in file_to_search.items():
            if not remote and debug:
                self.logger.logger.info("File: " + file_to_inspect)
            else:
                if debug:
                    try:
                        m = hashlib.md5()
                        m.update(file_to_inspect.encode('utf-8'))
                        self.logger.logger.info(
                            "Remote File in: {0}".format(file_to_inspect))

                        if m.hexdigest() in self.md5_file_to_url.keys():
                            self.logger.logger.info("URL: {0}".format(
                                self.md5_file_to_url[str(m.hexdigest())]))

                    except KeyError as e:
                        self.logger.logger.warning(
                            "Key error as {0} ".format(e))

            file_to_inspect_split = file_to_inspect.split(
                "?", 1)[0]  # remove parameter

            if remote and not (file_to_inspect_split.endswith(".js")
                               or file_to_inspect_split.endswith(".html")):
                # add extension html on file
                # of default wget add this extension
                file_to_inspect = file_to_inspect + ".html"

            if insideAPK:
                data = self.zip.open(file_to_inspect)
            else:
                data = open(file_to_inspect, "r")

            #######################################################################################################
            # start xss analysis on this file
            try:

                content_file = data.read()
                thread = threading.Thread(name="xss_" + file_to_inspect,
                                          target=self.analyze_xss_dom,
                                          args=(
                                              file_to_inspect,
                                              str(content_file),
                                          ))
                thread.start()
                #######################################################################################################

                file_read = str(content_file)
                soup = BeautifulSoup(file_read, 'lxml')
                try:

                    find_iframe, list_row_string, list_src_iframe, find_string_not_tag, file_with_sandbox = FileAnalysis.find_string(
                        self.string_to_find, self.search_tag, file_to_inspect,
                        file_read, soup, self.logger)

                    self.file_with_sandbox = {
                        **self.file_with_sandbox,
                        **file_with_sandbox
                    }  # merge dict

                    #######################################################################################################
                    # TODO insert in method --> String Analysis
                    if find_iframe and self.string_to_find == "iframe":
                        if not find_string_not_tag:
                            self.dict_file_with_string[
                                file_to_inspect] = list_row_string
                            self.src_iframe[file_to_inspect] = list_src_iframe

                        # TODO search id iframe in file js in script src
                        if not self.search_tag or file_to_inspect_split.endswith(
                                ".js") or find_string_not_tag:
                            self.file_with_string_iframe.append(
                                file_to_inspect)  # append file with iframe
                            print(bcolors.FAIL + "Found " +
                                  self.string_to_find + " in line " +
                                  str(list_row_string) + bcolors.ENDC)
                            self.logger.logger.info(
                                "Found  %s file %s in line %s",
                                self.string_to_find, file_to_inspect,
                                str(list_row_string))

                        else:
                            print(bcolors.FAIL + "Found tag " +
                                  self.string_to_find + ",  " +
                                  str(len(list_row_string)) + " times " +
                                  bcolors.ENDC)
                            self.logger.logger.info(
                                "Found in file %s tag %s , %s times",
                                file_to_inspect, self.string_to_find,
                                str(len(list_row_string)))

                            if len(self.src_iframe[file_to_inspect]) > 0:
                                self.logger.logger.info(
                                    "Founded this src {0} in iframe tag inside file {1}"
                                    .format(
                                        str(self.src_iframe[file_to_inspect]),
                                        file_to_inspect))

                            else:
                                self.logger.logger.info(
                                    "No src founded in iframe tag inside file {0}"
                                    .format(file_to_inspect))

                        #######################################################################################################

                        # TODO aggiungere il content e fare conclusioni su di esso e per i file JavaScript
                        find_csp = soup.find(
                            "meta", {"http-equiv": "Content-Security-Policy"})
                        if find_csp is not None:
                            print(bcolors.OKGREEN +
                                  "Find CSP with content: [" +
                                  find_csp["content"] + "]" + bcolors.ENDC)
                            self.logger.logger.info(
                                "Find CSP with content: [" +
                                find_csp["content"] + "]")
                            self.find_csp[file_to_inspect] = True

                        # only file html
                        elif not file_to_inspect_split.endswith(".js"):
                            print(bcolors.FAIL + "No CSP found!" +
                                  bcolors.ENDC)
                            self.logger.logger.info("No CSP found!")
                            self.find_csp[file_to_inspect] = False
                        elif file_to_inspect_split.endswith(".js"):
                            print(bcolors.FAIL +
                                  "It is a JS file, no CSP found!" +
                                  bcolors.ENDC)
                            self.logger.logger.info(
                                "It is a JS file, no CSP found!, investigate manually\n"
                            )
                            self.find_csp[file_to_inspect] = False

                    else:
                        print(bcolors.OKGREEN + "No " + self.string_to_find +
                              " in " + file_to_inspect + bcolors.ENDC)
                        self.logger.logger.info("No " + self.string_to_find +
                                                " in " + file_to_inspect +
                                                "\n")

                except zipfile.BadZipfile as e:
                    self.logger.error("Error bad zip file {0}".format(e))
                    continue
                except ValueError as e:
                    self.logger.error("Error value error {0}".format(e))
                    continue
            except UnicodeDecodeError as e:
                self.logger.logger.error("Error unicode error {0}".format(e))
                continue
        self.logger.logger.info("[END ANALYZE FILE]")
        return None

    def find_method_used(self):
        """
            funzione per ricercare i metodi che sono usati 
            all'interno dell'apk, tanto lenta
        """
        used_jadx = False
        if used_jadx:

            # Create DalvikVMFormat Object
            self.dalvik_format = DalvikVMFormat(self.apk)
            # Create Analysis Object
            self.analysis_object = Analysis(self.dalvik_format)
            # Load the decompiler
            # Make sure that the jadx executable is found in $PATH
            # or use the argument jadx="/path/to/jadx" to point to the executable
            decompiler = DecompilerJADX(self.dalvik_format,
                                        self.analysis_object)

            # propagate decompiler and analysis back to DalvikVMFormat
            self.dalvik_format.set_decompiler(decompiler)
            self.dalvik_format.set_vmanalysis(self.analysis_object)

            # Now you can do stuff like:
            list_method_analysis = self.analysis_object.get_methods()
            for method_analys in list_method_analysis:
                method_name = method_analys.get_method().get_name()
                # print(method_encoded.get_method().get_source())
                self.method[method_name] = list(method_analys.get_xref_from())

        elif self.use_analyze:
            # return apk, list dex , object analysis
            apk, self.dalvik_format, self.analysis_object = AnalyzeAPK(
                self.name_apk)

            for method_analys in self.analysis_object.get_methods():
                method_name = method_analys.get_method().get_name()
                # from method_name get list dove esso viene chiamato
                self.method[method_name] = list(method_analys.get_xref_from())

        elif self.use_smaliparser:
            # use smali parser, apktool and grep invece di Androguard
            dir_apk_tool = "temp_dir_" + self.name_only_apk + "/"
            list_method_to_analyze = self.conf["method_smali_parser"]
            self.method_2_value, self.all_url = smaliparser.start(
                dir_apk_tool, list_method_to_analyze)

        else:  # TODO to make faster analysis but not work well
            self.dalvik_format = DalvikVMFormat(self.apk)
            for encoded_method in self.dalvik_format.get_methods():
                method_analysis = MethodClassAnalysis(encoded_method)

                method_name = method_analysis.get_method().get_name()
                # print(method_name)
                # from method_name get list dove esso viene chiamato
                self.method[method_name] = list(
                    method_analysis.get_xref_from())
                # print(self.method[method_name])

    def check_method_conf(self):
        """
            function to check se methods inside conf.json method_to_check is used inside apk
        """

        method_to_find = self.conf["method_to_check"]
        method_present = dict()

        try:

            if self.use_smaliparser:
                if "setJavaScriptEnabled" in self.method_2_value.keys():
                    if "0x1" in self.method_2_value["setJavaScriptEnabled"]:
                        self.javascript_enabled = True
                        method_present["setJavaScriptEnabled"] = True
                if "addJavascriptInterface" in self.method_2_value.keys():
                    self.javascript_interface = True
                    method_present["addJavascriptInterface"] = True

            else:
                for mf in method_to_find:
                    method_present[mf] = False
                    for mapk in self.method.keys():
                        if mf in mapk:
                            method_present[mf] = True

                if method_present["setJavaScriptEnabled"]:
                    for value in self.method["setJavaScriptEnabled"]:
                        try:
                            if value[1] is not None:
                                encoded_method = value[1]
                                source_code = FileAnalysis.get_list_source_code(
                                    encoded_method)
                                if FileAnalysis.check_method_used_value(
                                        source_code, "setJavaScriptEnabled",
                                        "1"):
                                    # volendo si possono memorizzare tutti i file che lo settano atrue
                                    self.javascript_enabled = True
                                    break

                        except (TypeError, AttributeError, KeyError) as e:
                            self.logger.logger.error(
                                "Exception during check method used {0}".
                                format(e))
                            continue
            print()
            if self.dynamic_javascript_enabled:
                self.logger.logger.info(
                    "[JavaScript enabled (check dynamically) :" +
                    str(self.dynamic_javascript_enabled) + "]")
            else:
                self.logger.logger.info(
                    "[JavaScript enabled (check static):  " +
                    str(self.javascript_enabled) + "]")

        except Exception as e:
            self.logger.logger.error(
                "File conf.json without method setJavaScriptEnabled {0}".
                format(e))

        try:
            if not self.use_smaliparser:

                if self.dynamic_javascript_interface:

                    self.logger.logger.info(
                        "[Add interface WebView (check dynamically): " +
                        str(self.dynamic_javascript_interface) + "]")
                    self.javascript_interface = self.dynamic_javascript_interface

                else:

                    self.logger.logger.info(
                        "[Add interface WebView (check static): " +
                        str(method_present["addJavascriptInterface"]) + "]")
                    self.javascript_interface = method_present[
                        "addJavascriptInterface"]

            else:

                if self.dynamic_javascript_interface:
                    method_present[
                        "addJavascriptInterface"] = self.dynamic_javascript_interface
                    self.logger.logger.info(
                        "[Add interface WebView (check dynamically): " +
                        str(self.dynamic_javascript_interface) + "]")

                else:
                    method_present[
                        "addJavascriptInterface"] = self.javascript_interface
                    self.logger.logger.info(
                        "[Add interface WebView (check static): " +
                        str(self.javascript_interface) + "]")

        except Exception as e:
            # nothing
            self.logger.logger.error(
                "File conf.json without method addJavascriptInterface {0}\n".
                format(e))

        self.is_contains_all_methods = len(method_present) == len(
            method_to_find)
        return self.is_contains_all_methods

    def find_url_in_apk(self):
        """
            find all url/uri inside apk
        """

        # add url using dynamic analysis
        if self.api_monitor_dict is not None and self.network_dict is not None:
            self.add_url_dynamic()

        ##############################################################################
        # use smali_parser
        if self.use_smaliparser:
            # add url loaded for smali_parsr
            if "loadUrl" in self.method_2_value.keys():
                all_url_loaded = self.method_2_value["loadUrl"]

                # da queste devo filtrare ottenendo solo quelle http/https
                temp_url_loaded = list(
                    filter(
                        lambda x: x is not None and
                        (x.startswith("http") or x.startswith("https")),
                        all_url_loaded))
                self.url_loaded = list(set().union(self.url_loaded,
                                                   temp_url_loaded))

        else:
            # ALL string inside apk
            # use AndroGuard
            # url regularp expression
            # url_re = "(http:\/\/|https:\/\/|file:\/\/\/)?[-a-zA-Z0-9@:%._\+~#=]\.[a-z]([-a-zA-Z0-9@:%_\+.~#?&//=]*)"
            url_re = "^(http:\/\/|https:\/\/)\w+"
            list_string_analysis = list()  # list of string analysis object
            # se uso aalysis object
            if self.analysis_object is not None:
                list_string_analysis = self.analysis_object.find_strings(
                    url_re)  # --> gen object

            else:
                list_string = self.dalvik_format.get_regex_strings(url_re)

                # get all string inside apk
                for string_value in list_string:
                    list_string_analysis.append(StringAnalysis(string_value))

            ##################################################################################
            temp_string_value = list()
            # string- tuple with classAnalysis e encodeMethod that use the string
            dict_class_method_analysis = dict()
            for string_analysis in list_string_analysis:
                temp_string_value.append(
                    string_analysis.get_value())  # tutte le url
                dict_class_method_analysis[string_analysis.get_value()] = list(
                    string_analysis.get_xref_from()
                )  # url e relativo codice dove le ho trovate

            ##################################################################################
            # per ogni file, otteniamo una lista di  tupla
            # class analysis e encoded_method
            for key in dict_class_method_analysis.keys():
                for value in dict_class_method_analysis[key]:
                    # class_analysis = value[0]
                    try:
                        if value[1] is not None:
                            encoded_method = value[1]
                            # split the instruction in a list
                            source_code = FileAnalysis.get_list_source_code(
                                encoded_method)
                            if source_code is not None:
                                self.all_url.append(key)  # appendo l'url
                                if FileAnalysis.check_method_used_value(
                                        source_code, "loadUrl", key):
                                    self.url_loaded.append(
                                        key
                                    )  # appendo url se caricata dentro loadUrl

                    except (TypeError, AttributeError, KeyError) as e:
                        self.logger.logger.error(
                            "Exception during find url in apk {0}".format(e))
                        continue

        #######################################################################################################
        # debug part
        if len(self.url_loaded) > 0:
            # print(self.url_loaded)
            self.logger.logger.info(
                "[START URL LOADED INSIDE LOADURL FUNCTION]")
            self.url_loaded = list(set(self.url_loaded))
            for u in self.url_loaded:
                if u.startswith("http://"):
                    self.http_connection_static.append(u)
                self.logger.logger.info(
                    "Url inside load function: {0}".format(u))
            self.logger.logger.info("[END URL LOADED INSIDE LOADURL FUNCTION]")

            md5_file_to_url, file_download_to_analyze = utility.download_page_with_wget(
                self.name_only_apk, self.url_loaded)
            for key in md5_file_to_url.keys():
                if key not in self.md5_file_to_url.keys():
                    self.md5_file_to_url[key] = md5_file_to_url[key]

            for key in file_download_to_analyze.keys():
                if key not in self.file_download_to_analyze.keys():
                    self.file_download_to_analyze[
                        key] = file_download_to_analyze[key]

            # self.download_page_loaded_with_wget()
            self.find_string(self.file_download_to_analyze, remote=True)

        if len(self.all_url) > 0:
            self.all_url = list(set(self.all_url))
            self.logger.logger.info("[START ALL URL INSIDE APK]")
            for u in self.all_url:
                if u.startswith("http://"):
                    self.all_http_connection.append(u)
                self.logger.logger.info("Url inside apk {0}".format(u))
            self.logger.logger.info("[END ALL URL INSIDE APK]")

        html_dir = "temp_html_code/html_downloaded_{0}/".format(
            self.name_only_apk)

        # TODO eliminare
        save_page_html = False
        if os.path.exists(html_dir) and len(
                os.listdir(html_dir)) > 0 and save_page_html:
            # zip -r squash.zip dir1
            subprocess.call([
                "zip", "-r", "temp_html_code/html_{0}.zip".format(
                    self.name_only_apk), html_dir
            ],
                            stdout=subprocess.DEVNULL,
                            stderr=subprocess.DEVNULL)

        # delete dir o provare a zip
        subprocess.Popen(["rm", "-rf", html_dir],
                         stdout=subprocess.DEVNULL,
                         stderr=subprocess.DEVNULL)

    # check vulnerability
    def vulnerable_frame_confusion(self):
        """ 
            check if app is vulnerable on frame confusion
            1) iframe nella stringa di ricerca
            2) metodi addJavascriptInterface e setJavaScriptEnabled usati
            3) permesso internet
            4) almeno un file html con l'iframe all'interno e senza csp
        """

        # se esiste almeno un file con iframe senza csp --> vulnerble
        # se è false --> vulnerabile
        csp_in_file_iframe = True
        app_use_sandbox = True
        # print("File in dict_file_with_string: {}".format(self.dict_file_with_string.keys()))
        # print("File in find_csp: {}".format(self.find_csp.keys()))
        # print("File in file_with_sandbox: {}".format(self.file_with_sandbox.keys()))

        for file_with_iframe in self.dict_file_with_string.keys():
            csp_in_file_iframe = csp_in_file_iframe and self.find_csp[
                file_with_iframe]
            app_use_sandbox = app_use_sandbox and self.file_with_sandbox[
                file_with_iframe]

            if not self.find_csp[
                    file_with_iframe] or not self.file_with_sandbox[
                        file_with_iframe]:
                self.file_vulnerable_frame_confusion.append(file_with_iframe)

        # print("sandbox in app {}".format(self.app_use_sandbox))
        # se vero whitelist implementato male
        white_list_bug = len(
            self.list_origin_access) == 0 or "*" in self.list_origin_access
        self.is_vulnerable_frame_confusion = (
            "iframe" in self.string_to_find and self.check_method_conf()
            and (len(self.dict_file_with_string) > 0
                 or len(self.file_with_string_iframe) > 0)
            and self.is_contain_permission and not csp_in_file_iframe
            and white_list_bug and not self.app_use_sandbox)

    def add_url_dynamic(self):
        """
            function that aggiunge le url caricate 
            diamicamente attraverso che sono state trovate precendetemente 
            dall'analisi dinamica
        """

        #######################################################################################################
        function_load_url = ["loadUrl"]  # funzioni che caricano url in Android
        url_api_monitor = list()
        for keys in self.api_monitor_dict.keys():

            if keys in function_load_url:
                url_api_monitor = list(set().union(
                    url_api_monitor, self.api_monitor_dict[keys]["args"]))
            # dynamic interface and javascript enabled
            if keys == "addJavascriptInterface":
                self.dynamic_javascript_interface = True

            # TODO check --> considero javascriptenabled se ho solo l'interface abilitata
            if keys == "setJavaScriptEnabled" and True in self.api_monitor_dict[
                    keys]["args"]:
                self.dynamic_javascript_enabled = True

        # get all http/https/file in load function
        self.url_dynamic = filter(
            lambda x: x.startswith("http://") or x.startswith("https://") or x.
            startswith("file://"), url_api_monitor)

        self.load_url_dynamic = self.url_dynamic
        #######################################################################################################
        # TODO mettere la funzione evaluateJavaScript o loadUrl javascript: --> come se fosse un file javascript
        javascript_load_url = filter(lambda x: x.startswith("javascript:"),
                                     url_api_monitor)

        # method that exec js in recent api
        javascript_evaluate = list()
        method_evaluate_js = ["evaluateJavascript"]
        for keys in self.api_monitor_dict.keys():
            if keys in method_evaluate_js:
                javascript_evaluate = list(set().union(
                    javascript_evaluate, self.api_monitor_dict[keys]["args"]))

        # now write this code in a file and analyze them
        javascript_code_exec = list(set().union(javascript_load_url,
                                                javascript_evaluate))

        name_file = "code_js_loaded_"
        i = 1
        list_file_js_dynamic = dict()
        dir_write = os.path.join("temp_html_code",
                                 "html_downloaded_" + self.name_only_apk)

        if not os.path.isdir(dir_write):
            os.makedirs(dir_write)

        for code in javascript_code_exec:
            file_js = os.path.join(dir_write, name_file + "{0}.js".format(i))
            file = open(file_js, "w")
            file.write(code)
            file.close()
            list_file_js_dynamic[file_js] = False
            self.javascript_file[file_js] = False

        self.logger.logger.info("[Start javascript code dynamic]")
        self.find_string(list_file_js_dynamic)
        self.logger.logger.info("[End javascript code dynamic]\n")

        #######################################################################################################
        # TODO mettere metodi cordova

        #######################################################################################################
        # ora devo filtrare solo le url che sono http/https
        url_network = list()
        for keys in self.network_dict.keys():
            # TODO check
            url_list_new = list()
            for url in self.network_dict[keys]["url"]:
                # search ip
                ip = re.findall(r"[0-9]+(?:\.[0-9]+){3}", url)
                if ip != None and len(ip) > 0:
                    # change ip with host
                    # get only first element of every list --> every list are max 1 element
                    url_new = url.replace(ip[0],
                                          self.network_dict[keys]["host"][0])
                    url_list_new.append(url_new)
                else:
                    url_list_new.append(url)
            # add new url
            self.network_dict[keys]["url"] = url_list_new
            url_network = list(set().union(url_network,
                                           self.network_dict[keys]["url"]))

        ##########################################################################################################
        # remove url google
        # url effettivamente caricate nell'applicazione
        self.url_dynamic = list(set().union(self.url_dynamic, url_network))
        self.all_url_dynamic = self.url_dynamic
        url_dynamic_to_remove = list()
        for url_dyn in self.url_dynamic:
            for url_to_check in self.conf["url_to_remove"]:
                if url_to_check in url_dyn:
                    url_dynamic_to_remove.append(url_dyn)

        # TODO maybe to add
        url_dynamic_to_remove = list(set(url_dynamic_to_remove))
        for url_to_remove in url_dynamic_to_remove:
            self.url_dynamic.remove(url_to_remove)

        #######################################################################################################
        self.url_loaded = list(set().union(self.url_loaded, self.url_dynamic))

        self.all_url = list(set().union(self.all_url, self.url_loaded))
        self.logger.logger.info("[Init add url dynamic ]")
        for u in self.url_dynamic:
            if u.startswith("http://"):
                self.http_connection.append(u)
            if u in self.load_url_dynamic:
                self.logger.logger.info(
                    "Url dynamic inside loadUrl{0}".format(u))
            else:
                self.logger.logger.info("Url dynamic {0}".format(u))

        self.logger.logger.info("[End url dynamic]\n")