The decompiler API that works everywhere!
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, and is the backbone for all BinSync based plugins.
pip install libbs
You can optionally also do libbs --install
after to install generic plugins, but it's not required, since libbs
files will be installed with plugins that use it.
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.
You can find various examples using LibBS in the examples folder. Examples that are plugins show off more of the complicated API that allows you to use an abstracted UI, artifacts, and more.
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.
from libbs.api import DecompilerInterface
deci = DecompilerInterface.discover()
for addr in deci.functions:
function = deci.functions[addr]
if function.header.type == "void":
function.header.type = "int"
deci.functions[function.addr] = function
To use headless mode you must specify a decompiler to use. You can get the traditional interface using the following:
from libbs.api import DecompilerInterface
deci = DecompilerInterface.discover(force_decompiler="ida", 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
tell libbs where the headless binary path exists. This can be passed through either headless_dec_path
flag, or
through your environment. For Ghidra this would be: GHIDRA_HEADLESS_PATH
.
In designing the dictionaries that contain all Artifacts in a decompiler, we had a clash between ease-of-use and speed.
When accessing some artifacts like a Function
, we must decompile the function. Decompiling is slow. Due to this issue
we slightly changed how these dictionaries work to fast accessing.
The only way to access a full artifact is to use the getitem
interface of a dictionary. In practice this
looks like the following:
for func_addr, light_func in deci.functions.items():
full_function = deci.function[func_addr]
Notice, when using the items
function the function is light
, meaning it does not contain stack vars and other
info. This also means using keys
, values
, or list
on an artifact dictionary will have the same affect.