def output_parent_function_table(call_graph_analysis_list): dd = defaultdict(list) for item in call_graph_analysis_list: # print(item["parent"].class_name, item["parent"].name, item["crime"]) key = f"{item['parent'].class_name}{item['parent'].name}" dd[key].append(item["crime"]) # Pretty Table Output for parent, crimes in dd.items(): tb = PrettyTable() tb.field_names = ["Parent Function", f"{green(parent)}"] tb.align = "l" count = 1 for crime in crimes: if count == 1: tb.add_row(["Crime Description", red(f"{count}. {crime}")]) else: tb.add_row(["", red(f"{count}. {crime}")]) count += 1 print(tb)
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_single_file(self, path): if not os.path.isfile(path): tqdm.write(red(f"[*] Error: Given path is not a file: {path}")) return # Retreive file report tqdm.write(f"[*] Retrieved file scan report: {path}") file_md5 = self.get_file_md5(path) if file_md5 in self.reports: tqdm.write(green(f"[*] {file_md5} already retrieved report")) return self.reports[file_md5] report = self.retreive_report(file_md5) time.sleep(self.WAITING_TIME) 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"] return report["positives"] # Upload file to VT tqdm.write(f"[*] Upload file: {path}") with open(path, "rb") as f: scan_result = self.scan_file(os.path.basename(path), f) time.sleep(self.WAITING_TIME) if not scan_result: tqdm.write(red(f"[*] ERROR: All API keys are unavailable")) return -1 if scan_result["response_code"] == 0: tqdm.write(red(f"[*] ERROR: Failed to upload file: {path}")) return tqdm.write(f"[*] Retrieve file scan reports again") re_report = self.retreive_report(file_md5) time.sleep(self.WAITING_TIME) if not re_report: tqdm.write(red(f"[*] ERROR: All API keys are unavailable")) return -1 if re_report["response_code"] == 1: self.reports[file_md5] = report["positives"] return report["positives"] else: tqdm.write(f"[*] Unable to retrieve {file_md5}, add to waiting queue") self.waiting_queue.add(file_md5) return
def show_detail_report(self, rule_obj): """ Show the detail report. :param rule_obj: the instance of the RuleObject. :return: None """ # Count the confidence print("") print(f"Confidence: {rule_obj.check_item.count(True) * 20}%") print("") if rule_obj.check_item[0]: print(red(CHECK_LIST), end="") print(green(bold("1.Permission Request")), end="") print("") for permission in rule_obj.x1_permission: print(f"\t\t {permission}") if rule_obj.check_item[1]: print(red(CHECK_LIST), end="") print(green(bold("2.Native API Usage")), end="") print("") for api in self.quark_analysis.level_2_result: print(f"\t\t ({api.class_name}, {api.name})") if rule_obj.check_item[2]: print(red(CHECK_LIST), end="") print(green(bold("3.Native API Combination")), end="") print("") print( f"\t\t ({rule_obj.x2n3n4_comb[0]['class']}, {rule_obj.x2n3n4_comb[0]['method']})", ) print( f"\t\t ({rule_obj.x2n3n4_comb[1]['class']}, {rule_obj.x2n3n4_comb[1]['method']})", ) if rule_obj.check_item[3]: print(red(CHECK_LIST), end="") print(green(bold("4.Native API Sequence")), end="") print("") print(f"\t\t Sequence show up in:") for seq_method in self.quark_analysis.level_4_result: print(f"\t\t {seq_method.full_name}") if rule_obj.check_item[4]: print(red(CHECK_LIST), end="") print(green(bold("5.Native API Use Same Parameter")), end="") print("") for seq_operation in self.quark_analysis.level_5_result: print(f"\t\t {seq_operation.full_name}")
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 show_detail_report(self, rule_obj): """ Show the detail report. :param rule_obj: the instance of the RuleObject. :return: None """ # Count the confidence print("") print(f"Confidence: {rule_obj.check_item.count(True) * 20}%") print("") if rule_obj.check_item[0]: print(red(CHECK_LIST), end="") print(green(bold("1.Permission Request")), end="") print("") for permission in rule_obj.x1_permission: print("\t\t" + permission) if rule_obj.check_item[1]: print(red(CHECK_LIST), end="") print(green(bold("2.Native API Usage")), end="") print("") print("\t\t" + rule_obj.x2n3n4_comb[0]["method"]) if rule_obj.check_item[2]: print(red(CHECK_LIST), end="") print(green(bold("3.Native API Combination")), end="") print("") print("\t\t" + rule_obj.x2n3n4_comb[0]["method"]) print("\t\t" + rule_obj.x2n3n4_comb[1]["method"]) if rule_obj.check_item[3]: print(red(CHECK_LIST), end="") print(green(bold("4.Native API Sequence")), end="") print("") print("\t\t" + "Sequence show up in:") for seq_methon in self.same_sequence_show_up: print("\t\t" + repr(seq_methon)) if rule_obj.check_item[4]: print(red(CHECK_LIST), end="") print(green(bold("5.Native API Use Same Parameter")), end="") print("") for seq_operation in self.same_operation: print("\t\t" + repr(seq_operation))
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 yel(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 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 output_parent_function_table(rule_classification_data_bundle): dd = _convert_to_printable_dict(*rule_classification_data_bundle) # Pretty Table Output for parent, crimes in dd.items(): tb = PrettyTable() tb.field_names = [ "Parent Function", f"{green(parent)}", ] tb.align = "l" for count, crime in enumerate(set(crimes), start=1): if count == 1: tb.add_row(["Crime Description", red(f"* {crime}")]) else: tb.add_row(["", red(f"* {crime}")]) print(tb)
def change_api_key(self): tqdm.write(f"[*] {self.api_key} is unavailable, change another API key") self.api_keys_list[self.api_key] = False for api_key in self.api_keys_list: if self.api_keys_list[api_key]: self.api_key = api_key return True tqdm.write(red(f"[ERROR] There is no available api key")) return False
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 check_api_key_available(self): tqdm.write("[*] Check API keys available") for api_key in self.api_keys_list: try: params = { "apikey": api_key, "resource": "34efc3ebf51a6511c0d12cce7592db73", } res = requests.get(self.REPORT_URL, params) tqdm.write(f"API {api_key}: {res.status_code}") if res.status_code == 200: self.api_keys_list[api_key] = True elif res.status_code == 403: self.api_keys_list[api_key] = False elif res.status_code == 204: self.api_keys_list[api_key] = False elif res.status_code == 400: tqdm.write("Failed to check api key: Bad Request.") except Exception as e: tqdm.write(red(f"[ERROR] Failed to check api: {api_key}")) continue
def print_error(message): print(bold(red("[!]")) + f" ERROR: {message}")
def print_error(message): print(bold(red("[!]")) + " ERROR: {0}".format(message))