Skip to content

Commit

Permalink
Rename to LibBS (#8)
Browse files Browse the repository at this point in the history
* Initial Rename

* Initial Rename

* Update setup

* bump
  • Loading branch information
mahaloz authored Nov 29, 2023
1 parent f681372 commit 6ba0b0d
Show file tree
Hide file tree
Showing 69 changed files with 215 additions and 216 deletions.
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# YODALib
Your Only Decompiler API Library (YODALib)!
# LibBS
The decompiler API that works everywhere!

YODALib is an abstracted decompiler API that enables you to write plugins/scripts that work, with minimal edit,
in every decompiler supported by YODALib.
LibBS is an abstracted decompiler API that enables you to write plugins/scripts that work, with minimal edit,
in every decompiler supported by LibBS. LibBS was originally designed to work with [BinSync](https://binsync.net).

## Install
```bash
pip install -e .
```

## Usage
YODALib exposes all decompiler API through the abstract class `DecompilerInterface`. The `DecompilerInterface`
LibBS exposes all decompiler API through the abstract class `DecompilerInterface`. The `DecompilerInterface`
can be used in either the default mode, which assumes a GUI, or `headless` mode. In `headless` mode, the interface will
start a new process using a specified decompiler.

### UI Mode (default)
To use the same script everywhere, use the convenience function `DecompilerInterface.discover_interface()`, which will
auto find the correct interface. Copy the below code into any supported decompiler and it should run without edit.
```python
from yodalib.api import DecompilerInterface
from libbs.api import DecompilerInterface
deci = DecompilerInterface.discover_interface()
for function in deci.functions:
if function.header.type == "void *":
Expand All @@ -30,7 +30,7 @@ for function in deci.functions:
### Headless Mode
To use headless mode you must specify a decompiler to use. You can get the traditional interface using the following:
```python
from yodalib.api import DecompilerInterface
from libbs.api import DecompilerInterface
deci = DecompilerInterface.discover_interface(force_decompiler="ida", headless=True)
```

Expand Down Expand Up @@ -65,9 +65,8 @@ G/S: Getters/Setters
- [ ] Change Callbacks

### Ghidra
- [ ] Generic Interface Outline & Stubs
- [ ] Every G/S
- [ ] Change Callbacks
- [ ] Get/Set Comments

### angr
- [ ] Change Callbacks
Expand Down
1 change: 1 addition & 0 deletions libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.4.0"
16 changes: 8 additions & 8 deletions yodalib/__main__.py → libbs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import importlib
import importlib.resources

from yodalib.plugin_installer import YODAPluginInstaller
from libbs.plugin_installer import LibBSPluginInstaller

_l = logging.getLogger(__name__)


def run_ghidra_ui():
yodalib_path = Path(str(importlib.resources.files("yodalib"))).absolute()
decompilers_path = yodalib_path / "decompilers"
libbs_path = Path(str(importlib.resources.files("libbs"))).absolute()
decompilers_path = libbs_path / "decompilers"
if not decompilers_path.exists():
_l.error("Known plugins path does not exist, which means BinSync did not install correctly!")
return False
Expand All @@ -24,28 +24,28 @@ def run_ghidra_ui():


def install():
YODAPluginInstaller().install()
LibBSPluginInstaller().install()


def main():
parser = argparse.ArgumentParser(
description="""
The YODA Command Line Util. This is the script interface to YODA that allows you to install and run
The LibBS Command Line Util. This is the script interface to LibBS that allows you to install and run
the Ghidra UI for running plugins.
""",
epilog="""
Examples:
yodalib --install
libbs --install
"""
)
parser.add_argument(
"--install", action="store_true", help="""
Install all the YODA plugins to every decompiler.
Install all the LibBS plugins to every decompiler.
"""
)
parser.add_argument(
"--run-ghidra-ui", action="store_true", help="""
Execute the Ghidra file selector UI for running YODA scripts.
Execute the Ghidra file selector UI for running LibBS scripts.
"""
)
args = parser.parse_args()
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Type
import logging

from yodalib.data import (
from libbs.data import (
Artifact, Comment, Enum, FunctionHeader, Function, FunctionArgument,
GlobalVariable, Patch, StackVariable, Struct, StructMember
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

from yodalib.data import StackVariable, Artifact
from yodalib.api.type_parser import CTypeParser
from libbs.data import StackVariable, Artifact
from libbs.api.type_parser import CTypeParser

_l = logging.getLogger(name=__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
from functools import wraps
from typing import Dict, Optional, Union, Tuple, List

import yodalib
from yodalib.api.artifact_lifter import ArtifactLifter
from yodalib.api.artifact_dict import ArtifactDict
from yodalib.api.type_parser import CTypeParser, CType
from yodalib.data import (
import libbs
from libbs.api.artifact_lifter import ArtifactLifter
from libbs.api.artifact_dict import ArtifactDict
from libbs.api.type_parser import CTypeParser, CType
from libbs.data import (
Artifact,
Function, FunctionHeader, StackVariable,
Comment, GlobalVariable, Patch,
Enum, Struct
)
from yodalib.decompilers import YODALIB_SUPPORTED_DECOMPILERS, ANGR_DECOMPILER, \
from libbs.decompilers import libbs_SUPPORTED_DECOMPILERS, ANGR_DECOMPILER, \
BINJA_DECOMPILER, IDA_DECOMPILER, GHIDRA_DECOMPILER

_l = logging.getLogger(name=__name__)
Expand Down Expand Up @@ -63,7 +63,7 @@ def __init__(
# these will be changed often by public API use
headless: bool = False,
init_plugin: bool = False,
plugin_name: str = f"generic_yoda_plugin",
plugin_name: str = f"generic_libbs_plugin",
# [category/name] = (action_string, callback_func)
gui_ctx_menu_actions: Optional[dict] = None,
ui_init_args: Optional[Tuple] = None,
Expand Down Expand Up @@ -106,7 +106,7 @@ def __init__(
#

def _init_ui_components(self, *args, **kwargs):
from yodalib.ui.version import set_ui_version
from libbs.ui.version import set_ui_version
set_ui_version(self.qt_version)

# register a real plugin in the GUI
Expand Down Expand Up @@ -134,9 +134,9 @@ def _init_ui_components(self, *args, **kwargs):
def _init_gui_plugin(self, *args, **kwargs):
return None

def active_context(self) -> yodalib.data.Function:
def active_context(self) -> libbs.data.Function:
"""
Returns an yodalib Function. Currently only functions are supported as current contexts.
Returns an libbs Function. Currently only functions are supported as current contexts.
This function will be called very frequently, so its important that its implementation is fast
and can be done many times in the decompiler.
"""
Expand All @@ -155,7 +155,7 @@ def register_ctx_menu_item(self, name, action_string, callback_func, category=No
raise NotImplementedError

def gui_ask_for_string(self, question, title="Plugin Question") -> str:
from yodalib.ui.utils import gui_ask_for_string
from libbs.ui.utils import gui_ask_for_string
return gui_ask_for_string(question, title=title)


Expand Down Expand Up @@ -248,7 +248,7 @@ def get_decompilation_object(self, function: Function) -> Optional[object]:

#
# Override Optional API:
# These are API that provide extra introspection for plugins that may rely on YODA Interface
# These are API that provide extra introspection for plugins that may rely on LibBS Interface
#

def undo(self):
Expand All @@ -260,7 +260,7 @@ def undo(self):
def local_variable_names(self, func: Function) -> List[str]:
"""
Returns a list of local variable names for a function. Note, these also include register variables
that are normally not liftable in YODA.
that are normally not liftable in LibBS.
@param func: Function to get local variable names for
@return: List of local variable names
"""
Expand All @@ -269,7 +269,7 @@ def local_variable_names(self, func: Function) -> List[str]:
def rename_local_variables_by_names(self, func: Function, name_map: Dict[str, str]) -> bool:
"""
Renames local variables in a function by a name map. Note, these also include register variables
that are normally not liftable in YODA.
that are normally not liftable in LibBS.
@param func: Function to rename local variables in
@param name_map: Dictionary of old name to new name
@return: True if any local variables were renamed, False if otherwise
Expand All @@ -280,7 +280,7 @@ def rename_local_variables_by_names(self, func: Function, name_map: Dict[str, st
# Artifact API:
# These functions are the main API for interacting with the decompiler artifacts. Generally, these functions
# should all be implemented by the decompiler interface, but in the case that they are not, they should not
# crash the YODA Interface.
# crash the LibBS Interface.
#

# functions
Expand All @@ -301,7 +301,7 @@ def _get_function(self, addr, **kwargs) -> Optional[Function]:

def _functions(self) -> Dict[int, Function]:
"""
Returns a dict of yodalib.Functions that contain the addr, name, and size of each function in the decompiler.
Returns a dict of libbs.Functions that contain the addr, name, and size of each function in the decompiler.
Note: this does not contain the live data of the Artifact, only the minimum knowledge to that the Artifact
exists. To get live data, use the singleton function of the same name.
Expand Down Expand Up @@ -338,7 +338,7 @@ def _get_global_var(self, addr) -> Optional[GlobalVariable]:

def _global_vars(self) -> Dict[int, GlobalVariable]:
"""
Returns a dict of yodalib.GlobalVariable that contain the addr and size of each global var.
Returns a dict of libbs.GlobalVariable that contain the addr and size of each global var.
Note: this does not contain the live data of the Artifact, only the minimum knowledge to that the Artifact
exists. To get live data, use the singleton function of the same name.
Expand All @@ -355,7 +355,7 @@ def _get_struct(self, name) -> Optional[Struct]:

def _structs(self) -> Dict[str, Struct]:
"""
Returns a dict of yodalib.Structs that contain the name and size of each struct in the decompiler.
Returns a dict of libbs.Structs that contain the name and size of each struct in the decompiler.
Note: this does not contain the live data of the Artifact, only the minimum knowledge to that the Artifact
exists. To get live data, use the singleton function of the same name.
Expand All @@ -372,7 +372,7 @@ def _get_enum(self, name) -> Optional[Enum]:

def _enums(self) -> Dict[str, Enum]:
"""
Returns a dict of yodalib.Enum that contain the name of the enums in the decompiler.
Returns a dict of libbs.Enum that contain the name of the enums in the decompiler.
Note: this does not contain the live data of the Artifact, only the minimum knowledge to that the Artifact
exists. To get live data, use the singleton function of the same name.
Expand All @@ -389,7 +389,7 @@ def _get_patch(self, addr) -> Optional[Patch]:

def _patches(self) -> Dict[int, Patch]:
"""
Returns a dict of yodalib.Patch that contain the addr of each Patch and the bytes.
Returns a dict of libbs.Patch that contain the addr of each Patch and the bytes.
Note: this does not contain the live data of the Artifact, only the minimum knowledge to that the Artifact
exists. To get live data, use the singleton function of the same name.
Expand Down Expand Up @@ -430,7 +430,7 @@ def global_artifacts(self):

def global_artifact(self, lookup_item: Union[str, int]):
"""
Returns a live yodalib.data version of the Artifact located at the lookup_item location, which can
Returns a live libbs.data version of the Artifact located at the lookup_item location, which can
lookup any artifact supported in `global_artifacts`
@param lookup_item:
Expand All @@ -451,8 +451,8 @@ def global_artifact(self, lookup_item: Union[str, int]):

def set_artifact(self, artifact: Artifact, lower=True, **kwargs) -> bool:
"""
Sets a yodalib Artifact into the decompilers local database. This operations allows you to change
what the native decompiler sees with yodalib Artifacts. This is different from opertions on a yodalib State,
Sets a libbs Artifact into the decompilers local database. This operations allows you to change
what the native decompiler sees with libbs Artifacts. This is different from opertions on a libbs State,
since this is native to the decompiler
>>> func = Function(0xdeadbeef, 0x800)
Expand Down Expand Up @@ -597,7 +597,7 @@ def discover_interface(force_decompiler: str = None, **ctrl_kwargs) -> Optional[
@param force_decompiler: The optional string used to override the BSController returned
@return: The DecompilerInterface associated with the current decompiler env
"""
if force_decompiler and force_decompiler not in YODALIB_SUPPORTED_DECOMPILERS:
if force_decompiler and force_decompiler not in libbs_SUPPORTED_DECOMPILERS:
raise ValueError(f"Unsupported decompiler {force_decompiler}")

has_ida = False
Expand All @@ -611,7 +611,7 @@ def discover_interface(force_decompiler: str = None, **ctrl_kwargs) -> Optional[
except ImportError:
pass
if has_ida or force_decompiler == IDA_DECOMPILER:
from yodalib.decompilers.ida.interface import IDAInterface
from libbs.decompilers.ida.interface import IDAInterface
dec_controller = IDAInterface(**ctrl_kwargs)
return dec_controller

Expand All @@ -622,7 +622,7 @@ def discover_interface(force_decompiler: str = None, **ctrl_kwargs) -> Optional[
except ImportError:
pass
if has_binja or force_decompiler == BINJA_DECOMPILER:
from yodalib.decompilers.binja.interface import BinjaInterface
from libbs.decompilers.binja.interface import BinjaInterface
bv = DecompilerInterface._find_global_in_call_frames('bv')
dec_controller = BinjaInterface(bv=bv, **ctrl_kwargs)
return dec_controller
Expand All @@ -635,7 +635,7 @@ def discover_interface(force_decompiler: str = None, **ctrl_kwargs) -> Optional[
except ImportError:
pass
if has_angr_man or force_decompiler == ANGR_DECOMPILER:
from yodalib.decompilers.angr.interface import AngrInterface
from libbs.decompilers.angr.interface import AngrInterface
workspace = DecompilerInterface._find_global_in_call_frames('workspace')
dec_controller = AngrInterface(workspace=workspace, **ctrl_kwargs)
return dec_controller
Expand All @@ -644,9 +644,9 @@ def discover_interface(force_decompiler: str = None, **ctrl_kwargs) -> Optional[
# TODO: make this check do a check to see if a remote port is open and it can connect
is_ghidra = True
if is_ghidra or force_decompiler == GHIDRA_DECOMPILER:
from yodalib.decompilers.ghidra.interface import GhidraDecompilerInterface
from libbs.decompilers.ghidra.interface import GhidraDecompilerInterface
dec_controller = GhidraDecompilerInterface(**ctrl_kwargs)
else:
raise ValueError("Please use YODALib with our supported decompiler set!")
raise ValueError("Please use LibBS with our supported decompiler set!")

return dec_controller
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions yodalib/data/state.py → libbs/data/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from sortedcontainers import SortedDict


from yodalib.data import (
from libbs.data import (
Comment,
Enum,
Function,
Expand All @@ -21,7 +21,7 @@
StackVariable,
Struct,
)
from yodalib.data.artifacts.artifact import TomlHexEncoder
from libbs.data.artifacts.artifact import TomlHexEncoder


l = logging.getLogger(__name__)
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions libbs/decompiler_stubs/angr_libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
try:
from libbs.decompilers.angr import *
except ImportError:
print("[!] libbs is not installed, please `pip install libbs` for THIS python interpreter")
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
plugin_metadata_version = 0

[plugin]
name = "yodalib"
shortname = "yodalib"
name = "libbs"
shortname = "libbs"
version = "0.0.0"
description = ""
long_description = ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

## yodalib
## libbs

<p align="center">
<img src="https://i.imgur.com/qdesKpg.png" style="width: 10%;" alt="yodalib Logo"/>
<img src="https://i.imgur.com/qdesKpg.png" style="width: 10%;" alt="libbs Logo"/>
</p>

Your Only Decompiler API
4 changes: 4 additions & 0 deletions libbs/decompiler_stubs/binja_libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
try:
from libbs.decompilers.binja import *
except ImportError:
print("[!] libbs is not installed, please `pip install libbs` for THIS python interpreter")
Loading

0 comments on commit 6ba0b0d

Please sign in to comment.