Commit Graph
1012 Commits
Author SHA1 Message Date
Willi BallenthinandClaude Sonnet 4.6 2d008fb53e fix: add return after zero-offset yield in extract_insn_offset_features
`extract_insn_offset_features` in the x86/x64 BinExport2 extractor handled
zero-offset patterns (e.g. `mov [reg], reg`) in a nested branch but was
missing a `return` after yielding `Offset(0)` and `OperandOffset(0)`.
Execution then fell through to the general `mask_immediate` path, which read
`immediate` from the last-matched expression node (a register, not an
integer). Since that field defaults to 0, the function emitted duplicate
`Offset(0)` and `OperandOffset(0)` features for every such instruction.

Fix: add `return` after the two yields in the zero-pattern branch.

Tests: add `FEATURE_COUNT_TESTS_BE2_INTEL` covering `MOV [EDI], CX` at
0x401125 in mimikatz, asserting each of `Offset(0)` and `OperandOffset(1,0)`
is emitted exactly once.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 18:28:16 +03:00
Willi BallenthinandClaude Sonnet 4.6 81c22bb28c fix: correct scale/displacement in get_operand_phrase_info 5-expression branch
In the 5-expression branch of get_operand_phrase_info, two cases used
expression3 (the OPERATOR node) where expression4 (the IMMEDIATE_INT
value) was intended:

- Base + (Index * Scale): scale was expression3 ('*' operator), should be expression4 (the numeric scale value)
- (Index * Scale) + Displacement: displacement was expression3 ('+' operator), should be expression4 (the numeric displacement value)

Tests added using mimikatz.exe_.ghidra.BinExport:
- 0x40194d: MOVZX DI, [EAX + ECX * 1] — verifies scale=1 as IMMEDIATE_INT
- 0x401fd4: JMP [EAX * 4 + switchdataD_00402017] — verifies displacement=4202519 as IMMEDIATE_INT

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 18:19:19 +03:00
Willi BallenthinandClaude Sonnet 4.6 87b132011c fix: use HasField to check call-graph edge vertex indices
`_index_vertex_edges` used truthiness checks (`if not edge.source_vertex_index`)
to skip edges with absent fields, but this also silently drops any edge whose
source or target is vertex index 0 — a valid vertex. Both fields are protobuf
optional integers, so the correct absent-field check is `HasField()`, consistent
with `_index_flow_graph_edges` and `_index_call_graph_vertices` in the same file.

In mimikatz.exe_.ida.BinExport, vertex 0 at 0x401000 has 2 callees and 1 caller
that were all being silently discarded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 18:00:58 +03:00
Willi BallenthinandClaude Sonnet 4.6 243e6408b0 fix: close file handle in get_file_taste using a with statement
`get_file_taste` opened a file handle with `sample_path.open("rb").read(8)`,
discarding the file object without explicitly closing it. CPython reference-
counting closes it promptly in practice, but other implementations (PyPy,
Jython) and CPython under GC pressure may defer closure. Use a `with` statement
to guarantee the handle is released immediately after reading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 17:38:45 +03:00
Willi BallenthinandClaude Sonnet 4.6 47760269f8 fix: correct capa/subscope-rule key in RuleMetadata.from_capa
`RuleMetadata.from_capa` used `rule.meta.get("capa/subscope", False)` and
`Field(False, alias="capa/subscope")`, but the actual key set by
`_extract_subscope_rules_rec` is `"capa/subscope-rule"`. This caused
`is_subscope_rule` to always be `False` in every `RuleMetadata` instance,
making downstream filters in `render/utils.py`, `render/vverbose.py`, and
`scripts/import-to-ida.py` ineffective (though subscope rules are already
excluded from `ResultDocument` before reaching those callers).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 17:29:38 +03:00
Willi BallenthinandClaude Sonnet 4.6 099c9d41b7 fix: Scopes.from_dict uses cls instead of self
`Scopes.from_dict` was decorated with `@classmethod` but named its first
parameter `self` instead of `cls`, and hard-coded `Scopes(...)` in the
return statement instead of `cls(...)`. This meant any subclass calling
`SubScopes.from_dict(...)` would get a `Scopes` instance back rather than
a `SubScopes` instance.

Rename the parameter to `cls` and use it in the return statement so
that subclasses receive the correct type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 17:23:31 +03:00
Willi BallenthinandClaude Sonnet 4.6 70d2c13559 fix: add missing ELF branch in get_format_from_extension for .elf_ files
EXTENSIONS_ELF = "elf_" was defined but never used: get_format_from_extension
had branches for every other EXTENSIONS_* constant except ELF. Since .elf_
files are real test fixtures and a recognised input format, the fix is to add
the missing elif branch (and import FORMAT_ELF) rather than delete the
constant.

