mirror of
https://github.com/mandiant/capa.git
synced 2026-02-04 11:07:53 -08:00
Merge pull request #2501 from xusheng6/binja_database_support
Binja database support
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### New Features
|
||||
|
||||
- allow call as valid subscope for call scoped rules @mr-tz
|
||||
- support loading and analyzing a Binary Ninja database #2496 @xusheng6
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
@@ -466,6 +466,7 @@ FORMAT_VMRAY = "vmray"
|
||||
FORMAT_BINEXPORT2 = "binexport2"
|
||||
FORMAT_FREEZE = "freeze"
|
||||
FORMAT_RESULT = "result"
|
||||
FORMAT_BINJA_DB = "binja_database"
|
||||
STATIC_FORMATS = {
|
||||
FORMAT_SC32,
|
||||
FORMAT_SC64,
|
||||
@@ -475,6 +476,7 @@ STATIC_FORMATS = {
|
||||
FORMAT_FREEZE,
|
||||
FORMAT_RESULT,
|
||||
FORMAT_BINEXPORT2,
|
||||
FORMAT_BINJA_DB,
|
||||
}
|
||||
DYNAMIC_FORMATS = {
|
||||
FORMAT_CAPE,
|
||||
|
||||
@@ -18,6 +18,7 @@ from capa.features.common import (
|
||||
FORMAT_ELF,
|
||||
FORMAT_SC32,
|
||||
FORMAT_SC64,
|
||||
FORMAT_BINJA_DB,
|
||||
Format,
|
||||
String,
|
||||
Feature,
|
||||
@@ -137,6 +138,9 @@ def extract_file_function_names(bv: BinaryView) -> Iterator[tuple[Feature, Addre
|
||||
|
||||
|
||||
def extract_file_format(bv: BinaryView) -> Iterator[tuple[Feature, Address]]:
|
||||
if bv.file.database is not None:
|
||||
yield Format(FORMAT_BINJA_DB), NO_ADDRESS
|
||||
|
||||
view_type = bv.view_type
|
||||
if view_type in ["PE", "COFF"]:
|
||||
yield Format(FORMAT_PE), NO_ADDRESS
|
||||
|
||||
@@ -105,13 +105,13 @@ def find_binaryninja() -> Optional[Path]:
|
||||
logger.debug("detected OS: linux")
|
||||
elif sys.platform == "darwin":
|
||||
logger.warning("unsupported platform to find Binary Ninja: %s", sys.platform)
|
||||
return False
|
||||
return None
|
||||
elif sys.platform == "win32":
|
||||
logger.warning("unsupported platform to find Binary Ninja: %s", sys.platform)
|
||||
return False
|
||||
return None
|
||||
else:
|
||||
logger.warning("unsupported platform to find Binary Ninja: %s", sys.platform)
|
||||
return False
|
||||
return None
|
||||
|
||||
desktop_entry = get_desktop_entry("com.vector35.binaryninja.desktop")
|
||||
if not desktop_entry:
|
||||
|
||||
@@ -46,6 +46,7 @@ from capa.features.common import (
|
||||
FORMAT_FREEZE,
|
||||
FORMAT_DRAKVUF,
|
||||
FORMAT_UNKNOWN,
|
||||
FORMAT_BINJA_DB,
|
||||
FORMAT_BINEXPORT2,
|
||||
Format,
|
||||
)
|
||||
@@ -59,6 +60,7 @@ EXTENSIONS_DYNAMIC = ("json", "json_", "json.gz", "log", ".log.gz", ".zip")
|
||||
EXTENSIONS_BINEXPORT2 = ("BinExport", "BinExport2")
|
||||
EXTENSIONS_ELF = "elf_"
|
||||
EXTENSIONS_FREEZE = "frz"
|
||||
EXTENSIONS_BINJA_DB = "bndb"
|
||||
|
||||
logger = logging.getLogger("capa")
|
||||
|
||||
@@ -232,6 +234,8 @@ def get_format_from_extension(sample: Path) -> str:
|
||||
format_ = FORMAT_FREEZE
|
||||
elif sample.name.endswith(EXTENSIONS_BINEXPORT2):
|
||||
format_ = FORMAT_BINEXPORT2
|
||||
elif sample.name.endswith(EXTENSIONS_BINJA_DB):
|
||||
format_ = FORMAT_BINJA_DB
|
||||
return format_
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ from capa.features.common import (
|
||||
FORMAT_VMRAY,
|
||||
FORMAT_DOTNET,
|
||||
FORMAT_DRAKVUF,
|
||||
FORMAT_BINJA_DB,
|
||||
FORMAT_BINEXPORT2,
|
||||
)
|
||||
from capa.features.address import Address
|
||||
@@ -251,7 +252,7 @@ def get_extractor(
|
||||
|
||||
import capa.features.extractors.binja.extractor
|
||||
|
||||
if input_format not in (FORMAT_SC32, FORMAT_SC64):
|
||||
if input_format not in (FORMAT_SC32, FORMAT_SC64, FORMAT_BINJA_DB):
|
||||
if not is_supported_format(input_path):
|
||||
raise UnsupportedFormatError()
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ from capa.features.common import (
|
||||
FORMAT_DRAKVUF,
|
||||
STATIC_FORMATS,
|
||||
DYNAMIC_FORMATS,
|
||||
FORMAT_BINJA_DB,
|
||||
FORMAT_BINEXPORT2,
|
||||
)
|
||||
from capa.capabilities.common import find_capabilities, has_file_limitation, find_file_capabilities
|
||||
@@ -266,6 +267,7 @@ def install_common_args(parser, wanted=None):
|
||||
(FORMAT_VMRAY, "VMRay sandbox report"),
|
||||
(FORMAT_FREEZE, "features previously frozen by capa"),
|
||||
(FORMAT_BINEXPORT2, "BinExport2"),
|
||||
(FORMAT_BINJA_DB, "Binary Ninja Database"),
|
||||
]
|
||||
format_help = ", ".join([f"{f[0]}: {f[1]}" for f in formats])
|
||||
|
||||
|
||||
Submodule tests/data updated: 3f42b20ab5...b40457c616
@@ -332,6 +332,8 @@ def get_data_path_by_name(name) -> Path:
|
||||
return CD / "data" / "Practical Malware Analysis Lab 12-04.exe_"
|
||||
elif name == "pma16-01":
|
||||
return CD / "data" / "Practical Malware Analysis Lab 16-01.exe_"
|
||||
elif name == "pma16-01_binja_db":
|
||||
return CD / "data" / "Practical Malware Analysis Lab 16-01.exe_.bndb"
|
||||
elif name == "pma21-01":
|
||||
return CD / "data" / "Practical Malware Analysis Lab 21-01.exe_"
|
||||
elif name == "al-khaser x86":
|
||||
@@ -1387,6 +1389,43 @@ FEATURE_PRESENCE_TESTS_IDA = [
|
||||
("mimikatz", "file", capa.features.file.Import("cabinet.FCIAddFile"), True),
|
||||
]
|
||||
|
||||
FEATURE_BINJA_DATABASE_TESTS = sorted(
|
||||
[
|
||||
# insn/regex
|
||||
("pma16-01_binja_db", "function=0x4021B0", capa.features.common.Regex("HTTP/1.0"), True),
|
||||
(
|
||||
"pma16-01_binja_db",
|
||||
"function=0x402F40",
|
||||
capa.features.common.Regex("www.practicalmalwareanalysis.com"),
|
||||
True,
|
||||
),
|
||||
(
|
||||
"pma16-01_binja_db",
|
||||
"function=0x402F40",
|
||||
capa.features.common.Substring("practicalmalwareanalysis.com"),
|
||||
True,
|
||||
),
|
||||
("pma16-01_binja_db", "file", capa.features.file.FunctionName("__aulldiv"), True),
|
||||
# os & format & arch
|
||||
("pma16-01_binja_db", "file", OS(OS_WINDOWS), True),
|
||||
("pma16-01_binja_db", "file", OS(OS_LINUX), False),
|
||||
("pma16-01_binja_db", "function=0x404356", OS(OS_WINDOWS), True),
|
||||
("pma16-01_binja_db", "function=0x404356,bb=0x4043B9", OS(OS_WINDOWS), True),
|
||||
("pma16-01_binja_db", "file", Arch(ARCH_I386), True),
|
||||
("pma16-01_binja_db", "file", Arch(ARCH_AMD64), False),
|
||||
("pma16-01_binja_db", "function=0x404356", Arch(ARCH_I386), True),
|
||||
("pma16-01_binja_db", "function=0x404356,bb=0x4043B9", Arch(ARCH_I386), True),
|
||||
("pma16-01_binja_db", "file", Format(FORMAT_PE), True),
|
||||
("pma16-01_binja_db", "file", Format(FORMAT_ELF), False),
|
||||
# format is also a global feature
|
||||
("pma16-01_binja_db", "function=0x404356", Format(FORMAT_PE), True),
|
||||
],
|
||||
# order tests by (file, item)
|
||||
# so that our LRU cache is most effective.
|
||||
key=lambda t: (t[0], t[1]),
|
||||
)
|
||||
|
||||
|
||||
FEATURE_COUNT_TESTS = [
|
||||
("mimikatz", "function=0x40E5C2", capa.features.basicblock.BasicBlock(), 7),
|
||||
("mimikatz", "function=0x4702FD", capa.features.common.Characteristic("calls from"), 0),
|
||||
|
||||
@@ -36,7 +36,7 @@ except ImportError:
|
||||
@pytest.mark.skipif(binja_present is False, reason="Skip binja tests if the binaryninja Python API is not installed")
|
||||
@fixtures.parametrize(
|
||||
"sample,scope,feature,expected",
|
||||
fixtures.FEATURE_PRESENCE_TESTS + fixtures.FEATURE_SYMTAB_FUNC_TESTS,
|
||||
fixtures.FEATURE_PRESENCE_TESTS + fixtures.FEATURE_SYMTAB_FUNC_TESTS + fixtures.FEATURE_BINJA_DATABASE_TESTS,
|
||||
indirect=["sample", "scope"],
|
||||
)
|
||||
def test_binja_features(sample, scope, feature, expected):
|
||||
|
||||
Reference in New Issue
Block a user