diff --git a/README.md b/README.md index 88ad96f8..b19468c9 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,7 @@ for addr in deci.functions: function = deci.functions[addr] if function.header.type == "void": function.header.type = "int" - - deci.functions[function.addr] = function + deci.functions[function.addr] = function ``` ### Headless Mode @@ -43,7 +42,7 @@ To use headless mode you must specify a decompiler to use. You can get the tradi ```python from libbs.api import DecompilerInterface -deci = DecompilerInterface.discover(force_decompiler="ida", headless=True) +deci = DecompilerInterface.discover(force_decompiler="ghidra", headless=True) ``` In the case of decompilers that don't have a native python library for working with, like Ghidra and IDA, you will to diff --git a/libbs/__init__.py b/libbs/__init__.py index 9092f3a2..4d0d5150 100644 --- a/libbs/__init__.py +++ b/libbs/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.6.1" +__version__ = "1.6.2" import logging logging.getLogger("libbs").addHandler(logging.NullHandler()) diff --git a/libbs/api/artifact_dict.py b/libbs/api/artifact_dict.py index e9e720eb..137e6146 100644 --- a/libbs/api/artifact_dict.py +++ b/libbs/api/artifact_dict.py @@ -58,6 +58,18 @@ def __init__(self, artifact_cls, deci: "DecompilerInterface", error_on_duplicate def __len__(self): return len(self._artifact_lister()) + def _lifted_art_lister(self): + d = self._artifact_lister() + d_items = list(d.items()) + is_addr = hasattr(d_items[0][1], "addr") + new_d = {} + for k, v in d_items: + if is_addr: + k = self._deci.art_lifter.lift_addr(k) + new_d[k] = self._deci.art_lifter.lift(v) + + return new_d + def __getitem__(self, item): """ Takes a lifted identifier as input and returns a lifted artifact @@ -97,19 +109,19 @@ def __delitem__(self, key): pass def __iter__(self): - return iter(self._artifact_lister()) + return iter(self._lifted_art_lister()) def __repr__(self): return f"<{self.__class__.__name__}: {self._artifact_class.__name__} len={self.__len__()}>" def __str__(self): - return f"{self._artifact_lister()}" + return f"{self._lifted_art_lister()}" def keys(self): - return self._artifact_lister().keys() + return self._lifted_art_lister().keys() def values(self): - return self._artifact_lister().values() + return self._lifted_art_lister().values() def items(self): - return self._artifact_lister().items() + return self._lifted_art_lister().items() diff --git a/libbs/decompilers/ghidra/interface.py b/libbs/decompilers/ghidra/interface.py index db88edcb..75464295 100644 --- a/libbs/decompilers/ghidra/interface.py +++ b/libbs/decompilers/ghidra/interface.py @@ -260,6 +260,9 @@ def _set_function(self, func: Function, **kwargs) -> bool: def _get_function(self, addr, **kwargs) -> Optional[Function]: func = self._get_nearest_function(addr) + if func is None: + return None + dec = self._ghidra_decompile(func) # optimize on remote stack_variable_info: Optional[List[Tuple[int, str, str, int]]] = self.ghidra.bridge.remote_eval( diff --git a/tests/binaries/posix_syscall b/tests/binaries/posix_syscall new file mode 100644 index 00000000..83fa7f7d Binary files /dev/null and b/tests/binaries/posix_syscall differ diff --git a/tests/test_decompilers.py b/tests/test_decompilers.py index 7afcb4de..544612b8 100644 --- a/tests/test_decompilers.py +++ b/tests/test_decompilers.py @@ -17,11 +17,31 @@ BINJA_DECOMPILER: None, } + class TestHeadlessInterfaces(unittest.TestCase): def setUp(self): self._generic_renamed_name = "binsync_main" self._fauxware_path = TEST_BINARY_DIR / "fauxware" + def test_readme_example(self): + """ + TODO: Test more than just Ghidra here. + """ + deci = DecompilerInterface.discover( + force_decompiler=GHIDRA_DECOMPILER, + headless=True, + headless_dec_path=DEC_TO_HEADLESS[GHIDRA_DECOMPILER], + binary_path=TEST_BINARY_DIR / "posix_syscall", + ) + + for addr in deci.functions: + function = deci.functions[addr] + if function.header.type == "void": + function.header.type = "int" + deci.functions[function.addr] = function + + deci.shutdown() + def test_ghidra(self): # useful command for testing, kills all Headless-Ghidra: # kill $(ps aux | grep 'Ghidra-Headless' | awk '{print $2}')