Custom Backend LoaderΒΆ

If you want to load the disassembled binaries made by a tool that is not yet supported by QBinDiff you can implement your own backend loader.

You have to provide an implementation for all the classes that are found in src/qbindiff/loader/backend/abstract.py:

[3]:
import networkx
from collections.abc import Iterator

from qbindiff.loader.backend import (
    AbstractOperandBackend,
    AbstractInstructionBackend,
    AbstractBasicBlockBackend,
    AbstractFunctionBackend,
    AbstractProgramBackend
)
from qbindiff.loader import Structure
from qbindiff.loader.types import ReferenceType, ReferenceTarget, FunctionType
from qbindiff.types import Addr

class CustomOperandBackend(AbstractOperandBackend):

    def __str__(self) -> str:
        raise NotImplementedError()

    @property
    def immutable_value(self) -> int | None:
        raise NotImplementedError()

    @property
    def type(self) -> int:
        raise NotImplementedError()

    def is_immutable(self) -> bool:
        raise NotImplementedError()

class CustomInstructionBackend(AbstractInstructionBackend):

    @property
    def addr(self) -> Addr:
        raise NotImplementedError()

    @property
    def mnemonic(self) -> str:
        raise NotImplementedError()

    @property
    def references(self) -> dict[ReferenceType, list[ReferenceTarget]]:
        raise NotImplementedError()

    @property
    def operands(self) -> Iterator[AbstractOperandBackend]:
        raise NotImplementedError()

    @property
    def groups(self) -> list[int]:
        raise NotImplementedError()

    @property
    def id(self) -> int:
        raise NotImplementedError()

    @property
    def comment(self) -> str:
        raise NotImplementedError()

    @property
    def bytes(self) -> bytes:
        raise NotImplementedError()

class CustomBasicBlockBackend(AbstractBasicBlockBackend):

    @property
    def addr(self) -> Addr:
        raise NotImplementedError()

    @property
    def instructions(self) -> Iterator[AbstractInstructionBackend]:
        raise NotImplementedError()

class CustomFunctionBackend(AbstractFunctionBackend):

    @property
    def basic_blocks(self) -> Iterator[AbstractBasicBlockBackend]:
        raise NotImplementedError()

    @property
    def addr(self) -> Addr:
        raise NotImplementedError()

    @property
    def graph(self) -> networkx.DiGraph:
        raise NotImplementedError()

    @property
    def parents(self) -> set[Addr]:
        raise NotImplementedError()

    @property
    def children(self) -> set[Addr]:
        raise NotImplementedError()

    @property
    def type(self) -> FunctionType:
        raise NotImplementedError()

    @property
    def name(self) -> str:
        raise NotImplementedError()

class CustomProgramBackend(AbstractProgramBackend):

    @property
    def functions(self) -> Iterator[AbstractFunctionBackend]:
        raise NotImplementedError()

    @property
    def name(self) -> str:
        raise NotImplementedError()

    @property
    def structures(self) -> list[Structure]:
        raise NotImplementedError()

    @property
    def callgraph(self) -> networkx.DiGraph:
        raise NotImplementedError()

    @property
    def fun_names(self) -> dict[str, Addr]:
        raise NotImplementedError()

Most of the methods are self-explanatory but if you want to know more look at the docstring in the file src/qbindiff/loader/backend/abstract.py or at the python help.

[2]:
from qbindiff.loader.backend import AbstractProgramBackend

help(AbstractProgramBackend)
Help on class AbstractProgramBackend in module qbindiff.loader.backend.abstract:

class AbstractProgramBackend(builtins.object)
 |  This is an abstract class and should not be used as is.
 |  It represents a generic backend loader for a Program
 |
 |  Readonly properties defined here:
 |
 |  callgraph
 |      The callgraph of the program.
 |
 |  exec_path
 |      Returns the executable path
 |
 |  fun_names
 |      Returns a dictionary with function name as key and the function address as value.
 |
 |  functions
 |      Returns an iterator over backend function objects.
 |
 |  name
 |      The name of the program.
 |
 |  structures
 |      Returns the list of structures defined in program.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  __abstractmethods__ = frozenset({'callgraph', 'exec_path', 'fun_names'...