QBDI Dynamic Binary Instrumentation: Setup and Integration
A Dynamic Binary Instrumentation framework based on LLVM.
At a glance
- What is it?
- QBDI is an LLVM-based dynamic binary instrumentation framework for C++, Python, JavaScript, and Frida integrations across desktop and mobile platforms. It offers broad architecture coverage but leaves injection to external tools and does not support signals, new-thread creation, or C++ exceptions.
- Who is it for?
- QBDI fits reverse engineers and tool developers who need scriptable instrumentation across supported architectures and operating systems, especially when they already have a suitable injection mechanism. It is a poor fit for programs that depend on signals, newly created threads, C++ exception handling, or an unsupported platform combination.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 51 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
QBDI's Role in Native Code Analysis
QBDI solves a specific native-code analysis problem: instrumenting a program while it executes instead of modifying its source code first. Its intended users include reverse engineers, security researchers, and developers of dynamic analysis tools who need to observe or alter execution in a running binary. The framework targets x86, x86-64, ARM, and AArch64 systems, with documented operating-system coverage across Linux, macOS, Android, Windows, and iOS under stated conditions.
The repository describes QBDI as modular and based on LLVM. It exposes C and C++ APIs, with Python through PyQBDI and JavaScript access through Frida bindings. Its support table marks execution and memory access instrumentation as supported for each listed CPU and operating-system pair. That makes the framework relevant when an analysis tool must work across more than one binary architecture, but it does not mean every process-loading scenario is handled by the core library.
QBDI deliberately contains no preferred injection method. This boundary is important for evaluation. A user needs a separate tool or process-loading integration capable of placing QBDI in the target environment. QBDI includes QBDIPreload, described as a small `LD_PRELOAD`-based injector for dynamic executables on Linux and macOS, but that helper does not replace general process-injection requirements on every supported platform. The framework is also integrated with Frida, which supplies an external scripting and instrumentation path rather than making injection QBDI's sole concern.
QBDI's LLVM-Based Execution and Instrumentation Path
QBDI's documented design combines LLVM with platform and architecture components. The compilation section explains that it builds a local LLVM version statically because it uses private LLVM APIs that ordinary LLVM installations do not export and because its source must match a specific version of those APIs. That architectural choice affects both compatibility and build effort. A system LLVM installation cannot simply be assumed to replace QBDI's internal copy.
The framework exposes execution and memory access instrumentation. Those capabilities indicate that a host tool can issue requests involving instruction execution and memory operations during a target's run. The README does not document the complete runtime lifecycle, such as the exact sequence for creating an execution context, registering callbacks, starting a run, handling translated blocks, or stopping execution. Those details need to come from the stable or `dev-next` API documentation.
The repository layout supports this multi-part character. Public-facing material is under `include/`, implementation code is under `src/`, documentation lives in `docs/`, and language and C-family examples appear under `examples/`. Examples include `examples/cryptolock.c`, `examples/cryptolock.cpp`, `examples/mnemonicFilter.cpp`, `examples/modules.c`, `examples/modules.cpp`, and an `examples/pyqbdi/` directory. Their presence shows intended usage surfaces, but the README does not include enough source code to reproduce their behavior in this review.
Bindings should also be treated as separate adoption choices. The Python package is documented as self-contained and independent from the C/C++ package. Installing `PyQBDI` does not imply that it automatically supplies the native development files or release binaries used by a separate C++ host. An engineer must select the interface that matches the process-loading and scripting architecture of the intended tool.
Installing PyQBDI for a First Python Setup
PyQBDI provides the shortest documented installation path. The README directs users to PyPI and gives the following command:
pip install PyQBDIA successful installation should place the self-contained `PyQBDI` package in the active Python environment. The repository also contains `pyproject.toml`, `setup.py`, and an `examples/pyqbdi/` directory, which confirm that the Python binding is part of the source tree. The README does not show a complete Python script that loads a target executable, installs a callback, or invokes QBDI. Without that example, the first confirmed operation is package installation rather than instrumentation.
Native consumers use a different distribution path. The README states that every QBDI release is compiled and made available on the GitHub release page. Users who need the C/C++ or Frida API should download the release package for their operating system and architecture instead of assuming that `pip install PyQBDI` installs native headers or libraries. The repository does not provide a universal package-manager command for those native packages.
Development packages follow the same split by platform. The README links GitHub Actions artifacts for Android, Linux, macOS, Windows, and Python on the `dev-next` branch. It gives no strict development timeline or scheduled release plan. These artifacts are therefore a separate channel from tagged releases and may represent work that is not yet packaged as `v0.12.1` or another named release.
Building the Native QBDI Package on Linux
Building QBDI from source has a documented dependency list: CMake 3.12 or later, either Ninja or make, and a C++17 toolchain such as gcc, clang, or Visual Studio 2019. The `pyproject.toml` build requirements additionally list `cmake>=3.28`, `setuptools>=61.0`, `wheel`, and `ninja` for the Python packaging build path. This difference matters because a native build and a PyQBDI source build are not documented as sharing one identical prerequisite version.
For Linux on x86-64, the README tells developers to create a build directory and run the supplied configuration script. From the source tree, use:
mkdir build
cd build
../cmake/config/config-linux-X86_64.sh
ninjaThe script should configure CMake for the intended target, and Ninja should build that configuration. For x86 rather than x86-64, the README says to use the corresponding `config-linux-X86.sh` script with the same build-directory structure. It does not claim that these Linux instructions cover ARM or AArch64 builds.
QBDI supplies configuration scripts following the `config-OS-ARCH.sh` naming pattern. The README says those scripts must be modified for debug builds or cross-compilation. That is useful configuration guidance rather than a one-command abstraction. The source build also includes QBDI's locally built LLVM, so build time and toolchain compatibility matter even though LLVM is not presented as a separately installed package.
QBDIPreload, Frida, and External Process Integration
QBDI's modular boundary is the main integration decision. QBDIPreload is limited to an `LD_PRELOAD`-based mechanism for dynamic executables on Linux and macOS. That approach does not fit every target equally. Static executables, other operating systems, and process models that cannot use dynamic loading require a different injection strategy, but QBDI does not designate one as the core answer.
The documented Frida integration offers another route because the README states that QBDI is fully integrated with Frida. For teams that already script with Frida, this can reduce the need to design a separate JavaScript-facing control layer. It does not remove the target constraints documented for QBDI itself. Frida changes the surrounding tooling, not the absence of signal, thread-creation, or C++ exception handling in the core library.
There is also a distinction between a binding and an injection tool. PyQBDI gives Python code access to a self-contained QBDI package, while QBDIPreload supplies a narrow Linux and macOS loader. Neither statement establishes that arbitrary executable loading is solved for every platform. A prospective host should identify the target's loading behavior, choose an injection mechanism, and then use QBDI for instrumentation through the required API.
Signal, Thread, and Exception Boundaries in QBDI
The README identifies three current limitations that can determine whether QBDI is suitable for a target. It does not handle signals. It does not handle multithreading and, more precisely, does not deal with creation of new threads. It also does not handle C++ exception mechanisms. These are not minor configuration differences because they concern runtime semantics that frequently appear in real applications.
A program that starts worker threads after instrumentation begins falls outside the documented core behavior. A library that relies on POSIX or platform-specific signal handling also cannot be assumed to behave correctly under QBDI. C++ code throwing and catching exceptions poses a separate problem. The README suggests that such system-dependent features may be integrated as a new layer, but it does not specify an existing layer or implementation.
Platform support also has a qualification. The status table lists AArch64 with iOS, while a footnote says iOS support is unstable and requires a jailbroken device. ARM operating-system coverage is listed for Android and Linux rather than the full set shown for x86 architectures. An architecture appearing in the project name or binding does not by itself establish every operating-system combination.
For these reasons, QBDI is the wrong tool when correct execution of signals, newly created threads, or C++ exceptions is a primary requirement. The README does not claim that an external injection layer automatically fixes those core limitations.
QBDI Releases, Maintenance, and License Review
The repository is not archived, and its last push was on 2026-09-02. The latest listed release is `v0.12.1`, dated 2026-01-07, following `v0.12.0` from 2025-10-14. New work and fixes are merged onto `dev-next`, while tagged releases provide compiled C/C++ and Frida packages. The README warns that there is no strict development timeline or scheduled release plan, so development artifacts should not be treated as equivalent to a named release.
The upgrade path has a practical packaging cost. Native users must move between versioned release artifacts or development workflow artifacts, and should account for QBDI's LLVM API coupling when comparing branches. Python users have a separate self-contained package, which means its version lifecycle and behavior must be evaluated independently from the native C/C++ package.
The repository license is not an OSI identifier recognized by GitHub's classifier. The project includes `LICENSE.txt`, and the custom terms must be read there before use, distribution, modification, or integration. The repository-level description confirms a custom license, but it does not grant permission or impose duties. Any assessment of redistribution, derivative works, or commercial use therefore has to come from the actual `LICENSE.txt` text. This review does not provide legal advice or infer terms that are not included.
QBDI Compared with a Source-Level Instrumentation Path
A real alternative is source-level instrumentation. Tools in that category add hooks or transformed logic while an application is being built, whereas QBDI instruments a binary at runtime and targets code for which source is unavailable. Source-level approaches can offer more direct integration with language semantics and build systems. QBDI's advantage is its focus on native binaries across multiple architectures, including targets for which rebuilding the application is not practical.
The trade-off appears in runtime boundaries. QBDI documents missing support for signals, new-thread creation, and C++ exceptions. A source-instrumented application can potentially integrate with those facilities through its own code and platform mechanisms. QBDI instead offers broader use against existing native artifacts and exposes execution and memory access instrumentation, but an adopter must verify that the target does not depend on unsupported runtime behavior.
Another alternative is debugger-based analysis. A debugger can inspect a running process and control execution without rebuilding the source, but it serves a different workflow and the repository does not claim parity between QBDI's programmable instrumentation and debugger commands. The practical comparison is therefore source instrumentation versus runtime binary instrumentation. Choose QBDI when the binary artifact and cross-architecture reach matter more than avoiding the stated runtime limitations.
Editorial conclusion
QBDI fits reverse engineers and tool developers who need scriptable instrumentation across supported architectures and operating systems, especially when they already have a suitable injection mechanism. It is a poor fit for programs that depend on signals, newly created threads, C++ exception handling, or an unsupported platform combination. Before adoption, verify the selected release against the target architecture and operating system, inspect LICENSE.txt for the project's custom terms, and confirm that the required injection tool handles the target process model.
Frequently asked questions
How do I install PyQBDI?
Install the self-contained Python package with `pip install PyQBDI`. The README does not present this command as installing the separate C/C++ package.
Where can I download native QBDI releases?
The README says each QBDI version is compiled and published on the GitHub releases page. Development packages for the `dev-next` branch are published as GitHub Actions artifacts for their respective platforms.
Does QBDI support signals, multithreading, and C++ exceptions?
No. The README states that QBDI does not handle signals, multithreading or new thread creation, or C++ exception mechanisms.
Does QBDI include a preferred process injection method?
No. QBDI is designed to work with an external injection tool. It includes QBDIPreload for dynamic executables on Linux and macOS, and also offers integration with Frida.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/qbdi-qbdi)Was this useful?