Closes #3031

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 17:11:39 +03:00
MoritzandGitHub 557f521713 tests: update expected Binary Ninja version to 5.3 (#3011) 2026-04-16 12:35:43 -06:00
Mike HunhoffandGitHub ed7e0cd77d lint: replace black/isort/flake8 with ruff (#2992)
* lint: replace isort/flake8 with ruff

* update ruff links

* remove stale isort reference

* update CHANGELOG

* address review

* remove unused imports

* remove unnecessary list comprehension

* remove quotes from type annotation

* use dict.get instead of if-else block

* remove unnecessary utf-8 encoding declaration

* Revert "remove unused imports"

This reverts commit 18ba50a22b.

* skip check for unused imports

* fix UP036 Version block is outdated for minimum Python version

* add TODO comment for unused imports

* replace black with ruff

* address review comments
2026-04-07 12:10:41 -06:00
Capa Bot 0b7a5f4b78 Sync capa-testfiles submodule 2026-04-03 15:12:39 +00:00
Mike HunhoffandGitHub a6ac839eea fix mypy formatting (#2973) 2026-03-27 10:54:28 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4ba1b5d233 build(deps): bump bump-my-version from 1.2.4 to 1.3.0 (#2963)
* build(deps): bump bump-my-version from 1.2.4 to 1.3.0

Bumps [bump-my-version](https://github.com/callowayproject/bump-my-version) from 1.2.4 to 1.3.0.
- [Release notes](https://github.com/callowayproject/bump-my-version/releases)
- [Changelog](https://github.com/callowayproject/bump-my-version/blob/master/CHANGELOG.md)
- [Commits](https://github.com/callowayproject/bump-my-version/compare/1.2.4...v1.3)

---
updated-dependencies:
- dependency-name: bump-my-version
  dependency-version: 1.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* style: auto-format with black and isort

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-26 15:30:46 -06:00
devs6186andWilli Ballenthin c930891c21 rules: address code review feedback for bytes prefix index
- remove bytes_rules from _RuleFeatureIndex; bytes_prefix_index is the
  only structure needed for candidate selection
- build bytes_prefix_index directly in _index_rules_by_feature() instead
  of building bytes_rules then converting, removing one full pass
- add if -1 in bytes_prefix_index guard to avoid temporary object
  creation for the short-pattern fallback (almost never taken)
- remove assert isinstance(feature.value, bytes) checks in _match();
  add Bytes.value: bytes class-level annotation so mypy narrows the
  type without the runtime check
- remove cache structure compatibility block from cache.py per reviewer
  request to handle in a separate PR
- update test assertions from bytes_rules to bytes_prefix_index
2026-03-20 21:37:04 +01:00
devs6186andWilli Ballenthin f572c01d10 rules: clarify bytes_prefix_index guard and add mixed-pattern test
- Change _match() guard from bytes_rules to bytes_prefix_index
  so the guard references the field actually used for candidate selection.
- Update stale comment to describe the prefix-bucket strategy.
- Clarify bytes_rules dataclass comment (retained for logging only).
- Add test_bytes_prefix_index_mixed_short_and_long_patterns covering
  rules with both short (<4B) and long (>=4B) patterns exercised together.
2026-03-20 21:37:04 +01:00
devs6186andWilli Ballenthin b868be55b8 rules: simplify bytes prefix indexing and add collision tests 2026-03-20 21:37:04 +01:00
devs6186andWilli Ballenthin ed256d2416 rules: index extracted bytes by length prefix for O(1) candidate selection
Instead of iterating all extracted Bytes features for every bytes-based rule,
build a prefix index keyed by fixed bucket sizes (4, 8, 16, 32, 64, 128, 256)
once per scope evaluation.  Each bytes pattern is looked up in the largest
bucket that fits its length, then only candidates sharing that prefix are
compared, replacing the previous O(n) linear scan with an O(1) hash lookup.
Patterns shorter than the minimum bucket still fall back to the full scan.
Adds a test to verify correctness for exact match, startswith match, mismatch,
and short-bytes cases.

Closes: https://github.com/mandiant/capa/issues/2128
2026-03-20 21:37:04 +01:00
HarshitandGitHub 01c5602bb1 tests: import capa.render.default in test_render (#2938)
* tests: import capa.render.default in test_render

Signed-off-by: blenbot <harshitiszz23@gmail.com>

* tests: import capa.render.default in test_render

Signed-off-by: blenbot <harshitiszz23@gmail.com>

---------

Signed-off-by: blenbot <harshitiszz23@gmail.com>
2026-03-20 13:52:48 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MoritzCapa Bot
7b23834d8e build(deps-dev): bump black from 25.12.0 to 26.3.0 (#2902)
* build(deps-dev): bump black from 25.12.0 to 26.3.0

Bumps [black](https://github.com/psf/black) from 25.12.0 to 26.3.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/25.12.0...26.3.0)

---
updated-dependencies:
- dependency-name: black
  dependency-version: 26.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* style: auto-format with black and isort

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Moritz <mr-tz@users.noreply.github.com>
Co-authored-by: Capa Bot <capa-dev@mandiant.com>
2026-03-13 15:46:13 +01:00
Devyansh SomvanshiandGitHub c03d833a84 rules: handle empty or invalid YAML documents in Rule.from_yaml (#2903)
* rules: handle empty or invalid YAML documents in Rule.from_yaml

Empty or whitespace-only .yml files caused a cryptic TypeError in
Rule.from_dict (NoneType not subscriptable) when yaml.load returned None.
This made lint.py abort with a stack trace instead of a clear message.

Add an early guard in Rule.from_yaml that raises InvalidRule with a
descriptive message when the parsed document is None or structurally
invalid.  get_rules() now logs a warning and skips such files so that
scripts/lint.py completes cleanly even when placeholder .yml files
exist in the rules/ or rules/nursery/ directories.

Fixes #2900.

* changelog: add entry for #2900 empty YAML handling

* rules: fix exception check and add get_rules skip test

- Use e.args[0] instead of str(e) to check the error message.
  InvalidRule.__str__ prepends "invalid rule: " so str(e) never
  matched the bare message, causing every InvalidRule to be re-raised.
- Add test_get_rules_skips_empty_yaml to cover the get_rules skip path,
  confirming that an empty file is warned-and-skipped while a valid
  sibling rule is still loaded.

* fix: correct isort import ordering in tests/test_rules.py

Move capa.engine import before capa.rules.cache to satisfy
isort --length-sort ordering.
2026-03-10 15:04:11 -06:00
Devyansh SomvanshiandGitHub 1f4a16cbcc loader: skip PE files with unrealistically large section virtual sizes (#2905)
* loader: skip PE files with unrealistically large section virtual sizes

Some malformed PE samples declare section virtual sizes orders of
magnitude larger than the file itself (e.g. a ~400 KB file with a
900 MB section).  vivisect attempts to map these regions, causing
unbounded CPU and memory consumption (see #1989).

Add _is_probably_corrupt_pe() which uses pefile (fast_load=True) to
check whether any section's Misc_VirtualSize exceeds
max(file_size * 128, 512 MB).  If the check fires, get_workspace()
raises CorruptFile before vivisect is invoked, keeping the existing
exception handling path consistent.

Thresholds are intentionally conservative to avoid false positives on
large but legitimate binaries.  When pefile is unavailable the helper
returns False and behaviour is unchanged.

Fixes #1989.

* changelog: add entry for #1989 corrupt PE large sections

* loader: apply Gemini review improvements

- Extend corrupt-PE check to FORMAT_AUTO so malformed PE files
  cannot bypass the guard when format is auto-detected (the helper
  returns False for non-PE files so there is no false-positive risk).
- Replace magic literals 128 and 512*1024*1024 with named constants
  _VSIZE_FILE_RATIO and _MAX_REASONABLE_VSIZE for clarity.
- Remove redundant int() cast around getattr(Misc_VirtualSize); keep
  the `or 0` guard for corrupt files where pefile may return None.
- Extend test to cover FORMAT_AUTO path alongside FORMAT_PE.

* tests: remove mock-only corrupt PE test per maintainer request

williballenthin noted the test doesn't add real value since it only
exercises the mock, not the actual heuristic. Removing it per feedback.

* fix: resolve flake8 NIC002 implicit string concat and add missing test

Fix the implicit string concatenation across multiple lines that caused
code_style CI to fail. Also add the test_corrupt_pe_with_unrealistic_section_size_short_circuits
test that was described in the PR body but not committed.
2026-03-10 15:03:35 -06:00
038c46da16 features: fix Regex.get_value_str() returning escaped pattern, breaking capa2yara #1909 (#2886)
Co-authored-by: Moritz <mr-tz@users.noreply.github.com>
2026-03-05 12:14:27 +01:00
Capa Bot 239bafd285 Sync capa-testfiles submodule 2026-02-17 21:10:09 +00:00
26aba8067f loader: handle SegmentationViolation for malformed ELF files (#2799)
Catch envi.exc.SegmentationViolation raised by vivisect when processing
malformed ELF files with invalid relocations and convert it to a
CorruptFile exception with a descriptive message.

Closes #2794

Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2026-02-05 12:24:48 -07:00
Daniel AdeboyeGitHubgemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>Mike Hunhoff
77440c03f5 vmray: extract number features for registry key handles (#2835)
* vmray: extract number features for whitelisted void_ptr parameters

* added changelog

* Apply suggestions from code review

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix lint

* fix lint

* fix test

* remove unused import

* Add hKey parameter extraction and tests

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2026-01-30 15:10:57 -07:00
Capa Bot 93c11d2d4e Sync capa-testfiles submodule 2026-01-28 16:22:42 +00:00
Daniel AdeboyeandGitHub 37f2a897ff tests: remove redundant test_ida_features.py (#2834) 2026-01-23 09:46:58 -07:00
Mike HunhoffandGitHub 5a5545aa14 ghidra: fix unit tests (#2812)
* ghidra: fix unit tests

* fix formatting
2026-01-15 12:34:43 -07:00
Willi Ballenthin 0686305f43 ida: loader: load resource sections to help discovery of embedded files 2026-01-13 16:15:31 +01:00
Willi Ballenthin 8d6b878e79 ida: fix return value from open_database 2026-01-13 16:15:31 +01:00
Willi Ballenthin 03cc901f7b tests: idalib: xfail resource test on 9.0 2026-01-13 16:15:31 +01:00
Willi Ballenthin 1d561bd038 tests: idalib: xfail two tests on 9.0 and 9.1 2026-01-13 16:15:31 +01:00
Willi Ballenthin 200c8037dd tests: fix logging message 2026-01-13 16:15:31 +01:00
mr-tzandWilli Ballenthin 87fb96d08b load resource for test sample 2026-01-13 16:15:31 +01:00
Willi Ballenthin 82be20be64 loader: idalib: disable lumina
see #2742 in which Lumina names overwrote names provided by debug info
2026-01-13 16:15:31 +01:00
Willi Ballenthin 132e64a991 tests: idalib: better detect missing idapro package 2026-01-13 16:15:31 +01:00
MoritzandWilli Ballenthin 7bdd1f11bb Merge branch 'master' into idalib-tests 2026-01-13 16:15:31 +01:00
Capa Bot bfd1b09176 Sync capa-testfiles submodule 2026-01-06 16:50:00 +00:00
Mike HunhoffGitHubgemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
66dc70a775 ghidra: support PyGhidra (#2788)
* ghidra: init commit switch to PyGhidra

* update CHANGELOG and PyGhidra version requirements

* Update capa/features/extractors/ghidra/helpers.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix black errors

* support Ghidra v12

* remove deprecated APIs

* refactor outdated code

* fix pyinstaller, code refactoring

* address PR feedback

* add back capa_explorer.py

* beef up capa_explorer.py script

* refactor README

* refactor README

* fix #2747

* add sha256 check for workflows

* add sha256 check for workflows

* add sha256 check for workflows

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-18 17:55:49 -07:00
mr-tz dc08843e2d address idalib-based test fails 2025-12-11 14:18:13 +00:00
Capa Bot c0ae1352c6 Sync capa-testfiles submodule 2025-12-03 21:00:48 +00:00
MoritzandGitHub 074f7c742c Merge branch 'master' into idalib-tests 2025-11-24 19:52:40 +01:00
Mike HunhoffandGitHub 8d39765e7b ci: bump binja minor version (#2763) 2025-11-17 11:10:46 -07:00
Willi Ballenthin cf463676b2 fixtures: remove dups 2025-11-03 12:47:12 +01:00
Willi Ballenthin b5e5840a63 lints 2025-10-29 20:29:08 +01:00
Willi Ballenthin eda53ab3c1 tests: add feature tests for idalib 2025-10-29 20:20:57 +01:00
Capa Bot ca708ca52e Sync capa-testfiles submodule 2025-10-28 15:15:42 +00:00
Capa Bot add09df061 Sync capa-testfiles submodule 2025-10-20 15:18:32 +00:00
Capa Bot 3bc2d9915c Sync capa-testfiles submodule 2025-10-13 18:52:26 +00:00
Capa Bot 826330f511 Sync capa-testfiles submodule 2025-09-03 15:58:45 +00:00
Capa Bot 40e5095577 Sync capa-testfiles submodule 2025-09-03 15:55:29 +00:00