Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.16.4"
__version__ = "2.16.5"


import logging
Expand Down
9 changes: 8 additions & 1 deletion libbs/api/decompiler_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,13 @@ def should_watch_artifacts(self) -> bool:
# These are API that provide extra introspection for plugins that may rely on LibBS Interface
#

@property
def binary_arch(self) -> str:
"""
Returns a string of the currently loaded binary's architecture.
"""
raise NotImplementedError

@property
def default_pointer_size(self) -> int:
"""
Expand Down Expand Up @@ -976,7 +983,7 @@ def find_current_decompiler(force: str = None) -> Optional[str]:
except Exception:
pass

if not force or has_bn_ui:
if has_bn_ui:
return BINJA_DECOMPILER
available.add(BINJA_DECOMPILER)
# error can be thrown for an invalid license
Expand Down
27 changes: 26 additions & 1 deletion libbs/decompilers/angr/artifact_lifter.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import typing

from libbs.api import ArtifactLifter

if typing.TYPE_CHECKING:
from .interface import AngrInterface

class AngrArtifactLifter(ArtifactLifter):
"""
TODO: finish me
"""
def __init__(self, interface):
def __init__(self, interface: "AngrInterface"):
super(AngrArtifactLifter, self).__init__(interface)

def is_arm(self) -> bool:
if self.deci.binary_arch is not None:
return "ARM" in self.deci.binary_arch
return False


def lift_type(self, type_str: str) -> str:
return type_str

Expand All @@ -19,3 +29,18 @@ def lower_type(self, type_str: str) -> str:

def lower_stack_offset(self, offset: int, func_addr: int) -> int:
return offset

def lower_addr(self, addr: int) -> int:
new_addr = super().lower_addr(addr)
if self.is_arm() and not self.deci.addr_starts_instruction(addr):
new_addr += 1

return new_addr


def lift_addr(self, addr: int) -> int:
new_addr = super().lift_addr(addr)
if self.is_arm() and new_addr % 2 == 1:
new_addr -= 1

return new_addr
42 changes: 39 additions & 3 deletions libbs/decompilers/angr/interface.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
from collections import defaultdict
from functools import lru_cache
from typing import Optional, Dict, List
from pathlib import Path

Expand Down Expand Up @@ -39,6 +40,7 @@ def __init__(self, workspace=None, **kwargs):
self._ctx_menu_items = []
self._am_logger = None
self._cfg = None
self._binary_arch = None
super().__init__(name="angr", artifact_lifter=AngrArtifactLifter(self), **kwargs)

def _init_headless_components(self, *args, **kwargs):
Expand Down Expand Up @@ -186,6 +188,15 @@ def rename_local_variables_by_names(self, func: Function, name_map: Dict[str, st

return self.refresh_decompilation(func.addr)

@property
def binary_arch(self) -> str | None:
if self._binary_arch is None:
if self.main_instance.project.arch:
self._binary_arch = self.main_instance.project.arch.name

return self._binary_arch


#
# GUI API
#
Expand All @@ -210,7 +221,8 @@ def gui_register_ctx_menu(self, name, action_string, callback_func, category=Non

def gui_active_context(self) -> Optional[Context]:
curr_view = self.workspace.view_manager.current_tab
if not curr_view:
# current view is non-existent or does not support a "function" view type of context
if not curr_view or not hasattr(curr_view, "function"):
return None

try:
Expand Down Expand Up @@ -293,6 +305,11 @@ def _functions(self) -> Dict[int, Function]:
funcs = {}
for addr, func in self.main_instance.project.kb.functions.items():
funcs[addr] = Function(addr, func.size)

# syscalls and simprocedures are not real funcs to sync
if func.is_syscall or func.is_simprocedure or not func.name:
continue

funcs[addr].name = func.name

return funcs
Expand Down Expand Up @@ -395,12 +412,31 @@ def print(self, msg: str, **kwargs):
# angr-management specific helpers
#

# TODO: add LRU back one day
#@lru_cache(maxsize=1024)
def addr_starts_instruction(self, addr) -> bool:
"""
Returns True when the provided address maps to a valid instruction address in the binary and that address
is at the start of the instruction (not in the middle). Useful for checking if an instruction is
incorrectly computed due to ARM THUMB.
"""
cfg = self.main_instance.project.kb.cfgs.get_most_accurate()
if cfg is None:
l.warning("Unable load CFG from angr. Other operations may be wrong.")
return False

node = cfg.get_any_node(addr, anyaddr=True)
if node is None:
return False

return addr in node.instruction_addrs

def refresh_decompilation(self, func_addr):
if self.headless:
return False

self.main_instance.workspace.jump_to(func_addr)
view = self.main_instance.workspace._get_or_create_view("pseudocode", CodeView)
self.workspace.jump_to(func_addr)
view = self.workspace._get_or_create_view("pseudocode", CodeView)
view.codegen.am_event()
view.focus()
return True
Expand Down
Loading