def import_annotation(binary: Binary, type_: FileType, path: Path) -> Annotation: """Imports functions from annotation file and creates Annotation object. Args: binary: The Binary to which to import functions. Returns: the Annotation, with newly created functions. """ if not path.is_file(): raise FileNotFoundError logger.info(f"Importing {type_.name} file from {path}") ann_cls, fnc_gen = FileTypeMapping[type_] binary.partition() annotation = ann_cls(binary=binary, path=str(path)) meta = fnc_gen(path) for name, addr, size, mode in meta: if not binary.range_is_valid(addr, addr + size): logger.debug( f"{name} @{addr:#08X}-{addr+size:#08X} not in valid range") continue if len(name) > 0 and binary.range_is_valid(addr, addr + size): fnc = Function.get(binary=binary, addr=addr) if not fnc: fnc = binary.functions.create(addr=addr, size=size, name=name, mode=mode) annotation.functions.add(fnc) binary.annotations.add(annotation) return annotation
def _cli_list( list_history: bool, list_targets: bool, ): def format_binary_list( binary_list: Iterable[Binary], is_annotated: Optional[bool] = False) -> Iterable[dict]: keys = ["id", "name", "filepath"] data = [] for binary in list(binaries): b_dict = binary.to_dict(only=keys) if is_annotated is True: b_dict["#annotations"] = binary.annotations.count() b_dict["#functions"] = binary.functions.count() data.append(b_dict) return data if list_history is True: typer.echo("History Files") binaries = Binary.select_annotated() formatted = format_binary_list(binaries, is_annotated=True) table = tabulate(formatted, headers="keys") typer.echo(table) if list_history is True and list_targets is True: typer.echo() # additional newline for readability if list_targets is True: typer.echo("Target Files") binaries = Binary.select_unannotated() formatted = format_binary_list(binaries, is_annotated=False) table = tabulate(formatted, headers="keys") typer.echo(table)
def _binary_ops(binary: str, comment: str, export_csv: str, remove: bool): b = Binary.get(name=binary) if comment is not None: b.comment = comment if export_csv is not None: export_csv_combined(b, export_csv) if remove is True: Binary.delete(b)
def find_starts(target: Binary, start_cut: int = 8) -> Iterable[Match]: match_finder = make_start_scout() itree = target.partition_without_matches() matches = [] for interval in itree: data = target.read()[interval.begin:interval.end] for addr, matcher in match_finder(data, interval.begin): match, new = Match.deduplicate(target, addr, matcher.cut_size, dict(certainty=1)) match.matched_by.add(matcher) if new: target.matches.add(match) matches.append(match) return matches
def prepare_graph(histories: List[Path], annotations: List[Path], min_size: int, max_rel_fuzz: float) -> Optional[Graph]: logger.debug("Importing history") for history, annotation in zip(histories, annotations): bin_ = get_or_create_binary(history) get_or_create_annotation(bin_, annotation) logger.debug(f"Imported history {bin_.serialize()}") if Binary.select_annotated().count() == 0: typer.echo("No history entries in database") return None if histories: logger.debug("Clearing matchers") Matcher.reset() logger.debug("Grouping function symbols") groups = Function.common_functions(min_size, 1) logger.debug("finished grouping") logger.debug("make matchers") matchers = create_matchers(groups, min_size, max_rel_fuzz) logger.debug(f"{len(matchers)} matchers generated") graph = makeGraph(matchers) logger.debug("finish making matchers") return graph
def match_matchers_against(target: Binary, graph=None, parallelize=True) -> Iterable[Match]: """match_candidates_against matches all candidates against the given Binary. Args: target: the target binary to match the candidates against """ settings = SettingsStorage.get_settings() parallelize = parallelize or settings.get("matcher_parallelization", False) if graph is None: graph = makeGraph() bin_ = target.read() partitions = target.partition() if parallelize: matches = parallel_prepartioned_graph_match(graph, bin_, partitions) else: matches = prepartioned_graph_match(graph, bin_, partitions) match_results = [] for matchers, size, end in matches: start = end - size match, new = Match.deduplicate(target, start, size, dict(certainty=1 / len(matchers))) for matcher in matchers: match.matched_by.add(matcher) if new: target.matches.add(match) match_results.append(match) orm.commit() if settings.get("find_fnc_starts", False): starts = find_starts(target, start_cut=settings.get("fnc_start_size", 8)) match_results.extend(starts) orm.commit() return match_results
def get_or_create_binary(path: Path, make_target=False) -> Binary: """import_binary creates a Binary and stores it in database Args: binary_path: the file path of the binary Returns: Binary """ logger.info(f"retrieving binary for path {path}") binary = Binary.get(filepath=str(path)) if not binary: if not path.is_file(): raise FileNotFoundError binary = Binary(filepath=str(path), name=path.name) elif make_target: binary.is_target = True binary.partition() return binary