Example #1
0
    def analysis(self, apk, rule, core_library="androguard"):
        """
        The main function of Quark-Engine analysis, the analysis is based on the provided APK file.

        :param core_library: the library to analysis binary
        :param apk: the APK file
        :param rule: the rule to be checked, it could be a directory or a single json rule
        :return: None
        """

        self.quark = Quark(apk, core_library)

        if os.path.isdir(rule):

            rules_list = os.listdir(rule)

            for single_rule in rules_list:
                if single_rule.endswith("json"):
                    rule_path = os.path.join(rule, single_rule)
                    rule_checker = RuleObject(rule_path)

                    # Run the checker
                    self.quark.run(rule_checker)

                    # Generate json report
                    self.quark.generate_json_report(rule_checker)

        elif os.path.isfile(rule):
            if rule.endswith("json"):
                rule = RuleObject(rule)
                # Run checker
                self.quark.run(rule)
                # Generate json report
                self.quark.generate_json_report(rule)
Example #2
0
def update_rule_buffer(rule_buffer_list, rule_path_list):
    for rule_path in rule_path_list:
        with open(rule_path, "r") as json_file:
            json_data = json.loads(json_file.read())
        if isinstance(json_data, list):
            for rule_data in json_data:
                rule_buffer_list.append(RuleObject(rule_path, rule_data))
        else:
            rule_buffer_list.append(RuleObject(rule_path, json_data))
Example #3
0
    def test_check_parameter_values_with_one_keyword_rule(
            self, simple_quark_obj, rule_with_one_keyword):
        rule_object = RuleObject(rule_with_one_keyword)

        with patch("quark.core.quark.Quark.check_parameter_values") as mock:
            simple_quark_obj.run(rule_object)
            mock.assert_called()
    def test_init_with_complete_rule(self, complete_rule):
        rule = RuleObject(complete_rule)

        assert all(rule.check_item) is False
        assert rule.crime == "Send Location via SMS"
        assert rule.permission == [
            "android.permission.SEND_SMS",
            "android.permission.ACCESS_COARSE_LOCATION",
            "android.permission.ACCESS_FINE_LOCATION",
        ]
        assert rule.api == [
            {
                "class": "Landroid/telephony/TelephonyManager",
                "method": "getCellLocation",
                "descriptor": "()Landroid/telephony/CellLocation;",
            },
            {
                "class":
                "Landroid/telephony/SmsManager",
                "method":
                "sendTextMessage",
                "descriptor":
                ("(Ljava/lang/String; Ljava/lang/String;"
                 " Ljava/lang/String; Landroid/app/PendingIntent;"
                 " Landroid/app/PendingIntent;)V"),
            },
        ]
        assert rule.score == 4
        assert rule.rule_filename == "sendLocation_SMS.json"
        assert rule.label == ["location", "collection"]
Example #5
0
def quark_obj(simple_quark_obj):
    data = simple_quark_obj
    # rule
    rules = "quark/rules"
    rules_list = os.listdir(rules)
    for single_rule in rules_list:
        if single_rule.endswith("json"):
            rulepath = os.path.join(rules, single_rule)
            rule_checker = RuleObject(rulepath)

            # Run the checker
            data.run(rule_checker)
            data.generate_json_report(rule_checker)

    yield data
def rule_obj(scope="function"):
    rule_json = """
    {
        "crime": "Send Location via SMS",
        "permission": [
            "android.permission.SEND_SMS",
            "android.permission.ACCESS_COARSE_LOCATION",
            "android.permission.ACCESS_FINE_LOCATION"
        ],
        "api": [
            {
                "class": "Landroid/telephony/TelephonyManager",
                "method": "getCellLocation",
                "descriptor": "(I Ljava/lang/String; [B J)V"
            },
            {
                "class": "Landroid/telephony/SmsManager",
                "method": "sendTextMessage",
                "descriptor": "(ILjava/lang/String;[BJ)V"
            }
        ],
        "score": 4,
        "label": [
        "location",
        "collection"
    ]
    }
    """

    with open("sendLocation.json", "w") as f:
        f.write(rule_json)

    print("setup() begin")

    rule_obj = RuleObject("sendLocation.json")

    yield rule_obj

    del rule_obj
    os.remove("sendLocation.json")
