Repository: mandiant/capa
File: scripts/show-unused-features.py (Python)

Code before:

            for insn in extractor.get_instructions(f, bb):
                for feature, _ in extractor.extract_insn_features(f, bb, insn):
                    if capa.features.common.is_global_feature(feature):
                        continue
                    feature_map.update([feature])
    return feature_map


def get_colored(s: str):
    if "(" in s and ")" in s:
        s_split = s.split("(", 1)
        s_color = colored(s_split[1][:-1], "cyan")
        return f"{s_split[0]}({s_color})"
    else:
        return colored(s, "cyan")


def print_unused_features(feature_map: typing.Counter[Feature], rules_feature_set: Set[Feature]):
    unused_features = []
    for feature, count in feature_map.items():
        if feature in rules_feature_set:
            continue
        unused_features.append((count, get_colored(str(feature))))
    unused_features = [
        (get_colored(str(count)), feature) for count, feature in sorted(unused_features, key=lambda x: x[0])
    ]
    print("\n")
    print(tabulate.tabulate(unused_features, headers=["Count", "Feature"], tablefmt="plain"))
    print("\n")


def main(argv=None):
    if argv is None:
        argv = sys.argv[1:]

    parser = argparse.ArgumentParser(description="Show the features that capa doesn't have rules for yet")
    capa.main.install_common_args(parser, wanted={"format", "os", "sample", "signatures", "backend", "rules"})

    parser.add_argument("-F", "--function", type=str, help="Show features for specific function")
    args = parser.parse_args(args=argv)
    capa.main.handle_common_args(args)

    if args.function and args.backend == "pefile":
        print("pefile backend does not support extracting function features")
        return -1

    try:
        taste = capa.helpers.get_file_taste(Path(args.sample))
    except IOError as e:
        logger.error("%s", str(e))

Review comment (suggestion):
```suggestion
        (str(count), feature) for count, feature in sorted(unused_features, key=lambda x: x[0])
```

Code after:

            for insn in extractor.get_instructions(f, bb):
                for feature, _ in extractor.extract_insn_features(f, bb, insn):
                    if capa.features.common.is_global_feature(feature):
                        continue
                    feature_map.update([feature])
    return feature_map


def get_colored(s: str):
    if "(" in s and ")" in s:
        s_split = s.split("(", 1)
        s_color = colored(s_split[1][:-1], "cyan")
        return f"{s_split[0]}({s_color})"
    else:
        return colored(s, "cyan")


def print_unused_features(feature_map: typing.Counter[Feature], rules_feature_set: Set[Feature]):
    unused_features = []
    for feature, count in reversed(feature_map.most_common()):
        if feature in rules_feature_set:
            continue
        unused_features.append((str(count), get_colored(str(feature))))
    print("\n")
    print(tabulate.tabulate(unused_features, headers=["Count", "Feature"], tablefmt="plain"))
    print("\n")


def main(argv=None):
    if argv is None:
        argv = sys.argv[1:]

    parser = argparse.ArgumentParser(description="Show the features that capa doesn't have rules for yet")
    capa.main.install_common_args(parser, wanted={"format", "os", "sample", "signatures", "backend", "rules"})

    parser.add_argument("-F", "--function", type=str, help="Show features for specific function")
    args = parser.parse_args(args=argv)
    capa.main.handle_common_args(args)

    if args.function and args.backend == "pefile":
        print("pefile backend does not support extracting function features")
        return -1

    try:
        taste = capa.helpers.get_file_taste(Path(args.sample))
    except IOError as e:
        logger.error("%s", str(e))
        return -1

    try: