def calculate(self): # Level 1 threshold level_one_threshold = self.score_sum / 2**4 # Level 2 threshold level_two_threshold = self.score_sum / 2**3 # Level 3 threshold level_three_threshold = self.score_sum / 2**2 # Level 4 threshold level_four_threshold = self.score_sum / 2**1 # Level 5 threshold level_five_threshold = self.score_sum / 2**0 total_weight = self.weight_sum if 0 <= total_weight <= level_one_threshold: return green(LEVEL_INFO.LOW.value) elif level_one_threshold < total_weight <= level_two_threshold: return green(LEVEL_INFO.LOW.value) elif level_two_threshold < total_weight <= level_three_threshold: return yellow(LEVEL_INFO.Moderate.value) elif level_three_threshold < total_weight <= level_four_threshold: return yellow(LEVEL_INFO.Moderate.value) elif level_four_threshold < total_weight <= level_five_threshold: return red(LEVEL_INFO.High.value) else: raise ValueError("Weight calculate failed")
def show_label_report(self, rule_path, all_labels, table_version): """ Show the report based on label, last column represents max confidence for that label :param rule_path: the path where may be present the file label_desc.csv. :param all_labels: dictionary containing label:<array of confidence values associated to that label> :return: None """ label_desc = {} # clear table to manage max/detail version self.quark_analysis.label_report_table.clear() if os.path.isfile(os.path.join(rule_path, "label_desc.csv")): # associate to each label a description col_list = ["label", "description"] # csv file on form <label,description> # put this file in the folder of rules (it must not be a json file since it could create conflict with management of rules) df = pd.read_csv( os.path.join(rule_path, "label_desc.csv"), usecols=col_list ) label_desc = dict(zip(df["label"], df["description"])) for label_name in all_labels: confidences = np.array(all_labels[label_name]) if table_version == "max": self.quark_analysis.label_report_table.field_names = [ "Label", "Description", "Number of rules", "MAX Confidence %", ] self.quark_analysis.label_report_table.add_row( [ green(label_name), yellow(label_desc.get(label_name, "-")), (len(confidences)), red(np.max(confidences)), ] ) else: self.quark_analysis.label_report_table.field_names = [ "Label", "Description", "Number of rules", "MAX Confidence %", "AVG Confidence", "Std Deviation", "# of Rules with Confidence >= 80%", ] self.quark_analysis.label_report_table.add_row( [ green(label_name), yellow(label_desc.get(label_name, "-")), (len(confidences)), red(np.max(confidences)), magenta(round(np.mean(confidences), 2)), lightblue(round(np.std(confidences), 2)), lightyellow(np.count_nonzero(confidences >= 80)), ] )
def analyze_multi_file(self, path): if not os.path.isdir(path): tqdm.write(red(f"[*] Error: Given path is not a directory: {path}")) return file_count = sum(len(files) for _, _, files in os.walk(path)) progress_bar = tqdm(total=file_count) for root, dirs, files in os.walk(path): # Walk the directory for name in files: file_path = os.path.join(root, name) try: result = self.analyze_single_file(file_path) progress_bar.update(1) # Increment the progress bar # All API keys are unavailable if result == -1: return if not result: continue # Found positives file if result > 0: tqdm.write(green(f"[*] Found positives file: {file_path}")) except Exception as e: tqdm.write(yellow(f"[WARN] Exception found: {e.message}")) continue progress_bar.close() # Retrieve the file report from waiting queue tqdm.write(f"[*] Start to retrieve file report from waiting queue") for file_md5 in tqdm(self.waiting_queue): try: report = self.retreive_report(file_md5) if not report: tqdm.write(red(f"[*] ERROR: All API keys are unavailable")) return -1 if report["response_code"] == 1: self.reports[file_md5] = report["positives"] except Exception as e: tqdm.write(yellow(f"[WARN] Exception found: {e.message}")) continue
def check_progress(self): apk_status = self.db.get_progress_status(self.apk.id) if not apk_status: print(colors.yellow("wait for a second then check")) return False if apk_status == 1: print("{} as known as {} has done analysis!".format( colors.yellow(self.apk.name), self.apk.id)) return False elif apk_status == 4: print("{} as known as {} is failed parsing!".format( colors.yellow(self.apk.name), self.apk.id)) return False return True
def add_table_row(self, rule_obj, confidence, score, weight): self.quark_analysis.summary_report_table.add_row([ green(rule_obj.crime), yellow(confidence), score, red(weight), ])
def show_summary_report(self, rule_obj): """ Show the summary report. :param rule_obj: the instance of the RuleObject. :return: None """ # Count the confidence confidence = str(rule_obj.check_item.count(True) * 20) + "%" conf = rule_obj.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 print_warning(message): print(bold(yellow("[!]")) + f" WARNING: {message}")
def print_warning(message): print(bold(yellow("[!]")) + " WARNING: {0}".format(message))
def entry_point( summary, detail, apk, rule, output, graph, classification, threshold, list, permission, label, ): """Quark is an Obfuscation-Neglect Android Malware Scoring System""" # Load APK data = Quark(apk) # Load rules rules_list = [x for x in os.listdir(rule) if x.endswith("json")] if label: all_labels = {} # dictionary containing # key: label # value: list of confidence values # $ print(all_rules["accessibility service"]) # > [60, 40, 60, 40, 60, 40] for single_rule in tqdm(rules_list): rulepath = os.path.join(rule, single_rule) rule_checker = QuarkRule(rulepath) # Run the checker data.run(rule_checker) confidence = rule_checker.check_item.count(True) * 20 labels = rule_checker._label # array type, e.g. ['network', 'collection'] for single_label in labels: if single_label in all_labels: all_labels[single_label].append(confidence) else: all_labels[single_label] = [confidence] # get how many label with max confidence >= 80% counter_high_confidence = 0 for single_label in all_labels: if max(all_labels[single_label]) >= 80: counter_high_confidence += 1 print_info("Total Label found: " + yellow(str(len(all_labels)))) print_info("Rules with label which max confidence >= 80%: " + yellow(str(counter_high_confidence))) data.show_label_report(rule, all_labels, label) print(data.quark_analysis.label_report_table) # Show summary report if summary: if summary == "all_rules": label_flag = False elif summary.endswith("json"): rules_list = [summary] label_flag = False else: label_flag = True for single_rule in tqdm(rules_list): rulepath = os.path.join(rule, single_rule) rule_checker = QuarkRule(rulepath) labels = rule_checker._label if label_flag: if summary not in labels: continue # Run the checker data.run(rule_checker) data.show_summary_report(rule_checker, threshold) w = Weight(data.quark_analysis.score_sum, data.quark_analysis.weight_sum) print_warning(w.calculate()) print_info("Total Score: " + str(data.quark_analysis.score_sum)) print(data.quark_analysis.summary_report_table) if classification: data.show_rule_classification() if graph: data.show_call_graph() # Show detail report if detail: if detail == "all_rules": label_flag = False elif detail.endswith("json"): rules_list = [detail] label_flag = False else: label_flag = True for single_rule in tqdm(rules_list): rulepath = os.path.join(rule, single_rule) rule_checker = QuarkRule(rulepath) labels = rule_checker._label if label_flag: if detail not in labels: continue # Run the checker data.run(rule_checker) print("Rulepath: " + rulepath) print("Rule crime: " + rule_checker._crime) data.show_detail_report(rule_checker) print_success("OK") if classification: data.show_rule_classification() if graph: data.show_call_graph() # Show JSON report if output: for single_rule in tqdm(rules_list): rulepath = os.path.join(rule, single_rule) rule_checker = QuarkRule(rulepath) # Run the checker data.run(rule_checker) data.generate_json_report(rule_checker) json_report = data.get_json_report() with open(output, "w") as file: json.dump(json_report, file, indent=4) file.close() if list: if list == "all": for all_method in data.apkinfo.all_methods: print(all_method.full_name) if list == "native": for api in data.apkinfo.android_apis: print(api.full_name) if list == "custom": for custom_method in data.apkinfo.custom_methods: print(custom_method.full_name) if permission: for p in data.apkinfo.permissions: print(p)