Library / SDK
bitdefender/bddisasm avatar
bitdefender/bddisasm

bitdefender/bddisasm: an x86/x64 decoder that allocates no memory and runs in the kernel

bddisasm is a fast, lightweight, x86/x64 instruction decoder. The project also features a fast, basic, x86/x64 instruction emulator, designed specifically to detect shellcode-like behavior.

1,089 stars120 forksCApache-2.0

At a glance

What is it?
bddisasm is a C library for decoding x86 and x64 instructions, shipped with a small shellcode emulator, a table generator and a command line tool. It has no external dependencies, allocates nothing, is thread safe by design, and is used by Bitdefender in user, kernel and hypervisor environments on Windows and Linux.
Who is it for?
Adopt bddisasm when you need instruction level detail about untrusted x86 or x64 bytes, especially in an environment where you cannot allocate memory, cannot take a dependency, or must run inside a kernel or hypervisor, since the library was written for exactly those conditions.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A decoder written for the kernel, where allocation is not an option

The Bitdefender disassembler is an x86/x64 only instruction decoder written in C, and the list of what it deliberately is not is the interesting part. It has no external dependencies, it is thread safe, it allocates no memory at all, and the project says it works in virtually any environment, including user, kernel and hypervisor environments on both Windows and Linux.

Those three properties come from the same source. A decoder that runs inside a kernel cannot call into a general purpose allocator, cannot rely on a C library being present, and cannot assume it is the only thing touching memory. So the code is self contained, works on caller supplied buffers, and performs no allocation during a decode.

What you get back per instruction is also more than an opcode. The library exposes operands, both explicit and implicit, the access mode for each operand, the CPUID feature flag required by the instruction, and flags access information. For an analyst or a scanner, that metadata is the point, because it answers questions such as which registers are read and written, and whether an instruction needs a particular CPU feature, without re-implementing the encoding rules yourself.

Four projects: decoder, emulator, table generator and tool

The repository is not a single library, it is four, and the division tells you how to use it.

`bddisasm` is the main disassembler project. To use it you build the project and link against the output library, and the only headers you need are in the `inc` folder. `bdshemu` builds on the main library to provide a simple, lightweight, fast instruction emulator designated to target shellcodes, and it is also integrated into `disasmtool` so you can emulate raw binary files and see their output.

`isagenerator` holds the instruction definitions and the scripts that generate the disassembly tables. If you want to add support for a new instruction, this is where you do it, and the project warns you not to edit the generated files, which are `instructions.h`, `mnemonics.h`, `constants.h` and the `table_*.h` headers. Running the generation scripts requires Python 3.

`disasmtool` is the command line tool, described as used mainly as an example of how to integrate the two libraries. That is a useful framing to know before you build it: it is the reference for wiring the library up, and it doubles as a working disassembler on the command line.

Building with CMake and linking through find_package

CMake is the recommended build path. The prerequisites are CMake 3.16 or newer, with the note that older versions may work but have not been tested, and Ninja is optional but recommended, especially on Windows. The build was tested with GCC and Clang on Linux and with MSVC on Windows, and the Windows kernel build target is only available when building with MSBuild on Windows.

console
mkdir build
cmake -B build .
cmake --build build

That produces `bddisasm`, `bdshemu` and `disasmtool`. Turning off the tool is a single option, and installation is a standard target:

console
mkdir build
cmake -B build . -DBDD_INCLUDE_TOOL=OFF
console
cmake --build build --target install

Installation places the `bddisasm` and `bdshemu` static libraries plus their public headers, and `disasmtool` as well if it was built. Depending on the install location you may need to run the command as root.

Consumers then use `find_package`, and two targets are provided so a project can take only what it needs:

cmake
find_package(bddisasm REQUIRED)

# decoder-tool needs only the decoder library
target_link_libraries(decoder-tool PRIVATE bddisasm::bddisasm)

# emulator-tool needs bdshemu
target_link_libraries(emulator-tool PRIVATE bddisasm::bdshemu)

Choosing `bddisasm::bddisasm` over `bddisasm::bdshemu` when you only need decoding is a real decision, not a formality, because the emulator target pulls the decoder in automatically and the emulator carries its own state model.

The emulator models instructions, not programs

bdshemu is described as a simple, lightweight, fast instruction emulator designed to detect shellcode-like behavior, and the documentation is unusually clear about where that model stops. The emulator supports basic x86/x64 instructions, and it does not support emulating any kind of API call. The only supported memory accesses are inside the shellcode itself and on the emulated stack.

That is a sharp and useful boundary. A shellcode detector does not need to run a real program, it needs to know which instructions a blob would execute and which memory it would touch. By refusing to model the operating system, bdshemu stays small enough to embed in a scanner, and the absence of API support becomes a feature rather than a gap: a blob that tries to call a Windows API is recognised as doing so rather than being simulated.

The same restriction explains why bdshemu is a separate project from the decoder. The decoder is a pure function from bytes to structured instructions, while the emulator adds an execution model with registers, a stack and a memory view. Keeping them apart means a tool that only needs to classify bytes never pays for the emulator.

A legacy decoder and a mini decoder, with stated speed

The library ships two decoding paths, and the project publishes a measurement for both. On an Intel Core Ultra 7 165H, using BDDISASM v3.0, the legacy decoder runs at around 240 CPU clocks per decoded instruction, roughly 12 million decoded instructions per second, and the mini decoder at around 150 CPU clocks per instruction, roughly 17 million per second.

