From 9dd8b7a86448ff7882966347c755631b4c589f9b Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 21 Nov 2024 12:31:11 +0800 Subject: [PATCH] binja: fix crash when the IL of certain functions are not available. #2249 --- CHANGELOG.md | 1 + capa/features/extractors/binja/extractor.py | 11 ++++++++++- capa/features/extractors/binja/function.py | 11 +++++++++-- capa/features/extractors/binja/insn.py | 11 ++++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb2b8ce74..197e6ce7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - IDA Pro: rename ida to idapro module for plugin and idalib in IDA 9.0 #2453 @mr-tz - ghidra: fix saving of base address @mr-tz - binja: support loading raw x86/x86_64 shellcode #2489 @xusheng6 +- binja: fix crash when the IL of certain functions are not available. #2249 @xusheng6 ### capa Explorer Web diff --git a/capa/features/extractors/binja/extractor.py b/capa/features/extractors/binja/extractor.py index a5bea1596..1d4dd6bd7 100644 --- a/capa/features/extractors/binja/extractor.py +++ b/capa/features/extractors/binja/extractor.py @@ -8,6 +8,7 @@ from typing import Iterator import binaryninja as binja +from binaryninja import ILException import capa.features.extractors.elf import capa.features.extractors.binja.file @@ -55,7 +56,15 @@ def get_basic_blocks(self, fh: FunctionHandle) -> Iterator[BBHandle]: f: binja.Function = fh.inner # Set up a MLIL basic block dict look up to associate the disassembly basic block with its MLIL basic block mlil_lookup = {} - for mlil_bb in f.mlil.basic_blocks: + try: + mlil = f.mlil + except ILException: + return + + if mlil is None: + return + + for mlil_bb in mlil.basic_blocks: mlil_lookup[mlil_bb.source_block.start] = mlil_bb for bb in f.basic_blocks: diff --git a/capa/features/extractors/binja/function.py b/capa/features/extractors/binja/function.py index 058f98a94..dfddfda2b 100644 --- a/capa/features/extractors/binja/function.py +++ b/capa/features/extractors/binja/function.py @@ -7,7 +7,7 @@ # See the License for the specific language governing permissions and limitations under the License. from typing import Iterator -from binaryninja import Function, BinaryView, SymbolType, RegisterValueType, LowLevelILOperation +from binaryninja import Function, BinaryView, SymbolType, ILException, RegisterValueType, LowLevelILOperation from capa.features.file import FunctionName from capa.features.common import Feature, Characteristic @@ -24,7 +24,14 @@ def extract_function_calls_to(fh: FunctionHandle): # Everything that is a code reference to the current function is considered a caller, which actually includes # many other references that are NOT a caller. For example, an instruction `push function_start` will also be # considered a caller to the function - llil = caller.llil + llil = None + try: + # Temporary fix for https://github.com/Vector35/binaryninja-api/issues/6020. Since `.llil` can throw an + # exception rather than returning None + llil = caller.llil + except ILException: + continue + if (llil is None) or llil.operation not in [ LowLevelILOperation.LLIL_CALL, LowLevelILOperation.LLIL_CALL_STACK_ADJUST, diff --git a/capa/features/extractors/binja/insn.py b/capa/features/extractors/binja/insn.py index 0e8b74ea8..cae131ef9 100644 --- a/capa/features/extractors/binja/insn.py +++ b/capa/features/extractors/binja/insn.py @@ -13,6 +13,7 @@ BinaryView, ILRegister, SymbolType, + ILException, BinaryReader, RegisterValueType, LowLevelILOperation, @@ -43,7 +44,15 @@ def is_stub_function(bv: BinaryView, addr: int) -> Optional[int]: call_count = 0 call_target = None - for il in func.llil.instructions: + try: + llil = func.llil + except ILException: + return None + + if llil is None: + continue + + for il in llil.instructions: if il.operation in [ LowLevelILOperation.LLIL_CALL, LowLevelILOperation.LLIL_CALL_STACK_ADJUST,