From bf4695c6bfdd9cffbaf45b2d1912b94cc8cbab28 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 29 Feb 2024 15:52:58 +0800 Subject: [PATCH 1/4] binja: update binja version check after 4.0 release --- tests/test_binja_features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_binja_features.py b/tests/test_binja_features.py index 78addff7c..c226d2ee6 100644 --- a/tests/test_binja_features.py +++ b/tests/test_binja_features.py @@ -63,4 +63,4 @@ def test_standalone_binja_backend(): @pytest.mark.skipif(binja_present is False, reason="Skip binja tests if the binaryninja Python API is not installed") def test_binja_version(): version = binaryninja.core_version_info() - assert version.major == 3 and version.minor == 5 + assert version.major == 4 and version.minor == 0 From 58e4a30156668bbd280efbb5295ccb840aebe080 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 29 Feb 2024 15:53:28 +0800 Subject: [PATCH 2/4] binja: fix stack string detection and always use builtin function outlining --- capa/features/extractors/binja/basicblock.py | 69 ++------------------ 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/capa/features/extractors/binja/basicblock.py b/capa/features/extractors/binja/basicblock.py index 568ecc7ad..e74c9f486 100644 --- a/capa/features/extractors/binja/basicblock.py +++ b/capa/features/extractors/binja/basicblock.py @@ -7,17 +7,15 @@ # See the License for the specific language governing permissions and limitations under the License. import string -import struct from typing import Tuple, Iterator -from binaryninja import Function, Settings +from binaryninja import Function from binaryninja import BasicBlock as BinjaBasicBlock from binaryninja import ( BinaryView, SymbolType, RegisterValueType, VariableSourceType, - MediumLevelILSetVar, MediumLevelILOperation, MediumLevelILBasicBlock, MediumLevelILInstruction, @@ -29,11 +27,6 @@ from capa.features.extractors.helpers import MIN_STACKSTRING_LEN from capa.features.extractors.base_extractor import BBHandle, FunctionHandle -use_const_outline: bool = False -settings: Settings = Settings() -if settings.contains("analysis.outlining.builtins") and settings.get_bool("analysis.outlining.builtins"): - use_const_outline = True - def get_printable_len_ascii(s: bytes) -> int: """Return string length if all operand bytes are ascii or utf16-le printable""" @@ -65,7 +58,7 @@ def get_stack_string_len(f: Function, il: MediumLevelILInstruction) -> int: addr = target.value.value sym = bv.get_symbol_at(addr) - if not sym or sym.type != SymbolType.LibraryFunctionSymbol: + if not sym or sym.type not in [SymbolType.LibraryFunctionSymbol, SymbolType.SymbolicFunctionSymbol]: return 0 if sym.name not in ["__builtin_strncpy", "__builtin_strcpy", "__builtin_wcscpy"]: @@ -91,52 +84,6 @@ def get_stack_string_len(f: Function, il: MediumLevelILInstruction) -> int: return max(get_printable_len_ascii(bytes(s)), get_printable_len_wide(bytes(s))) -def get_printable_len(il: MediumLevelILSetVar) -> int: - """Return string length if all operand bytes are ascii or utf16-le printable""" - width = il.dest.type.width - value = il.src.value.value - - if width == 1: - chars = struct.pack(" bool: - """verify instruction moves immediate onto stack""" - if il.operation != MediumLevelILOperation.MLIL_SET_VAR: - return False - - if il.src.operation != MediumLevelILOperation.MLIL_CONST: - return False - - if il.dest.source_type != VariableSourceType.StackVariableSourceType: - return False - - return True - - def bb_contains_stackstring(f: Function, bb: MediumLevelILBasicBlock) -> bool: """check basic block for stackstring indicators @@ -144,14 +91,10 @@ def bb_contains_stackstring(f: Function, bb: MediumLevelILBasicBlock) -> bool: """ count = 0 for il in bb: - if use_const_outline: - count += get_stack_string_len(f, il) - else: - if is_mov_imm_to_stack(il): - count += get_printable_len(il) - - if count > MIN_STACKSTRING_LEN: - return True + count += get_stack_string_len(f, il) + if count > MIN_STACKSTRING_LEN: + return True + return False From 92cfc0caa7131e941f7f4ce110254c28e6d8630b Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 29 Feb 2024 16:50:20 +0800 Subject: [PATCH 3/4] binja: add support for forwarded export and enable the related unit tests --- capa/features/extractors/binja/file.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/capa/features/extractors/binja/file.py b/capa/features/extractors/binja/file.py index 0054e62b1..cd340e77d 100644 --- a/capa/features/extractors/binja/file.py +++ b/capa/features/extractors/binja/file.py @@ -74,13 +74,18 @@ def extract_file_embedded_pe(bv: BinaryView) -> Iterator[Tuple[Feature, Address] def extract_file_export_names(bv: BinaryView) -> Iterator[Tuple[Feature, Address]]: """extract function exports""" - for sym in bv.get_symbols_of_type(SymbolType.FunctionSymbol): + for sym in bv.get_symbols_of_type(SymbolType.FunctionSymbol) + bv.get_symbols_of_type(SymbolType.DataSymbol): if sym.binding in [SymbolBinding.GlobalBinding, SymbolBinding.WeakBinding]: name = sym.short_name - yield Export(name), AbsoluteVirtualAddress(sym.address) - unmangled_name = unmangle_c_name(name) - if name != unmangled_name: - yield Export(unmangled_name), AbsoluteVirtualAddress(sym.address) + if name.startswith("__forwarder_name(") and name.endswith(")"): + yield Export(name[17:-1]), AbsoluteVirtualAddress(sym.address) + yield Characteristic("forwarded export"), AbsoluteVirtualAddress(sym.address) + else: + yield Export(name), AbsoluteVirtualAddress(sym.address) + + unmangled_name = unmangle_c_name(name) + if name != unmangled_name: + yield Export(unmangled_name), AbsoluteVirtualAddress(sym.address) for sym in bv.get_symbols_of_type(SymbolType.DataSymbol): if sym.binding not in [SymbolBinding.GlobalBinding]: From 12234c357267247318a2168bbc8e6fccaaa68361 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 29 Feb 2024 16:57:09 +0800 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4eff5a81..438d97e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ ### Bug Fixes - do some imports closer to where they are used #1810 @williballenthin +- binja: fix and simplify stack string detection code after binja 4.0 @xusheng6 +- binja: add support for forwarded export #1646 @xusheng6 ### capa explorer IDA Pro plugin @@ -31,6 +33,7 @@ - ci: Fix PR review in the changelog check GH action #2004 @Ana06 - ci: use rules number badge stored in our bot gist and generated using `schneegans/dynamic-badges-action` #2001 capa-rules#882 @Ana06 - ci: update github workflows to use latest version of actions that were using a deprecated version of node #1967 #2003 capa-rules#883 @sjha2048 @Ana06 +- ci: update binja version to stable 4.0 #2016 @xusheng6 ### Raw diffs - [capa v7.0.1...master](https://github.com/mandiant/capa/compare/v7.0.1...master)