The two are separate entry points with different cost profiles, and you choose based on the metadata you need.

Whichever path you use, the coverage claim is broad: comprehensive support for Intel and AMD x86 instructions implemented in modern CPUs, including rich per instruction metadata. Whether the decoder is complete for a given encoding is still worth checking against the instruction tables, particularly for recently added instructions, and the `isagenerator` project is where a gap would be closed upstream.

Fuzzing, security handling and a public headers contract

The resilience claim is specific: the decoder is tested against internal fuzzers and against the well known mishegos tool from Trail of Bits. The tree backs that up with a `Dockerfile.fuzzing`, a `prepare_fuzzing_image.sh` script, a `bdshemu_fuzz/` directory and a `bddisasm_test/` suite alongside `bdshemu_test/`, and there is a `benchmark.sh` script for the performance numbers. A `.readthedocs.yaml` and a `docs/` directory mean the published documentation is generated from the repository.

Two smaller engineering details are worth knowing if you vendor this code. First, `nd_vsnprintf_s` and `nd_memset` are implemented inside bddisasm by default when `vsnprintf` and `memset` are available, and the public compile definitions `BDDISASM_HAS_VSNPRINTF` and `BDDISASM_HAS_MEMSET` signal that. You can turn that off with `BDD_USE_EXTERNAL_VSNPRINTF=ON` and `BDD_USE_EXTERNAL_MEMSET=ON`, which is the switch to flip in a kernel build where you want to route through your own primitives.

Second, the project can be consumed as a sub-project rather than installed, either as a git submodule or through CMake's FetchContent, and in that mode the `disasmtool`, `isagenerator` and `install` targets are not available.

cmake
FetchContent_Declare(
    bddisasm
    GIT_REPOSITORY https://github.com/bitdefender/bddisasm
    GIT_TAG origin/master
)

FetchContent_MakeAvailable(bddisasm)

The licence is Apache-2.0, and the repository carries a `SECURITY.md` file for reporting problems, which is where a vulnerability in a component used inside security products should be directed.

vcpkg, Make and the version lag on the package manager

Two other routes exist, and the project is honest about the tradeoffs. vcpkg is described as the easiest way to install bddisasm, with the command `vcpkg install bddisasm` installing the `bddisasm` and `bdshemu` static libraries, and with a warning that the version available on vcpkg may not always be the latest.

That warning shapes how you should use it. vcpkg is convenient when you want a pinned, reproducible dependency in a large build, but if you need a specific fix that landed after the last vcpkg port update, the package manager will not give it to you. The direct CMake build is the route that always reflects the current source.

On Linux there is also a plain Makefile, and it builds only the two libraries without `disasmtool`:

console
make
console
make install

The release history shows steady work on the v3 line, with v3.0.1 published on 2026-02-19, v3.0.2 on 2026-10-06 and v3.1.0 on 2026-10-14, and the last push to the repository on 2026-10-14. A `CHANGELOG.md` is in the tree, and since this is an API consumed by C and C++ code that vendors it, the changelog is where you look before moving a minor version forward.

Editorial conclusion

Adopt bddisasm when you need instruction level detail about untrusted x86 or x64 bytes, especially in an environment where you cannot allocate memory, cannot take a dependency, or must run inside a kernel or hypervisor, since the library was written for exactly those conditions. Do not adopt it as a full disassembler, since it decodes instructions rather than producing readable assembly listings, and do not expect bdshemu to model a program, because it does not support API calls and only touches memory inside the shellcode and on the emulated stack. Verify first that your compiler toolchain is covered by the tested combinations, GCC and Clang on Linux and MSVC on Windows, and that the version on vcpkg may lag the release, and that the v3.1.0 tag published on 2026-10-14 matches the API your integration code expects.

Frequently asked questions

What is bddisasm used for?

bddisasm is a lightweight x86/x64 only instruction decoder in C, with no external dependencies, no memory allocation and thread safe by design. It provides per instruction details such as explicit and implicit operands, operand access mode, CPUID feature flag and flags access.

Can bdshemu emulate a full Windows program?

No. bdshemu is a basic x86/x64 instruction emulator aimed at shellcode, it does not support emulating any kind of API call, and the only supported memory accesses are inside the shellcode itself and on the emulated stack.

How do I build bddisasm and link it into a CMake project?

Build with `mkdir build`, `cmake -B build .` and `cmake --build build`, then install with `cmake --build build --target install`. Consumers call `find_package(bddisasm REQUIRED)` and link `bddisasm::bddisasm` for the decoder alone or `bddisasm::bdshemu` for the emulator.

How do I add support for a new instruction in bddisasm?

The `isagenerator` project contains the instruction definitions and the scripts that generate the disassembly tables, and it needs Python 3. The generated files `instructions.h`, `mnemonics.h`, `constants.h` and the `table_*.h` headers should not be edited by hand.

Is the version of bddisasm on vcpkg up to date?

Not always. The project warns that the version available on vcpkg may not be the latest, so if you need a recent fix you should build from source with CMake or consume the repository as a git submodule or through FetchContent.

Official sources

  1. bitdefender/bddisasm on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bitdefender-bddisasm.svg)](https://hysenlabs.com/projects/bitdefender-bddisasm)

Was this useful?