Example #7
0
    def generate_rule(self, percentile_rank=0.2, web_editor=None):
        """
        Generate rules and export them to the output directory.

        :param percentile_rank: The percentile rank
                                for filter APIs by used count.
        :param web_editor: The path of the web editor html file.
        :return: None
        """
        # Rescursive search for apis in target method.
        lower_funcs = set(self.apkinfo.lowerfunc(self.method))
        self.method_recursive_search(lower_funcs)
        self.api_set, _ = filter_api_by_usage_count(
            self.apkinfo, self.api_set, percentile_rank=percentile_rank)

        first_apis_pool = list(self.api_set)
        second_apis_pool = list(self.api_set)

        # Setup progress bar.
        second_api_pool_num = len(second_apis_pool)
        outter_loop = tqdm(first_apis_pool)

        self.generated_result = list()

        # The number of rule file.
        rule_number = 1

        for api1 in first_apis_pool:
            outter_loop.update(1)

            for num, api2 in enumerate(second_apis_pool, start=1):
                inner_desc = f"{num}/{second_api_pool_num}"
                outter_loop.set_postfix(inner_loop=inner_desc, refresh=True)

                # Skip the case of same method.
                if api2.name == api1.name:
                    continue

                generated_rule = {
                    "crime":
                    "",
                    "permission": [],
                    "api": [
                        {
                            "class": api1.class_name,
                            "method": api1.name,
                            "descriptor": api1.descriptor,
                        },
                        {
                            "class": api2.class_name,
                            "method": api2.name,
                            "descriptor": api2.descriptor,
                        },
                    ],
                    "score":
                    1,
                    "label": [],
                }
                comb = RuleObject("test", json_data=generated_rule)

                try:
                    self.quark.run(comb)
                except KeyboardInterrupt:
                    raise
                except Exception as e:
                    tqdm.write(
                        "{} and {} combination has some error when analyzing,\
                        ERROR MESSAGE: {}".format(
                            api1,
                            api2,
                            e,
                        ), )
                    continue

                if comb.check_item[4]:
                    continue

                if web_editor:
                    generated_rule["number"] = rule_number
                    self.generated_result.append(generated_rule)
                    rule_number += 1

                else:
                    rule_name = f"{rule_number}.json"
                    rule_path = os.path.join(self.output_dir, rule_name)
                    with open(rule_path, "w") as rule_file:
                        json.dump(generated_rule, rule_file, indent=4)

                    rule_number += 1

        if web_editor:
            web_editor_data = {
                "apk_filename": self.quark.apkinfo.filename,
                "md5": self.quark.apkinfo.md5,
                "size_bytes": self.quark.apkinfo.filesize,
                "result": self.generated_result
            }

            editor_html = ReportGenerator(
                web_editor_data).get_rule_generate_editor_html()

            if ".html" not in web_editor:
                web_editor = f"{web_editor}.html"

            with open(web_editor, "w") as file:
                file.write(editor_html)
                file.close()

        # Clear progress bar
        outter_loop.clear()
        outter_loop.close()
        return
 def test_init_with_incomplete_rule(self, incomplete_rule):
     with pytest.raises(KeyError):
         _ = RuleObject(incomplete_rule)
 def test_init_with_invalid_file(self, invalid_file):
     with pytest.raises(BaseException):
         _ = RuleObject(invalid_file)
 def test_init_with_non_exist_file(self):
     with pytest.raises(FileNotFoundError):
         _ = RuleObject("NON_EXIST_FILE")
 def test_init_with_invalid_path(self):
     with pytest.raises(TypeError):
         _ = RuleObject(["Not", "a", "file"])