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..a0baffe77 100644 --- a/capa/features/extractors/binja/extractor.py +++ b/capa/features/extractors/binja/extractor.py @@ -55,7 +55,11 @@ 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: + mlil = f.mlil_if_available + 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..f70278a9d 100644 --- a/capa/features/extractors/binja/insn.py +++ b/capa/features/extractors/binja/insn.py @@ -43,7 +43,11 @@ def is_stub_function(bv: BinaryView, addr: int) -> Optional[int]: call_count = 0 call_target = None - for il in func.llil.instructions: + llil = func.llil_if_available + if llil is None: + continue + + for il in llil.instructions: if il.operation in [ LowLevelILOperation.LLIL_CALL, LowLevelILOperation.LLIL_CALL_STACK_ADJUST,