Esempio n. 1
0
    def analyze(self):
        self.packed_files = dict()
        self.malware_detect()

        for file in self.a.get_files():
            file_type = check_header(self.a.get_file(file)[0:4].hex())

            if file_type == "JAR":
                write_file_to_dir(self.output_dir,
                                  file.split("/")[-1], a.get_file(file))
                try:
                    a, d, dx = AnalyzeAPK(self.output_dir +
                                          file.split("/")[-1])
                    if a.get_package():
                        self.packed_files[self.a.get_package()] = {file: {}}
                    else:
                        continue
                except Exception as e:
                    # not an APK file
                    continue

                with open(PERMISSIONS_FILE) as json_file:
                    permissions = json.load(json_file)

                perms_desc = {}
                dangerous_perms = {}

                if a.get_permissions():
                    for perm in a.get_permissions():
                        try:
                            perms_desc[perm] = {
                                "description":
                                permissions[perm]["description"],
                                "level": permissions[perm]["protection_lvl"]
                            }
                            if any(
                                    re.findall(
                                        r'dangerous',
                                        permissions[perm]["protection_lvl"],
                                        re.IGNORECASE)):
                                # Permission is flagged as dangerous
                                dangerous_perms[permissions[perm]
                                                ["permission"]] = permissions[
                                                    perm]["description"]

                        except Exception as e:
                            continue

                self.packed_files[self.a.get_package()][file] = dangerous_perms

        return {
            "packed_file": self.packed_files,
            "detected_malware": self.detected_malware
        }
Esempio n. 2
0
    def each(self, target):
        self.results = dict()

        try:
            apk, vm, vm_analysis = AnalyzeAPK(target)

            # First, get basic information about the APK
            self.results['name'] = apk.get_app_name()
            self.results['package'] = apk.get_package()
            self.results['permissions'] = apk.get_permissions()
            self.results['main_activity'] = apk.get_main_activity()
            self.results['receivers'] = apk.get_receivers()
            self.results['services'] = apk.get_services()
            self.results['main_activity_content'] = vm.get_class("L{};".format(
                self.results['main_activity']).replace('.', '/')).get_source()
        except:
            apk = None
            vm, vm_analysis = AnalyzeDex(target)
            self.results['dex'] = True

        # Then, run all the APK Plugins in order to see if this is a known malware
        for plugin in APKPlugin.__subclasses__():
            plugin = plugin(target, apk, vm, vm_analysis)
            plugin.apply(self)

        return True
Esempio n. 3
0
    def analyse(self):
        self.packed_files = dict()
        self.malware_detect()

        for file in self.a.get_files():
            file_type = check_header(self.a.get_file(file)[0:4].hex())

            if file_type == "JAR":

                if not os.path.isdir(self.output_dir):
                    os.makedirs(self.output_dir)

                f = open(self.output_dir + file.split("/")[-1], 'wb')
                f.write(self.a.get_file(file))
                f.close()
                try:
                    a, d, dx = AnalyzeAPK(self.output_dir + file.split("/")[-1])

                    if a.get_package():
                        self.packed_files[self.a.get_package()] = {file: {}}
                    else:
                        continue
                except Exception as e:
                    # not an APK file
                    continue

                with open(PERMISSIONS_FILE) as json_file:
                    permissions = json.load(json_file)

                perms_desc = {}
                dangerous_perms = {}

                if a.get_permissions():
                    for perm in a.get_permissions():
                        try:
                            mapped = list(filter(lambda x: x["permission"] == perm, permissions))
                            perms_desc[perm] = {"desc": mapped[0]["desc"], "level": mapped[0]["protection_lvl"]}
                            if any(re.findall(r'dangerous', mapped[0]["protection_lvl"], re.IGNORECASE)):
                                # Permission is flagged as dangerous
                                dangerous_perms[mapped[0]["permission"]] = mapped[0]["desc"]

                        except Exception as e:
                            continue

                self.packed_files[self.a.get_package()][file] = dangerous_perms

        return {"packed_file": self.packed_files, "detected_malware": self.detected_malware}
Esempio n. 4
0
def main(args=None, stdout_suppress=False, stderr_suppress=False):
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdout = devnull if stdout_suppress else sys.stdout
        sys.stderr = devnull if stderr_suppress else sys.stderr
        results = None
        try:
            if args and not isinstance(args, list):
                raise TypeError(f"Args are {type(args)}, which is not a list.")
            _args = _parseargs(args)
            _a, _vm, _vmx = AnalyzeAPK(_args.file)

            print(("Analyse file: {:s}".format(_args.file)))
            print(("Package name: {:s}".format(_a.get_package())))

            if "android.permission.INTERNET" in _a.get_permissions():
                print("App requires INTERNET permission. Continue analysis...")

                _result = {
                    "trustmanager": [],
                    "hostnameverifier": [],
                    "onreceivedsslerror": [],
                }
                _result = _check_all(_vm, _vmx)
                results = _result
                if not _args.xml and not _args.output:
                    _print_result(_result, _java=_args.java)
                else:
                    _xml_result(
                        _a,
                        _result,
                        printed=True if _args.xml else False,
                        file=_args.output if _args.output else None,
                    )

                if _args.dir:
                    print("Store decompiled Java code in {:s}".format(_args.dir))
                    _store_java(_vmx, _vm, _args)
            else:
                print(
                    "App does not require INTERNET permission. No need to worry about SSL misuse... Abort!"
                )

        except:
            import traceback

            # printing stack trace
            traceback.print_exc()
        finally:
            sys.stdout = old_stdout
            sys.stderr = old_stderr
            return results
Esempio n. 5
0
def GetFromInstructions(apkfile, PMap):
    SuspiciousApiSet = set()
    URLDomainSet = set()
    UsedPermissionSet = set()
    restrictedApiSet = set()
    apiList = getSentitiveApiList()
    try:
        apkfile = os.path.abspath(apkfile)
        a, d, dx = AnalyzeAPK(apkfile)
    except Exception as e:
        print(e)
        return

    requestedPermission = a.get_permissions()
    print(requestedPermission)
    for method in d[0].get_methods():
        g = dx.get_method(method)
        for BasicBlock in g.get_basic_blocks().get():
            instructions = BasicBlockAttrBuilder.GetBasicBlockDalvikCode(
                BasicBlock)

            calledApis = getApiCalls(instructions)
            for apiCall in calledApis:
                for sApi in apiList:
                    if apiCall in sApi:
                        SuspiciousApiSet.add(sApi)
                        break

                perm = pmap.GetPermFromFullApi(apiCall)
                if (perm != None):
                    UsedPermissionSet.add(perm)
                    if perm not in requestedPermission:
                        restrictedApiSet.add(apiCall)

            for Instruction in instructions:
                URLSearch = re.search(
                    r"https?://([\da-z\.-]+\.[a-z\.]{2, 6}|[\d.]+)[^'\"]*",
                    Instruction, re.IGNORECASE)
                if (URLSearch):
                    URL = URLSearch.group()
                    Domain = re.sub(
                        "https?://(.*)", "\g<1>",
                        re.search(r"https?://([^/:\\\\]*)", URL,
                                  re.IGNORECASE).group(), 0, re.IGNORECASE)
                    URLDomainSet.add(Domain)

    return SuspiciousApiSet, URLDomainSet, UsedPermissionSet, restrictedApiSet
Esempio n. 6
0
def sigpidclass(path):
    # import pandas as pd
    # app.config['SFILE']=r"C:\Users\moham\drebinsayo\scripts\srd"
    # ds=app.config["SFILE"]
    # ps=os.listdir(ds)
    # for fffs in ps:
    #     bbbs=os.path.join(app.config["SFILE"], fffs)
    #     os.remove(bbbs)
    # files = request.files["file"]
    # apple=app.config['SFILE']
    # files.save(os.path.join(app.config["SFILE"], files.filename))
    # # import GetApkData as ge
    # # import importlib
    # # importlib.reload(ge)
    # sapple=files.filename
    # fsapple=ds+"\\"+sapple
    from androguard.misc import AnalyzeAPK
    a, d, dx = AnalyzeAPK(path)
    ttapp = a.get_permissions()
    #ttapp= android.permission.send_sms
    for t in ttapp:
        if t[0] != 'a':
            ttapp.remove(t)
    el = []
    for i in ttapp:
        k = i.split('.')[-1]
        el.append(k)
    dpermf = pd.read_csv('onlydangsigt.csv')
    malapp = {i: 0 for i in dpermf.columns}
    del malapp['malware']
    for i in el:
        for j in malapp:
            if (i == j):
                malapp[j] = 1
    y_testap = list(malapp.values())
    y_testwork = np.array([np.array(y_testap)])
    model = pickle.load(open('rfc_sig.pkl', 'rb'))
    bans = model.predict(y_testwork)
    if (bans == False):
        band = "benign"
    else:
        band = "malware"
    return band
