add Lancelot backend

This commit is contained in:
Willi Ballenthin
2024-09-27 13:01:41 +00:00
parent 9c90f0e554
commit 826377530d
5 changed files with 70 additions and 1 deletions

View File

@@ -79,6 +79,7 @@ BACKEND_VMRAY = "vmray"
BACKEND_FREEZE = "freeze"
BACKEND_BINEXPORT2 = "binexport2"
BACKEND_IDA = "ida"
BACKEND_LANCELOT = "lancelot"
class CorruptFile(ValueError):
@@ -351,6 +352,18 @@ def get_extractor(
return capa.features.extractors.ida.extractor.IdaFeatureExtractor()
elif backend == BACKEND_LANCELOT:
import lancelot
import capa.features.extractors.binexport2
import capa.features.extractors.binexport2.extractor
buf = input_path.read_bytes()
be2_buf: bytes = lancelot.binexport2_from_bytes(buf)
be2 = capa.features.extractors.binexport2.get_binexport2_from_bytes(be2_buf)
return capa.features.extractors.binexport2.extractor.BinExport2FeatureExtractor(be2, buf)
else:
raise ValueError("unexpected backend: " + backend)

View File

@@ -57,6 +57,7 @@ from capa.loader import (
BACKEND_FREEZE,
BACKEND_PEFILE,
BACKEND_DRAKVUF,
BACKEND_LANCELOT,
BACKEND_BINEXPORT2,
)
from capa.helpers import (
@@ -298,6 +299,7 @@ def install_common_args(parser, wanted=None):
(BACKEND_BINJA, "Binary Ninja"),
(BACKEND_DOTNET, ".NET"),
(BACKEND_BINEXPORT2, "BinExport2"),
(BACKEND_LANCELOT, "Lancelot"),
(BACKEND_FREEZE, "capa freeze"),
(BACKEND_CAPE, "CAPE"),
(BACKEND_DRAKVUF, "DRAKVUF"),

View File

@@ -36,7 +36,7 @@ import capa.main
logger = logging.getLogger("capa.compare-backends")
BACKENDS = ("vivisect", "ida", "binja")
BACKENDS = ("vivisect", "ida", "binja", "lancelot")
@dataclass
@@ -113,6 +113,9 @@ def collect(args):
file.unlink()
doc = json.loads(results_path.read_text(encoding="utf-8"))
for backend in BACKENDS:
if backend not in doc:
doc[backend] = {}
plan = []
for file in sorted(p for p in testfiles.glob("*")):
@@ -228,6 +231,7 @@ def report(args):
t.add_column("viv")
t.add_column("ida")
t.add_column("bn")
t.add_column("lan")
t.add_column("rule")
for rule, _ in seen_rules.most_common():
@@ -235,6 +239,7 @@ def report(args):
"x" if rule in rules_by_backend["vivisect"] else " ",
"x" if rule in rules_by_backend["ida"] else " ",
"x" if rule in rules_by_backend["binja"] else " ",
"x" if rule in rules_by_backend["lancelot"] else " ",
rule,
)

View File

@@ -134,6 +134,23 @@ def fixup_viv(path: Path, extractor):
extractor.vw.makeFunction(0x404970)
@lru_cache
def get_lancelot_extractor(path: Path):
import lancelot
import capa.features.extractors.binexport2
import capa.features.extractors.binexport2.extractor
buf = path.read_bytes()
be2_buf: bytes = lancelot.binexport2_from_bytes(buf)
be2 = capa.features.extractors.binexport2.get_binexport2_from_bytes(be2_buf)
extractor = capa.features.extractors.binexport2.extractor.BinExport2FeatureExtractor(be2, buf)
setattr(extractor, "path", path.as_posix())
return extractor
@lru_cache(maxsize=1)
def get_pefile_extractor(path: Path):
import capa.features.extractors.pefile

View File

@@ -0,0 +1,32 @@
# Copyright (C) 2024 Mandiant, Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at: [package root]/LICENSE.txt
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.
import pytest
import fixtures
@fixtures.parametrize(
"sample,scope,feature,expected",
fixtures.FEATURE_PRESENCE_TESTS + fixtures.FEATURE_SYMTAB_FUNC_TESTS,
indirect=["sample", "scope"],
)
def test_lancelot_features(sample, scope, feature, expected):
if ".elf" in sample.name:
pytest.xfail("lancelot doesn't handle ELF files")
fixtures.do_test_feature_presence(fixtures.get_lancelot_extractor, sample, scope, feature, expected)
@fixtures.parametrize(
"sample,scope,feature,expected",
fixtures.FEATURE_COUNT_TESTS,
indirect=["sample", "scope"],
)
def test_lancelot_feature_counts(sample, scope, feature, expected):
if ".elf" in sample.name:
pytest.xfail("lancelot doesn't handle ELF files")
fixtures.do_test_feature_count(fixtures.get_lancelot_extractor, sample, scope, feature, expected)