Esempio n. 7
0
def analyze(app):

    result = {}

    # We open the APK
    apk_path = c.get_apk_path(app)
    # Here we check if the APK is actually there, otherwise we skip the analysis
    if (not os.path.exists(apk_path)):
        return
    a, d, dx = AnalyzeAPK(apk_path)

    # Get all the permissions requested by the app
    requested_permissions = a.get_permissions()

    # Get all the Android activities of the app
    activities = a.get_activities()

    # Get all String constants in the app presumably containing a URL
    urls = list()
    for u in dx.find_strings("http[s]?://."):
        urls.append(u.get_value())

    # We pack together all the partial results
    result['permissions'] = requested_permissions
    result['activities'] = activities
    result['urls'] = urls

    # We save the result into a JSON file
    app_suffix_path = app['id'] + c.SEPARATOR + app['latest_crawled_version']
    result_path = c.DATA_PATH + app_suffix_path + c.SEPARATOR + 'androguard.json'
    c.save(result_path, result)

    # Now we run also the Androwarn analysis (with no Play Store look up)
    data = perform_analysis(apk_path, a, d, dx, False)

    # We generate the JSON report with the following parameters
    # Verbosity level: 3 (advanced)
    # Report type: json
    # Output path: same pattern as all the other JSON files produced so far
    androwarn_report_path = c.DATA_PATH + app_suffix_path + c.SEPARATOR + 'androwarn.json'
    generate_report(app['id'], data, 3, 'json', androwarn_report_path)
Esempio n. 8
0
def get_prediction():
    f_rep = [0] * 900
    dat = flask.request.get_json()
    name = dat['file_name']
    with open(name, 'rb') as f:
        b = f.read()
        a, d, dx = AnalyzeAPK(b, raw = True)
    perms = str(a.get_permissions())
    perm_count = len(perms)
    app_name = a.get_app_name()
    perms = re.findall(r"(?=.)[A-Z|_]+(?=')", perms)
    for p in perms:
        if p in features:
            f_rep[features.index(p)] = 1
    xml = apk.APK(name).get_android_manifest_xml()
    xml = tostring(xml, encoding = 'unicode')
    intents = re.findall(r'(?<=<intent\-filter>)(.*?)(?=</intent\-filter>)',xml,re.DOTALL)
    for intent in intents:
        ints= (re.findall(r'(?<=\<action android:name=\")([^"]*)"',intent,re.DOTALL))
        for a in ints:
            if a in features:
                f_rep[features.index(a)] = 1
    classes = dx.get_external_classes()
    class_count = len(classes)
    for classObj in classes:
        vmClass = str(classObj.get_vm_class())
        if vmClass not in api_dang:
            continue
        vmMeth = classObj.get_methods()
        for vmMethIter in vmMeth:
            met = str(vmMethIter.method)
            if met in features:
                f_rep[features.index(met)] = 1
    f_rep = np.array(f_rep)[np.newaxis, :]
    pred = model.predict(f_rep)[0]
    response = {"appName": app_name, "class": pred, "permCount": perm_count, "fileName": name, "classCount": class_count}
    response = flask.jsonify(response)
    return response
Esempio n. 9
0
def analyseAPK(apk_file):

    sha256 = get_sha256(apk_file)
    a, d, dx = AnalyzeAPK(apk_file)

    # ============== extract permissions ===============
    permissions = a.get_permissions()

    # ============== extract sensitiveApis ===============
    sensitiveApis = set()
    for dd in d:
        for method in dd.get_methods():
            g = dx.get_method(method)
            for BasicBlock in g.get_basic_blocks().get():
                instructions = BasicBlockAttrBuilder.GetBasicBlockDalvikCode(
                    BasicBlock)
                PscoutApis = BasicBlockAttrBuilder.GetInvokedPscoutApis(
                    instructions)
                sensitiveApis = sensitiveApis.union(PscoutApis)

    # ============== extract third-party-libraries ===========
    tpls = getThirdPartyLibrary(apk_file, sha256)

    return sha256, permissions, list(sensitiveApis), tpls
    ret_type = androconf.is_android(args.APK)
    if ret_type != "APK":
        print("Not an APK file")
        sys.exit(1)

    apk, dex, dexes = AnalyzeAPK(args.APK)

    res = {
        'app_name':
        apk.get_app_name(),
        'package_name':
        apk.get_package(),
        'providers':
        apk.get_providers(),
        'new_permissions':
        extract_new_permissions(apk.get_permissions()),
        'filters':
        get_intent_filers(apk),
        'certificate': {},
        'wearable':
        apk.is_wearable(),
        'max_sdk_version': (apk.get_max_sdk_version()),
        'min_sdk_version':
        int(apk.get_min_sdk_version()),
        'version_code':
        apk.xml['AndroidManifest.xml'].get(
            '{http://schemas.android.com/apk/res/android}versionCode'),
        'libraries':
        list(apk.get_libraries()),
        'androidtv':
        apk.is_androidtv(),
Esempio n. 11
0
def generate_facts(app_folder,result_prefix,rules,storage=None):
    files = get_all_in_dir(app_folder,"*")
    send_intent_actions_stats = Counter()
    recv_intent_actions_stats = Counter()
    len_files = 0
    is_apk = None
    for file in files:
        logging.info("Analyzing file %s",file)
        try:
            a,d, dx = AnalyzeAPK(file)
            is_apk = True
            # Create package to file relations
        except:
            is_apk = None
            print "Not valid APK file:  "+file
        try:
            if is_apk:
                with open(result_prefix+"_packages.txt", 'a') as f:
                    f.write("package('"+a.get_package()+"','"+ntpath.basename(file)+"').\n")
                # Permissions
                permissions = []
                permissions.extend([(str(a.get_package()), permission) for permission in a.get_permissions()])
                with open(result_prefix+"_uses_aux.txt", 'a') as f:
                    for permission in permissions:
                        f.write("uses('"+permission[0]+"','"+permission[1]+"').\n")
                # Intents
                logging.info("Looking for Intent Sends")
                sends = Set()
                sends.update([(str(a.get_package()),"i_"+intent.action) for intent in get_implicit_intents(a,d,dx)])
                send_intent_actions_stats.update([send[1] for send in sends])
                # Shared Prefs
                logging.info("Looking for Shared Prefs Sends")
                sends.update([(str(a.get_package()),"sp_"+shared.package+"_"+shared.preference_file) for shared in get_shared_preferences_writes(a,d,dx)])
                with open(result_prefix+"_trans_aux.txt", 'a') as f:
                    for send in sends:
                        f.write("trans('"+send[0]+"','"+escape_quotes(send[1])+"').\n")
                # Receivers
                logging.info("Looking for Dynamic Receivers")
                receives = Set()
                receives.update([(str(a.get_package()),"i_"+receiver.get_action()) for receiver in get_dynamic_receivers(a,d,dx)])
                logging.info("Looking for Static Receivers")
                receives.update([(str(a.get_package()),"i_"+receiver.get_action()) for receiver in get_static_receivers(a)])
                recv_intent_actions_stats.update([receive[1] for receive in receives])
                # Shared Prefs
                logging.info("Looking for Shared Prefs Receives")
                receives.update([(str(a.get_package()),"sp_"+shared.package+"_"+shared.preference_file) for shared in get_shared_preferences_reads(a,d,dx)])
                with open(result_prefix+"_recv_aux.txt", 'a') as f:
                     for receive in receives:
                        f.write("recv('"+receive[0]+"','"+escape_quotes(receive[1])+"').\n")
                len_files += 1
                utils.remove_duplicate_lines(result_prefix+"_uses_aux.txt",result_prefix+"_uses.txt",True)
                utils.remove_duplicate_lines(result_prefix+"_trans_aux.txt",result_prefix+"_trans.txt",True)
                utils.remove_duplicate_lines(result_prefix+"_recv_aux.txt",result_prefix+"_recv.txt",True)
        except:
            print "Error during analysis:  "+file
            traceback.print_exc()
    if rules != "":
        with open(os.path.splitext(rules)[0]+"_program.pl", 'w') as f:
            #write packages
            with open(result_prefix+"_packages.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
            #write uses
            with open(result_prefix+"_uses.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
            #write trans
            with open(result_prefix+"_trans.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
                if storage:
                    f.write("trans(A,'external_storage'):- uses(A,'android.permission.WRITE_EXTERNAL_STORAGE').\n")
            #write receives
            with open(result_prefix+"_recv.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
                if storage:
                    f.write("recv(A,'external_storage'):- uses(A,'android.permission.WRITE_EXTERNAL_STORAGE').\n")
                    f.write("recv(A,'external_storage'):- uses(A,'android.permission.READ_EXTERNAL_STORAGE').\n")
            with open(rules, 'r') as to_read:
                f.writelines(to_read.readlines())
    with open(result_prefix+"_intent_send_stats",'w') as send_stats_file:
        send_stats_file.write("**** Results for send intent analysis ****\n")
        send_stats_file.write("Files analized: ")
        send_stats_file.write(str(len_files))
        send_stats_file.write("\n")
        for send_stat in send_intent_actions_stats.most_common():
            freq = send_stat[1]/len_files
            send_stats_file.write(send_stat[0]+", "+"{0:.2f}".format(round(freq,2))+", "+str(send_stat[1])+"\n")
    with open(result_prefix+"_intent_recv_stats",'w') as recv_stats_file:
        recv_stats_file.write("**** Results for send intent analysis ****\n")
        recv_stats_file.write("Files analized: ")
        recv_stats_file.write(str(len_files))
        recv_stats_file.write("\n")
        for recv_stat in recv_intent_actions_stats.most_common():
            freq = recv_stat[1]/len_files
            recv_stats_file.write(recv_stat[0]+", "+"{0:.2f}".format(round(freq,2))+", "+str(recv_stat[1])+"\n")
    logging.info("Results saved in %s files",result_prefix)
    return os.path.splitext(rules)[0]+"_program.pl"
Esempio n. 12
0
class XRule:
    def __init__(self, apk):

        self.a, self.d, self.dx = AnalyzeAPK(apk)

        # Create Class, Method, String and Field
        # crossreferences for all classes in the Analysis.
        # self.dx.create_xref()

        self.pre_method0 = []
        self.pre_method1 = []

        self.same_sequence_show_up = []
        self.same_operation = []
        self.check_item = [False, False, False, False, False]

        # Pretty Table Output
        self.tb = PrettyTable()
        self.tb.field_names = ["Rule", "Confidence", "Score", "Weight"]
        self.tb.align = "l"

        # Sum of the each weight
        self.weight_sum = 0
        # Sum of the each rule
        self.score_sum = 0

    @property
    def permissions(self):
        """
        :returns: A list of permissions
        :rtype: list
        """
        return self.a.get_permissions()

    def find_method(self, class_name=".*", method_name=".*"):
        """
        Find method from given class_name and method_name,
        default is find all.

        :returns: an generator of MethodClassAnalysis
        :rtype: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if (result is not None) and len(list(result)) > 0:
            return self.dx.find_methods(class_name, method_name)

        else:
            # Method Not Found
            return None

    def upperFunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.
        :param class_name:
        :param method_name:
        :return: list
        """

        result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for md in method_set:
                for _, call, _ in md.get_xref_from():
                    # Get class name and method name:
                    # call.class_name, call.name
                    result.append((call.class_name, call.name))

            return remove_dup_list(result)
        else:
            return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.
        :param class_name:
        :param method_name:
        :return: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if result is not None:
            for m in self.dx.find_methods(class_name, method_name):
                for idx, ins in m.get_method().get_instructions_idx():
                    bytecode_obj = None
                    reg_list = []

                    # count the number of the registers.
                    length_operands = len(ins.get_operands())
                    if length_operands == 0:
                        # No register, no parm
                        bytecode_obj = BytecodeObject(ins.get_name(), None,
                                                      None)
                    elif length_operands == 1:
                        # Only one register

                        reg_list.append(
                            "v" +
                            str(ins.get_operands()[length_operands - 1][1]))
                        bytecode_obj = BytecodeObject(
                            ins.get_name(),
                            reg_list,
                            None,
                        )
                    elif length_operands >= 2:
                        # the last one is parm, the other are registers.

                        parameter = ins.get_operands()[length_operands - 1]
                        for i in range(0, length_operands - 1):
                            reg_list.append("v" +
                                            str(ins.get_operands()[i][1]))
                        if len(parameter) == 3:
                            # method or value
                            parameter = parameter[2]
                        else:
                            # Operand.OFFSET
                            parameter = parameter[1]

                        bytecode_obj = BytecodeObject(
                            ins.get_name(),
                            reg_list,
                            parameter,
                        )

                    yield bytecode_obj
        else:
            raise ValueError("Method Not Found")

    def find_f_previous_method(self, base, top):
        """
        Find the previous method based on base method
        before top method.

        This will append the method into self.pre_method0
        :param base:
        :param top:
        :return: None
        """

        method_set = self.upperFunc(base[0], base[1])

        if method_set is not None:

            if top in method_set:
                self.pre_method0.append(base)
            else:
                for item in method_set:
                    self.find_f_previous_method(item, top)

    def find_s_previous_method(self, base, top):
        """
        Find the previous method based on base method
        before top method.

        This will append the method into self.pre_method1
        :param base:
        :param top:
        :return: None
        """

        method_set = self.upperFunc(base[0], base[1])

        if method_set is not None:
            if top in method_set:
                self.pre_method1.append(base)
            else:
                for item in method_set:
                    self.find_s_previous_method(item, top)

    def find_intersection(self, list1, list2, depth=1):
        """
        Find the list1 ∩ list2.

        list1 & list2 are list within tuple, for example,
        [("class_name","method_name"),...]

        :param list1:
        :param list2:
        :param depth: MAX recursion
        :return:
        """
        # Check both lists are not null
        if len(list1) > 0 and len(list2) > 0:

            # Limit up to three layers of the recursions.
            if depth == MAX_SEARCH_LAYER:
                return None
            # find ∩
            result = set(list1).intersection(list2)
            if len(result) > 0:

                return result
            else:
                # Not found same method usage, try to find the next layer.

                next_list1 = []
                next_list2 = []
                for item in list1:
                    if self.upperFunc(item[0], item[1]) is not None:
                        next_list1 = self.upperFunc(item[0], item[1])
                for item in list2:
                    if self.upperFunc(item[0], item[1]) is not None:
                        next_list2.extend(self.upperFunc(item[0], item[1]))
                # Append first layer into next layer
                for pre_list in list1:
                    next_list1.append(pre_list)
                for pre_list in list2:
                    next_list2.append(pre_list)

                depth += 1

                # To find the same method, push the previous two
                # methods into the stack here. Once it found there
                # is same method, pop the previous method from stack.
                self.pre_method0.append(list1)
                self.pre_method1.append(list2)

                return self.find_intersection(next_list1, next_list2, depth)
        else:
            raise ValueError("List is Null")

    def check_sequence(self, same_method, f_func, s_func):
        """
        Check if the first function appeared before the second function.

        :param same_method: the tuple with (class_name, method_name)
        :param f_func: the first show up function, which is (class_name, method_name)
        :param s_func: the tuple with (class_name, method_name)
        :return: boolean
        """

        method_set = self.find_method(same_method[0], same_method[1])
        seq_table = []

        if method_set is not None:
            for md in method_set:
                for _, call, number in md.get_xref_to():

                    to_md_name = str(call.name)

                    if (to_md_name == f_func[1]) or (to_md_name == s_func[1]):

                        seq_table.append((call.name, number))

            # sorting based on the value of the number
            if len(seq_table) < 2:
                # Not Found sequence in same_method
                return False
            seq_table.sort(key=operator.itemgetter(1))

            idx = 0
            length = len(seq_table)
            f_func_val = None
            s_func_val = None
            while idx < length:
                if seq_table[idx][0] == f_func[1]:
                    f_func_val = idx
                    break
                idx += 1
            while length > 0:
                if seq_table[length - 1][0] == s_func[1]:
                    s_func_val = length - 1
                    break
                length -= 1

            if s_func_val > f_func_val:
                # print("Found sequence in :" + repr(same_method))
                return True
            else:
                return False

    def check_parameter(self, common_method, fist_method_name,
                        second_method_name):
        """
        check the usage of the same parameter between
        two method.

        :param common_method: ("class_name", "method_name")
        :param fist_method_name:
        :param second_method_name:
        :return:
        """

        pyeval = PyEval()
        # Check if there is an operation of the same register
        state = False

        for bytecode_obj in self.get_method_bytecode(common_method[0],
                                                     common_method[1]):
            # ['new-instance', 'v4', Lcom/google/progress/SMSHelper;]
            instruction = []
            instruction.append(bytecode_obj.mnemonic)
            if bytecode_obj.registers is not None:
                instruction.extend(bytecode_obj.registers)
            if bytecode_obj.parameter is not None:
                instruction.append(bytecode_obj.parameter)

            # for the case of MUTF8String
            instruction = [str(x) for x in instruction]

            if instruction[0] in pyeval.eval.keys():

                pyeval.eval[instruction[0]](instruction)

        for table in pyeval.show_table():
            for val_obj in table:
                matchers = [fist_method_name, second_method_name]
                matching = [
                    s for s in val_obj.called_by_func
                    if all(xs in s for xs in matchers)
                ]
                if len(matching) > 0:
                    state = True
                    break
        return state

    def run(self, rule_obj):
        """
        Run the five levels check to get the y_score.
        :param rule_obj:
        :return:
        """

        # Level 1
        if set(rule_obj.x1_permission).issubset(set(self.permissions)):
            self.check_item[0] = True

        # Level 2
        test_md0 = rule_obj.x2n3n4_comb[0]["method"]
        test_cls0 = rule_obj.x2n3n4_comb[0]["class"]
        if self.find_method(test_cls0, test_md0) is not None:
            self.check_item[1] = True
            # Level 3
            test_md1 = rule_checker.x2n3n4_comb[1]["method"]
            test_cls1 = rule_checker.x2n3n4_comb[1]["class"]
            if self.find_method(test_cls1, test_md1) is not None:
                self.check_item[2] = True

                # Level 4
                # [('class_a','method_a'),('class_b','method_b')]
                # Looking for the first layer of the upperfunction
                upperfunc0 = self.upperFunc(test_cls0, test_md0)
                upperfunc1 = self.upperFunc(test_cls1, test_md1)

                same = self.find_intersection(upperfunc0, upperfunc1)
                if same is not None:

                    for common_method in same:

                        base_method_0 = (test_cls0, test_md0)
                        base_method_1 = (test_cls1, test_md1)
                        self.pre_method0.clear()
                        self.pre_method1.clear()
                        self.find_f_previous_method(base_method_0,
                                                    common_method)
                        self.find_s_previous_method(base_method_1,
                                                    common_method)
                        # TODO It may have many previous method in self.pre_method
                        pre_0 = self.pre_method0[0]
                        pre_1 = self.pre_method1[0]

                        if self.check_sequence(common_method, pre_0, pre_1):
                            self.check_item[3] = True
                            self.same_sequence_show_up.append(common_method)

                            # Level 5
                            if self.check_parameter(common_method,
                                                    str(pre_0[1]),
                                                    str(pre_1[1])):
                                self.check_item[4] = True
                                self.same_operation.append(common_method)

    def show_easy_report(self, rule_obj):
        """
        Show the summary report.

        :param rule_obj:
        :return:
        """
        # Count the confidence
        confidence = str(self.check_item.count(True) * 20) + "%"
        conf = self.check_item.count(True)
        weight = rule_obj.get_score(conf)
        score = rule_obj.yscore

        self.tb.add_row(
            [green(rule_obj.crime),
             yellow(confidence), score,
             red(weight)])

        # add the weight
        self.weight_sum += weight
        # add the score
        self.score_sum += score

    def show_detail_report(self, rule_obj):
        """
        Show the detail report

        :param rule_obj:
        :return:
        """

        # Count the confidence
        print("")
        print("Confidence:" + str(self.check_item.count(True) * 20) + "%")
        print("")

        if self.check_item[0]:

            COLOR_OUTPUT_RED("\t[" + u"\u2713" + "]")
            COLOR_OUTPUT_GREEN(bold("1.Permission Request"))
            print("")

            for permission in rule_obj.x1_permission:
                print("\t\t" + permission)
        if self.check_item[1]:

            COLOR_OUTPUT_RED("\t[" + u"\u2713" + "]")
            COLOR_OUTPUT_GREEN(bold("2.Native API Usage"))
            print("")
            print("\t\t" + rule_obj.x2n3n4_comb[0]["method"])
        if self.check_item[2]:

            COLOR_OUTPUT_RED("\t[" + u"\u2713" + "]")
            COLOR_OUTPUT_GREEN(bold("3.Native API Combination"))

            print("")
            print("\t\t" + rule_obj.x2n3n4_comb[0]["method"])
            print("\t\t" + rule_obj.x2n3n4_comb[1]["method"])
        if self.check_item[3]:

            COLOR_OUTPUT_RED("\t[" + u"\u2713" + "]")
            COLOR_OUTPUT_GREEN(bold("4.Native API Sequence"))

            print("")
            print("\t\t" + "Sequence show up in:")
            for seq_methon in self.same_sequence_show_up:
                print("\t\t" + repr(seq_methon))
        if self.check_item[4]:

            COLOR_OUTPUT_RED("\t[" + u"\u2713" + "]")
            COLOR_OUTPUT_GREEN(bold("5.Native API Use Same Parameter"))
            print("")
            for seq_operation in self.same_operation:
                print("\t\t" + repr(seq_operation))
Esempio n. 13
0
class Apkinfo:
    """Information about apk based on androguard analysis"""
    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        # return the APK, list of DalvikVMFormat, and Analysis objects
        self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(apk_filepath)
        self.apk_filename = os.path.basename(apk_filepath)
        self.apk_filepath = apk_filepath

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def filename(self):
        """
        Return the filename of apk.

        :return: a string of apk filename
        """
        return os.path.basename(self.apk_filepath)

    @property
    def filesize(self):
        """
        Return the file size of apk file by bytes.

        :return: a number of size bytes
        """
        return os.path.getsize(self.apk_filepath)

    @property
    def md5(self):
        """
        Return the md5 checksum of the apk file.

        :return: a string of md5 checksum of the apk file
        """
        md5 = hashlib.md5()
        with open(self.apk_filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5.update(chunk)
        return md5.hexdigest()

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        return self.apk.get_permissions()

    def find_method(self, class_name=".*", method_name=".*", descriptor=None):
        """
        Find method from given class_name and method_name,
        default is find all method.

        :param descriptor:
        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of MethodClassAnalysis
        """

        regex_method_name = f"^{method_name}$"

        if descriptor is not None:

            des = descriptor.replace(")", "\)").replace("(", "\(")

            result = self.analysis.find_methods(class_name,
                                                regex_method_name,
                                                descriptor=des)

            if list(result):
                return self.analysis.find_methods(class_name,
                                                  regex_method_name,
                                                  descriptor=des)
            else:
                return None
        else:

            result = self.analysis.find_methods(class_name, regex_method_name)

            if list(result):
                return self.analysis.find_methods(class_name,
                                                  regex_method_name)
            else:
                return None

    def upperfunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a list of all upper functions
        """

        upperfunc_result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for method in method_set:
                for _, call, _ in method.get_xref_from():
                    # Call is the MethodAnalysis in the androguard
                    # call.class_name, call.name, call.descriptor
                    upperfunc_result.append(call)

            return tools.remove_dup_list(upperfunc_result)

        return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of all bytecode instructions
        """

        result = self.analysis.find_methods(class_name, method_name)

        if list(result):
            for method in self.analysis.find_methods(class_name, method_name):
                try:
                    for _, ins in method.get_method().get_instructions_idx():
                        bytecode_obj = None
                        reg_list = []

                        # count the number of the registers.
                        length_operands = len(ins.get_operands())
                        if length_operands == 0:
                            # No register, no parameter
                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                None,
                                None,
                            )
                        elif length_operands == 1:
                            # Only one register

                            reg_list.append(
                                f"v{ins.get_operands()[length_operands - 1][1]}",
                            )
                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                reg_list,
                                None,
                            )
                        elif length_operands >= 2:
                            # the last one is parameter, the other are registers.

                            parameter = ins.get_operands()[length_operands - 1]
                            for i in range(0, length_operands - 1):
                                reg_list.append(
                                    "v" + str(ins.get_operands()[i][1]), )
                            if len(parameter) == 3:
                                # method or value
                                parameter = parameter[2]
                            else:
                                # Operand.OFFSET
                                parameter = parameter[1]

                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                reg_list,
                                parameter,
                            )

                        yield bytecode_obj
                except AttributeError as error:
                    # TODO Log the rule here
                    continue
def analyze_apk_androguard(apk_file: str,
                           md5_app: str = None,
                           dict_analysis_apk: dict = None):
    """

    Parameters
    ----------
    apk_file

    Returns
    -------

    """
    tracker_name_package = {}  # package name analytics to monitoring
    logger.info("Start App Analyzer")
    start = time.time()
    application, dalvik, analysis = AnalyzeAPK(apk_file)

    # read all trackers package name inside app
    with open(
            os.path.join(os.getcwd(), "resources",
                         "package_name_trackers_most_used.txt"), "r") as file:
        tracker_list = file.readlines()
        tracker_list = [x.strip() for x in tracker_list]

    # creation of regular expression for searching methods inside apps
    for tracker in tracker_list:
        name = tracker.split(",")[0]
        packages = tracker.split(",")[1].split("|")
        packages_new = []
        for package in packages:
            package_new = "L" + package.replace(".", "/")
            if package_new.endswith("/"):
                package_new = package_new + ".*"
            else:
                package_new = package_new + "/.*"
            packages_new.append(package_new)
        tracker_name_package[name] = packages_new

    # creation list of API for monitoring
    n_method = 0
    list_tracker_inside_app = []
    trackers_api_to_monitoring = {
    }  # dict api to monitoring during dynamic analysis
    for key, list_package_name in tracker_name_package.items():
        for package_name in list_package_name:
            methods = list(
                analysis.find_methods(package_name)
            )  # find all methods that satisfy regular expression

            if len(methods) > 0:
                trackers_api_to_monitoring[package_name] = []
                list_tracker_inside_app.append(key)

            # add each method to list for monitoring during dynamic analysis
            for method in methods:
                n_method = n_method + 1
                trackers_api_to_monitoring[package_name].append(
                    (method.get_method().get_class_name().replace(
                        "L", "", 1).replace("/", ".").replace(";", ""),
                     method.get_method().get_name()))

            if len(methods) > 0:
                # remove duplicate
                trackers_api_to_monitoring[package_name] = list(
                    set(trackers_api_to_monitoring[package_name]))

    list_tracker_inside_app = list(set(list_tracker_inside_app))
    list_permissions_app = application.get_permissions()
    end = time.time()
    logger.info(
        "Permission requested by the app {}".format(list_permissions_app))
    logger.info("Tracker inside the app {}".format(list_tracker_inside_app))
    logger.info("Execution time App Analyzer {}".format(end - start))
    # logger.info("API to Monitoring (Trackers) {}".format(n_method))

    dict_analysis_apk["permission_requested"] = list_permissions_app
    dict_analysis_apk["trackers_inside"] = list_tracker_inside_app
    dict_analysis_apk["execution_time_app_analyzer"] = end - start
    # dict_analysis_apk["api_to_monitoring_trackers"] = n_method

    write_result_md5_app(md5_app, list_tracker_inside_app,
                         list_permissions_app, end - start, dict_analysis_apk)
    logger.info("End App Analyzer")

    return list_tracker_inside_app, list_permissions_app, trackers_api_to_monitoring, application, dict_analysis_apk
Esempio n. 15
0
def main():
    input_dir = './recv'
    file_num = 1
    tic = time.time()
    # user_input = raw_input("Masukkan Lokasi File: ")
    user_input = os.path.join(input_dir, '%06d.apk' % file_num)
    assert os.path.exists(
        user_input), "file tidak ditemukan pada, " + str(user_input)
    print("File Ditemukan !!")
    a, d, dx = AnalyzeAPK(user_input)
    dx.create_xref()
    package_name = a.get_package()
    permissions = a.get_permissions()
    val = [
        "android.permission.READ_PHONE_STATE",
        "android.permission.RECEIVE_BOOT_COMPLETED",
        "android.permission.READ_SMS", "android.permission.WRITE_SMS",
        "android.permission.SEND_SMS", "android.permission.RECEIVE_SMS",
        "android.permission.CALL_PHONE",
        "android.permission.CHANGE_WIFI_STATE",
        "android.permission.RESTART_PACKAGES", "android.permission.GET_TASKS"
    ]
    # valApi = ['Landroid/content/Intent;->getAction()','Ldalvik/system/DexClassLoader;->loadClass','Landroid/telephony/TelephonyManager;->getDeviceId()','Landroid/telephony/TelephonyManager;->getLine1Number()','Landroid/telephony/TelephonyManager;->getNetworkOperator()','Landroid/telephony/TelephonyManager;->getSimSerialNumber()','Landroid/telephony/TelephonyManager;->getSimOperator()','Landroid/telephony/TelephonyManager;->getSubscriberId()','Landroid/telephony/SmsManager;->sendTextMessage','Landroid/location/LocationManager;->getLastKnownLocation']
    ps = []

    API_freq = dict()
    frequency(dx, API_freq)

    fs = open(
        os.path.join('./Documents/API-Kurang/coba', package_name + '.txt'),
        "w")
    #datas = str(sorted(API_freq.items(), key=lambda b:b[1], reverse=True))
    datas = str(sorted(API_freq.items(), key=lambda b: b[1], reverse=True))
    #print(sorted(API_freq.items(), key=lambda b:b[1], reverse=True))
    print(permissions)
    for i in range(0, len(val)):
        if (check(permissions, val[i])):
            ps.append(1)
        else:
            ps.append(0)

    if 'Landroid/content/Intent;->getAction()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Ldalvik/system/DexClassLoader;->loadClass' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getDeviceId()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getLine1Number()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getNetworkOperator()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getSimSerialNumber()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getSimOperator()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/TelephonyManager;->getSubscriberId()' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/telephony/SmsManager;->sendTextMessage' in datas:
        ps.append(1)
    else:
        ps.append(0)

    if 'Landroid/location/LocationManager;->getLastKnownLocation' in datas:
        ps.append(1)
    else:
        ps.append(0)

    ps.append(package_name)

    print(ps)

    # fs.write(datas)
    # #print(time.time()-tic)
    # fs.close()

    #print(sorted(API_freq.items(), key=lambda b:b[1], reverse=True))
    print(time.time() - tic)
    print("Done !!!")

    return ps
    file_num += 1
Esempio n. 16
0
from androguard.misc import AnalyzeAPK



a, d, dx = AnalyzeAPK('Virus0e69af88dcbb469e30f16609b10c926c.apk')

activity = a.get_activities()
service = a.get_services()
provider = a.get_providers()
receiver = a.get_receivers()
permission = a.get_permissions()



print(activity)
print(service)
print(provider)
print(receiver)
print(permission)


'''
['com.security.service.MainActivity']
[]
[]
['com.security.service.receiver.ActionReceiver', 'com.security.service.receiver.SmsReceiver', 'com.security.service.receiver.RebootReceiver']
['android.permission.RECEIVE_SMS', 'android.permission.SEND_SMS']
'''
Esempio n. 17
0
class AndroguardImp(BaseApkinfo):
    """Information about apk based on androguard analysis"""

    __slots__ = ("apk", "dalvikvmformat", "analysis")

    def __init__(self, apk_filepath: Union[str, PathLike]):
        super().__init__(apk_filepath, "androguard")

        if self.ret_type == "APK":
            # return the APK, list of DalvikVMFormat, and Analysis objects
            self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(
                apk_filepath)
        elif self.ret_type == "DEX":
            # return the sha256hash, DalvikVMFormat, and Analysis objects
            _, _, self.analysis = AnalyzeDex(apk_filepath)
        else:
            raise ValueError("Unsupported File type.")

    @property
    def permissions(self) -> List[str]:
        if self.ret_type == "APK":
            return self.apk.get_permissions()

        if self.ret_type == "DEX":
            return []

    @property
    def android_apis(self) -> Set[MethodObject]:
        apis = set()

        for external_cls in self.analysis.get_external_classes():
            for meth_analysis in external_cls.get_methods():
                if meth_analysis.is_android_api():
                    apis.add(meth_analysis)

        return {self._convert_to_method_object(api) for api in apis}

    @property
    def custom_methods(self) -> Set[MethodObject]:
        return {
            self._convert_to_method_object(meth_analysis)
            for meth_analysis in self.analysis.get_methods()
            if not meth_analysis.is_external()
        }

    @property
    def all_methods(self) -> Set[MethodObject]:
        return {
            self._convert_to_method_object(meth_analysis)
            for meth_analysis in self.analysis.get_methods()
        }

    @functools.lru_cache()
    def find_method(
        self,
        class_name: Optional[str] = ".*",
        method_name: Optional[str] = ".*",
        descriptor: Optional[str] = ".*",
    ) -> MethodObject:
        regex_class_name = re.escape(class_name)
        regex_method_name = f"^{re.escape(method_name)}$"
        regex_descriptor = re.escape(descriptor)

        method_result = self.analysis.find_methods(
            classname=regex_class_name,
            methodname=regex_method_name,
            descriptor=regex_descriptor,
        )

        result = next(method_result, None)
        return self._convert_to_method_object(result) if result else None

    @functools.lru_cache()
    def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
        method_analysis = method_object.cache
        return {
            self._convert_to_method_object(call)
            for _, call, _ in method_analysis.get_xref_from()
        }

    def lowerfunc(self, method_object: MethodObject) -> Set[MethodObject]:
        method_analysis = method_object.cache
        return {(self._convert_to_method_object(call), offset)
                for _, call, offset in method_analysis.get_xref_to()}

    def get_method_bytecode(self,
                            method_object: MethodObject) -> Set[MethodObject]:
        method_analysis = method_object.cache
        try:
            for (
                    _,
                    ins,
            ) in method_analysis.get_method().get_instructions_idx():
                bytecode_obj = None
                reg_list = []

                # count the number of the registers.
                length_operands = len(ins.get_operands())
                if length_operands == 0:
                    # No register, no parameter
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        None,
                        None,
                    )
                else:
                    index_of_parameter_starts = None
                    for i in range(length_operands - 1, -1, -1):
                        if not isinstance(ins.get_operands()[i][0], Operand):
                            index_of_parameter_starts = i
                            break

                    if index_of_parameter_starts is not None:
                        parameter = ins.get_operands(
                        )[index_of_parameter_starts]
                        parameter = (parameter[2]
                                     if len(parameter) == 3 else parameter[1])

                        for i in range(index_of_parameter_starts):
                            reg_list.append(
                                "v" + str(ins.get_operands()[i][1]), )
                    else:
                        parameter = None
                        for i in range(length_operands):
                            reg_list.append(
                                "v" + str(ins.get_operands()[i][1]), )

                    bytecode_obj = BytecodeObject(ins.get_name(), reg_list,
                                                  parameter)

                yield bytecode_obj
        except AttributeError:
            # TODO Log the rule here
            pass

    def get_strings(self) -> str:
        return {
            str(string_analysis.get_orig_value())
            for string_analysis in self.analysis.get_strings()
        }

    @functools.lru_cache()
    def _construct_bytecode_instruction(self, instruction):
        """
        Construct a list of strings from the given bytecode instructions.

        :param instruction: instruction instance from androguard
        :return: a list with bytecode instructions strings
        """
        instruction_list = [instruction.get_name()]
        reg_list = []

        # count the number of the registers.
        length_operands = len(instruction.get_operands())
        if length_operands == 0:
            # No register, no parameter
            return instruction_list

        elif length_operands == 1:
            # Only one register

            reg_list.append(
                f"v{instruction.get_operands()[length_operands - 1][1]}")

            instruction_list.extend(reg_list)

            return instruction_list
        elif length_operands >= 2:
            # the last one is parameter, the other are registers.

            parameter = instruction.get_operands()[length_operands - 1]
            for i in range(length_operands - 1):
                reg_list.append("v" + str(instruction.get_operands()[i][1]), )
            parameter = parameter[2] if len(parameter) == 3 else parameter[1]
            instruction_list.extend(reg_list)
            instruction_list.append(parameter)

            return instruction_list

    @functools.lru_cache()
    def get_wrapper_smali(
        self,
        parent_method: MethodObject,
        first_method: MethodObject,
        second_method: MethodObject,
    ) -> Dict[str, Union[BytecodeObject, str]]:
        method_analysis = parent_method.cache

        result = {
            "first": None,
            "first_hex": None,
            "second": None,
            "second_hex": None,
        }

        first_method_pattern = (
            f"{first_method.class_name}"
            f"->{first_method.name}{first_method.descriptor}")
        second_method_pattern = (
            f"{second_method.class_name}"
            f"->{second_method.name}{second_method.descriptor}")

        for _, ins in method_analysis.get_method().get_instructions_idx():
            if first_method_pattern in str(ins):
                result["first"] = self._construct_bytecode_instruction(ins)
                result["first_hex"] = ins.get_hex()
            if second_method_pattern in str(ins):
                result["second"] = self._construct_bytecode_instruction(ins)
                result["second_hex"] = ins.get_hex()

        return result

    @property
    def superclass_relationships(self) -> Dict[str, Set[str]]:
        hierarchy_dict = defaultdict(set)

        for _class in self.analysis.get_classes():
            hierarchy_dict[str(_class.name)].add(str(_class.extends))
            hierarchy_dict[str(_class.name)].union(
                str(implements) for implements in _class.implements)

        return hierarchy_dict

    @property
    def subclass_relationships(self) -> Dict[str, Set[str]]:
        hierarchy_dict = defaultdict(set)

        for _class in self.analysis.get_classes():
            class_name = str(_class.name)
            hierarchy_dict[str(_class.extends)].add(class_name)
            for implements in _class.implements:
                hierarchy_dict[str(implements)].add(class_name)

        return hierarchy_dict

    @staticmethod
    @functools.lru_cache
    def _convert_to_method_object(
        method_analysis: MethodAnalysis, ) -> MethodObject:
        return MethodObject(
            access_flags=method_analysis.access,
            class_name=str(method_analysis.class_name),
            name=str(method_analysis.name),
            descriptor=str(method_analysis.descriptor),
            cache=method_analysis,
        )
Esempio n. 18
0
def api_check(folder, APKname):
    if os.path.exists("result/" + folder + APKname + 'data/'):
        print(APKname + " Already scanned")
        return

    print("Starting apk:" + APKname)

    apk_start_time = time.time()

    RESULTdict = dict.fromkeys(RESULT_PARAMS, 0)

    ##отдельные словари для фич
    OtherDict = dict.fromkeys(('obfuscation', 'database'), 0)

    APIdict = dict.fromkeys((API_CALLS + API_ClASS), 0)

    permission_dict = dict.fromkeys(PERMISSIONS, 0)

    strings_dict = dict.fromkeys(API_SYSTEM_COMMANDS, 0)

    groupAPI_dict = dict.fromkeys(APIGROUPS, 0)
    ##№№№

    #a-APK d[0]-DalvikVMFormat dx-Analysis
    try:
        a, d, dx = AnalyzeAPK(folder + APKname)
    except:
        print(" ERROR: Androguard parse error, skipping file")
        return

###
    temp = a.get_details_permissions()
    temp2 = a.get_declared_permissions_details()
    temp3 = a.get_uses_implied_permission_list()

    # ########TODO почитать про использование пермишинсов без запросов

    ####

    RESULTdict["APP_Name"] = APKname
    RESULTdict['folder'] = folder
    #methods = []

    #подозрительные строки
    RESULTdict["warn_strings"] = []
    strings = dx.get_strings_analysis()
    #w=d[0].get_strings()
    list_system_commands = read_system_commands(strings, API_SYSTEM_COMMANDS)
    for i in list_system_commands:
        #print(i)
        RESULTdict["warn_strings"].append(i)

    for i in list_system_commands:
        strings_dict[i] += 1

    ### общая информация
    RESULTdict['permissions'] = a.get_permissions()
    RESULTdict['activities'] = a.get_activities()
    RESULTdict['providers'] = a.get_providers()
    RESULTdict['services'] = a.get_services()
    RESULTdict['libraries'] = a.get_libraries()
    RESULTdict['is_obfuscation'] = 1 if is_ascii_obfuscation(d[0]) else 0
    RESULTdict['is_database'] = 1 if d[0].get_regex_strings(DB_REGEX) else 0
    #TODO intents_analysis from new.py

    OtherDict['obfuscation'] = RESULTdict['is_obfuscation']
    OtherDict['database'] = RESULTdict['is_database']

    #permissions
    RESULTdict['warn_permissions'] = []

    #RESULTdict['feature_vectors']['permissions'] = []
    for permission in PERMISSIONS:

        if permission in RESULTdict['permissions']:
            RESULTdict['warn_permissions'].append(permission)
            permission_dict[permission] = 1

###########################################################################
#TODO подсчет групп АПИ и системных команд для вектора фич
###########################################################################

#API
    RESULTdict['API_groups'] = []
    external_classes = dx.get_external_classes()
    for i in external_classes:
        class_name = i.get_vm_class()
        methods_list = class_name.get_methods()
        for method in methods_list:
            a = '%s' % method.get_class_name().replace(';', '')
            b = '%s' % method.get_name()
            c = '%s' % method.get_descriptor()
            #TODO permission_api_name https://androguard.readthedocs.io/en/latest/api/androguard.core.analysis.html?highlight=permission#androguard.core.analysis.analysis.ExternalMethod.permission_api_name
            if b in API_CALLS:
                APIdict[b] += 1
                ###TODO !!!нужна нормализация данных
            if a in API_ClASS:
                APIdict[a] += 1

            temp = GroupAPI_Checker.checkAPIGroup(a.replace('/', '.')[1:], b)
            if (temp != None):
                groupAPI_dict[temp] += 1
                RESULTdict['API_groups'].append(temp)

##запись общих параметров
    with open("result/" + 'API_CALLS.csv', 'a', encoding='utf8') as csvfile:
        fieldnames = (('APP_Name', 'folder') + API_CALLS + API_ClASS)
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        tempDict = APIdict.copy()
        tempDict['APP_Name'] = APKname
        tempDict['folder'] = folder
        writer.writerow(tempDict)

    with open("result/" + 'OtherDict.csv', 'a', encoding='utf8') as csvfile:
        fieldnames = 'APP_Name', 'folder', 'obfuscation', 'database'
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        tempDict = OtherDict.copy()
        tempDict['APP_Name'] = APKname
        tempDict['folder'] = folder
        writer.writerow(tempDict)

    with open("result/" + 'permission_dict.csv', 'a',
              encoding='utf8') as csvfile:
        fieldnames = ('APP_Name', 'folder') + PERMISSIONS
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        tempDict = permission_dict.copy()
        tempDict['APP_Name'] = APKname
        tempDict['folder'] = folder
        writer.writerow(tempDict)

    with open("result/" + 'strings_dict.csv', 'a', encoding='utf8') as csvfile:
        fieldnames = ('APP_Name', 'folder') + API_SYSTEM_COMMANDS
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        tempDict = strings_dict.copy()
        tempDict['APP_Name'] = APKname
        tempDict['folder'] = folder
        writer.writerow(tempDict)

    with open("result/" + 'groupAPI_dict.csv', 'a',
              encoding='utf8') as csvfile:
        fieldnames = ('APP_Name', 'folder') + APIGROUPS
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        tempDict = groupAPI_dict.copy()
        tempDict['APP_Name'] = APKname
        tempDict['folder'] = folder
        writer.writerow(tempDict)

    with open("result/" + 'RESULTdict.csv', 'a', encoding='utf8') as csvfile:
        fieldnames = RESULT_PARAMS
        writer = csv.DictWriter(csvfile,
                                fieldnames=fieldnames,
                                delimiter=";",
                                lineterminator="\n")
        #writer.writeheader()
        writer.writerow(RESULTdict)


##запись параметров данного приложения
    try:
        if os.path.exists("result/" + folder):
            os.mkdir('result/' + folder + APKname + 'data')
        else:
            os.mkdir('result/' + folder)
            os.mkdir('result/' + folder + APKname + 'data')
    except OSError:
        print("Создать директорию %s не удалось" %
              ('result/' + folder + APKname + 'data'))
    else:
        with open("result/" + folder + APKname + 'data/RESULT.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = RESULT_PARAMS
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(RESULTdict)

        with open("result/" + folder + APKname + 'data/OtherDict.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = 'obfuscation', 'database'
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(OtherDict)

        with open("result/" + folder + APKname + 'data/APIdict.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = API_CALLS + API_ClASS
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(APIdict)

        with open("result/" + folder + APKname + 'data/permission_dict.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = PERMISSIONS
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(permission_dict)

        with open("result/" + folder + APKname + 'data/strings_dict.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = API_SYSTEM_COMMANDS
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(strings_dict)

        with open("result/" + folder + APKname + 'data/groupAPI_dict.csv',
                  'w',
                  encoding='utf8') as csvfile:
            fieldnames = APIGROUPS
            writer = csv.DictWriter(csvfile,
                                    fieldnames=fieldnames,
                                    delimiter=";",
                                    lineterminator="\n")
            writer.writeheader()
            writer.writerow(groupAPI_dict)

    print("APK done:{} ".format(time.time() - apk_start_time))
Esempio n. 19
0
class Apkinfo:
    """Information about apk based on androguard analysis"""

    __slots__ = [
        "ret_type",
        "apk",
        "dalvikvmformat",
        "analysis",
        "apk_filename",
        "apk_filepath",
    ]

    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        self.ret_type = androconf.is_android(apk_filepath)

        if self.ret_type == "APK":
            # return the APK, list of DalvikVMFormat, and Analysis objects
            self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(apk_filepath)

        if self.ret_type == "DEX":
            # return the sha256hash, DalvikVMFormat, and Analysis objects
            _, _, self.analysis = AnalyzeDex(apk_filepath)

        self.apk_filename = os.path.basename(apk_filepath)
        self.apk_filepath = apk_filepath

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def filename(self):
        """
        Return the filename of apk.

        :return: a string of apk filename
        """
        return os.path.basename(self.apk_filepath)

    @property
    def filesize(self):
        """
        Return the file size of apk file by bytes.

        :return: a number of size bytes
        """
        return os.path.getsize(self.apk_filepath)

    @property
    def md5(self):
        """
        Return the md5 checksum of the apk file.

        :return: a string of md5 checksum of the apk file
        """
        md5 = hashlib.md5()
        with open(self.apk_filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5.update(chunk)
        return md5.hexdigest()

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        if self.ret_type == "APK":
            return self.apk.get_permissions()

        if self.ret_type == "DEX":
            return []

    @functools.lru_cache()
    def find_method(self, class_name=".*", method_name=".*", descriptor=".*"):
        """
        Find method from given class_name, method_name and the descriptor.
        default is find all method.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :param descriptor: the descriptor of the Android API
        :return: a generator of MethodClassAnalysis
        """

        regex_class_name = re.escape(class_name)
        regex_method_name = f"^{re.escape(method_name)}$"
        regex_descriptor = re.escape(descriptor)

        method_result = self.analysis.find_methods(
            classname=regex_class_name,
            methodname=regex_method_name,
            descriptor=regex_descriptor,
        )
        if list(method_result):
            (result,) = list(
                self.analysis.find_methods(
                    classname=regex_class_name,
                    methodname=regex_method_name,
                    descriptor=regex_descriptor,
                )
            )

            return result
        else:
            return None

    @functools.lru_cache()
    def upperfunc(self, method_analysis):
        """
        Return the xref from method from given method analysis instance.

        :param method_analysis: the method analysis in androguard
        :return: a set of all xref from functions
        """
        upperfunc_result = set()

        for _, call, _ in method_analysis.get_xref_from():
            # Call is the MethodAnalysis in the androguard
            # call.class_name, call.name, call.descriptor
            upperfunc_result.add(call)

        return upperfunc_result

    def get_method_bytecode(self, method_analysis):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param method_analysis: the method analysis in androguard
        :return: a generator of all bytecode instructions
        """

        try:
            for _, ins in method_analysis.get_method().get_instructions_idx():
                bytecode_obj = None
                reg_list = []

                # count the number of the registers.
                length_operands = len(ins.get_operands())
                if length_operands == 0:
                    # No register, no parameter
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        None,
                        None,
                    )
                elif length_operands == 1:
                    # Only one register

                    reg_list.append(
                        f"v{ins.get_operands()[length_operands - 1][1]}",
                    )
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        None,
                    )
                elif length_operands >= 2:
                    # the last one is parameter, the other are registers.

                    parameter = ins.get_operands()[length_operands - 1]
                    for i in range(0, length_operands - 1):
                        reg_list.append(
                            "v" + str(ins.get_operands()[i][1]),
                        )
                    if len(parameter) == 3:
                        # method or value
                        parameter = parameter[2]
                    else:
                        # Operand.OFFSET
                        parameter = parameter[1]

                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        parameter,
                    )

                yield bytecode_obj
        except AttributeError as error:
            # TODO Log the rule here
            pass

    def get_strings(self):

        all_strings = set()

        for string_analysis in self.analysis.get_strings():
            all_strings.add(str(string_analysis.get_orig_value()))

        return all_strings

    @functools.lru_cache()
    def construct_bytecode_instruction(self, instruction):
        """
        Construct a list of strings from the given bytecode instructions.

        :param instruction: instruction instance from androguard
        :return: a list with bytecode instructions strings
        """
        instruction_list = [instruction.get_name()]
        reg_list = []

        # count the number of the registers.
        length_operands = len(instruction.get_operands())
        if length_operands == 0:
            # No register, no parameter
            return instruction_list

        elif length_operands == 1:
            # Only one register

            reg_list.append(f"v{instruction.get_operands()[length_operands - 1][1]}")

            instruction_list.extend(reg_list)

            return instruction_list
        elif length_operands >= 2:
            # the last one is parameter, the other are registers.

            parameter = instruction.get_operands()[length_operands - 1]
            for i in range(0, length_operands - 1):
                reg_list.append(
                    "v" + str(instruction.get_operands()[i][1]),
                )
            if len(parameter) == 3:
                # method or value
                parameter = parameter[2]
            else:
                # Operand.OFFSET
                parameter = parameter[1]

            instruction_list.extend(reg_list)
            instruction_list.append(parameter)

            return instruction_list

    @functools.lru_cache()
    def get_wrapper_smali(self, method_analysis, first_method, second_method):
        """
        Return the dict of two method smali code from given method analysis object, only for self-defined
        method.
        :param method_analysis:
        :return:

        {
        "first": "invoke-virtual v5, Lcom/google/progress/Locate;->getLocation()Ljava/lang/String;",
        "second": "invoke-virtual v3, v0, v4, Lcom/google/progress/SMSHelper;->sendSms(Ljava/lang/String; Ljava/lang/String;)I"
        }
        """

        result = {"first": None, "first_hex": None, "second": None, "second_hex": None}

        first_method_pattern = f"{first_method.class_name}->{first_method.name}{first_method.descriptor}"
        second_method_pattern = f"{second_method.class_name}->{second_method.name}{second_method.descriptor}"

        for _, ins in method_analysis.get_method().get_instructions_idx():
            if first_method_pattern in str(ins):
                result["first"] = self.construct_bytecode_instruction(ins)
                result["first_hex"] = ins.get_hex()
            if second_method_pattern in str(ins):
                result["second"] = self.construct_bytecode_instruction(ins)
                result["second_hex"] = ins.get_hex()

        return result
Esempio n. 20
0
def get_permissions(apk_file: AnalyzeAPK) -> List[str]:
    return apk_file.get_permissions()
Esempio n. 21
0
    for name in obj:
            for action,intent_name in a.get_intent_filters(itemtype, name).items():
                        for intent in intent_name:
                                alista.append(intent)
    return alista



i = 0
while i < 1200:
    file =  (data.iloc[i][0])
    numero = (data.iloc[i][1])
    try:
        a, d, dx = AnalyzeAPK(file)
        print ("===> "+ file + " <===")
        perms =  (a.get_permissions())
        prov = (a.get_providers())
        serv = (a.get_services())
        sint = helper(serv,'service')
        receivers = a.get_receivers()
        r = []
        for x in receivers: r.append(x) 
        rint = helper(receivers,'receiver')
        writer.writerow((numero,file,perms,prov,serv,sint,r,rint))
        csv_base.flush()
    except zipfile.BadZipFile: # WiNDOWS FILE
        print ('THEY TRY 2 GET ME' + str(numero) )
    except KeyError: # DIC ERROR
            print('F**K ====>' + str(numero))
    except TypeError:
            print ('Really ====>' + str(numero))
Esempio n. 22
0
class Apkinfo:

    def __init__(self, apk_filepath):
        self.a, self.d, self.dx = AnalyzeAPK(apk_filepath)

        # Create Class, Method, String and Field
        # crossreferences for all classes in the Analysis.
        # self.dx.create_xref()

    @property
    def permissions(self):
        """
        :returns: A list of permissions
        :rtype: list
        """
        return self.a.get_permissions()

    def find_method(self, class_name=".*", method_name=".*"):
        """
        Find method from given class_name and method_name,
        default is find all.

        :returns: an generator of MethodClassAnalysis
        :rtype: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if len(list(result)) > 0:
            return self.dx.find_methods(class_name, method_name)

        else:
            # Method Not Found
            return None

    def upperfunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.
        :param class_name:
        :param method_name:
        :return: list
        """

        result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for md in method_set:
                for _, call, _ in md.get_xref_from():
                    # Get class name and method name:
                    # call.class_name, call.name
                    result.append((call.class_name, call.name))

            return tools.remove_dup_list(result)
        else:
            return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.
        :param class_name:
        :param method_name:
        :return: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if len(list(result)) > 0:
            for m in self.dx.find_methods(class_name, method_name):
                for idx, ins in m.get_method().get_instructions_idx():
                    bytecode_obj = None
                    reg_list = []

                    # count the number of the registers.
                    length_operands = len(ins.get_operands())
                    if length_operands == 0:
                        # No register, no parm
                        bytecode_obj = BytecodeObject(ins.get_name(), None, None)
                    elif length_operands == 1:
                        # Only one register

                        reg_list.append(
                            "v" + str(ins.get_operands()[length_operands - 1][1])
                        )
                        bytecode_obj = BytecodeObject(ins.get_name(), reg_list, None, )
                    elif length_operands >= 2:
                        # the last one is parm, the other are registers.

                        parameter = ins.get_operands()[length_operands - 1]
                        for i in range(0, length_operands - 1):
                            reg_list.append("v" + str(ins.get_operands()[i][1]))
                        if len(parameter) == 3:
                            # method or value
                            parameter = parameter[2]
                        else:
                            # Operand.OFFSET
                            parameter = parameter[1]

                        bytecode_obj = BytecodeObject(
                            ins.get_name(), reg_list, parameter,
                        )

                    yield bytecode_obj
        else:
            return None
Esempio n. 23
0
class Apkinfo:
    """Information about apk based on androguard analysis"""

    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        # return the APK, list of DalvikVMFormat, and Analysis objects
        self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(apk_filepath)
        self.apk_filename = os.path.basename(apk_filepath)

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        return self.apk.get_permissions()

    def find_method(self, class_name=".*", method_name=".*"):
        """
        Find method from given class_name and method_name,
        default is find all method.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of MethodClassAnalysis
        """

        result = self.analysis.find_methods(class_name, method_name)

        if list(result):
            return self.analysis.find_methods(class_name, method_name)

        return None

    def upperfunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a list of all upper functions
        """

        upperfunc_result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for method in method_set:
                for _, call, _ in method.get_xref_from():
                    # Get class name and method name:
                    # call.class_name, call.name
                    upperfunc_result.append((call.class_name, call.name))

            return tools.remove_dup_list(upperfunc_result)

        return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of all bytecode instructions
        """

        result = self.analysis.find_methods(class_name, method_name)

        if list(result):
            for method in self.analysis.find_methods(class_name, method_name):
                for _, ins in method.get_method().get_instructions_idx():
                    bytecode_obj = None
                    reg_list = []

                    # count the number of the registers.
                    length_operands = len(ins.get_operands())
                    if length_operands == 0:
                        # No register, no parameter
                        bytecode_obj = BytecodeObject(
                            ins.get_name(), None, None,
                        )
                    elif length_operands == 1:
                        # Only one register

                        reg_list.append(
                            f"v{ins.get_operands()[length_operands - 1][1]}",
                        )
                        bytecode_obj = BytecodeObject(
                            ins.get_name(), reg_list, None,
                        )
                    elif length_operands >= 2:
                        # the last one is parameter, the other are registers.

                        parameter = ins.get_operands()[length_operands - 1]
                        for i in range(0, length_operands - 1):
                            reg_list.append(
                                "v" + str(ins.get_operands()[i][1]),
                            )
                        if len(parameter) == 3:
                            # method or value
                            parameter = parameter[2]
                        else:
                            # Operand.OFFSET
                            parameter = parameter[1]

                        bytecode_obj = BytecodeObject(
                            ins.get_name(), reg_list, parameter,
                        )

                    yield bytecode_obj
Esempio n. 24
0
class Apkinfo:
    """Information about apk based on androguard analysis"""

    __slots__ = [
        "ret_type", "apk", "dalvikvmformat", "analysis", "apk_filename",
        "apk_filepath"
    ]

    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        self.ret_type = androconf.is_android(apk_filepath)

        if self.ret_type == "APK":
            # return the APK, list of DalvikVMFormat, and Analysis objects
            self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(
                apk_filepath)

        if self.ret_type == "DEX":
            # return the sha256hash, DalvikVMFormat, and Analysis objects
            _, _, self.analysis = AnalyzeDex(apk_filepath)

        self.apk_filename = os.path.basename(apk_filepath)
        self.apk_filepath = apk_filepath

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def filename(self):
        """
        Return the filename of apk.

        :return: a string of apk filename
        """
        return os.path.basename(self.apk_filepath)

    @property
    def filesize(self):
        """
        Return the file size of apk file by bytes.

        :return: a number of size bytes
        """
        return os.path.getsize(self.apk_filepath)

    @property
    def md5(self):
        """
        Return the md5 checksum of the apk file.

        :return: a string of md5 checksum of the apk file
        """
        md5 = hashlib.md5()
        with open(self.apk_filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5.update(chunk)
        return md5.hexdigest()

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        if self.ret_type == "APK":
            return self.apk.get_permissions()

        if self.ret_type == "DEX":
            return []

    @functools.lru_cache()
    def find_method(self, class_name=".*", method_name=".*", descriptor=".*"):
        """
        Find method from given class_name, method_name and the descriptor.
        default is find all method.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :param descriptor: the descriptor of the Android API
        :return: a generator of MethodClassAnalysis
        """

        regex_class_name = re.escape(class_name)
        regex_method_name = f"^{re.escape(method_name)}$"
        regex_descriptor = re.escape(descriptor)

        method_result = self.analysis.find_methods(
            classname=regex_class_name,
            methodname=regex_method_name,
            descriptor=regex_descriptor)
        if list(method_result):
            result, = list(
                self.analysis.find_methods(classname=regex_class_name,
                                           methodname=regex_method_name,
                                           descriptor=regex_descriptor))

            return result
        else:
            return None

    @functools.lru_cache()
    def upperfunc(self, method_analysis):
        """
        Return the xref from method from given method analysis instance.

        :param method_analysis: the method analysis in androguard
        :return: a set of all xref from functions
        """
        upperfunc_result = set()

        for _, call, _ in method_analysis.get_xref_from():
            # Call is the MethodAnalysis in the androguard
            # call.class_name, call.name, call.descriptor
            upperfunc_result.add(call)

        return upperfunc_result

    def get_method_bytecode(self, method_analysis):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param method_analysis: the method analysis in androguard
        :return: a generator of all bytecode instructions
        """

        try:
            for _, ins in method_analysis.get_method().get_instructions_idx():
                bytecode_obj = None
                reg_list = []

                # count the number of the registers.
                length_operands = len(ins.get_operands())
                if length_operands == 0:
                    # No register, no parameter
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        None,
                        None,
                    )
                elif length_operands == 1:
                    # Only one register

                    reg_list.append(
                        f"v{ins.get_operands()[length_operands - 1][1]}", )
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        None,
                    )
                elif length_operands >= 2:
                    # the last one is parameter, the other are registers.

                    parameter = ins.get_operands()[length_operands - 1]
                    for i in range(0, length_operands - 1):
                        reg_list.append("v" + str(ins.get_operands()[i][1]), )
                    if len(parameter) == 3:
                        # method or value
                        parameter = parameter[2]
                    else:
                        # Operand.OFFSET
                        parameter = parameter[1]

                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        parameter,
                    )

                yield bytecode_obj
        except AttributeError as error:
            # TODO Log the rule here
            pass