Bitdefender Disassembler (bddisasm)

repository·master·Indexed 21 days ago

https://github.com/bitdefender/bddisasm

A lightweight, high-performance, thread-safe x86/x64 instruction decoder designed for user-space, kernel, and hypervisors. It includes Python wrappers (pybddisasm), Rust bindings (bddisasm and bddisasm-sys), and an instruction specification generator (isagenerator) for creating C header files and structures.

Tokens
11K
Snippets
32
Records
52
Agent score
76%

What's inside bddisasm

  1. Overview of the Instruction Specification Generator (isagenerator)

    master

    The isagenerator project is used to generate the C header files and structures required by the main Bitdefender disassembler. It consists of two primary components:

    1. Instruction specifications: Located in the instructions/ folder, these define instruction details including CPUID feature flags.
    2. Generation scripts:
      • isg_x86: A Python package used to parse instruction specifications into structured classes.
      • generate_tables.py: A script that uses the parsed data to generate the actual C files and structures.

    Adding new instructions: To add support for a new instruction, you typically only need to add it to the relevant table file within the instruction specifications. If the instruction requires a specific CPUID flag, you may also need to modify the corresponding CPUID files. Modifications to isg_x86 or generate_tables.py are generally only required when introducing a completely new encoding type.

  2. Instruction specification syntax format

    master

    Instruction specifications follow a strict, case-sensitive format (except for the mnemonic):

    mnemonic; explicit operands; implicit operands; encoding; flags

    • Mnemonic: The instruction name (e.g., ADD). Supports decorators and hints.
    • Explicit Operands: Operands that must be manually specified (e.g., eax, ecx).
    • Implicit Operands: Operands that the instruction operates on automatically (e.g., FLAGS).
    • Encoding: The binary encoding details, enclosed in square brackets [].
    • Flags: Additional metadata.
  3. Mnemonic decorators and hints

    master

    When defining a mnemonic, you can use decorators and hints to modify how the instruction class is generated or how the parser handles the mnemonic.

    Decorators (Not part of the instruction class name)

    • {ND}: Indicates a new data destination form.
    • {NF}: Indicates the instruction does not update flags. The parser adds an NF suffix to the mnemonic.
    • {ZU}: Indicates zero-upper support for the destination. The parser adds a ZU suffix to the mnemonic.

    Hints (Included in the instruction class name)

    • cc: Tells the parser the mnemonic contains a condition code. The cc sequence is replaced with the condition code encoded in the low 4 bits of the opcode.
    • sc: Tells the parser the EVEX.SC field contains a condition code. The sc sequence is replaced with the condition code encoded in the EVEX.SC field.

    Example:

    • Specification ADD{ND}{NF} results in instruction class ND_INS_ADD.
    • Specification SETcc{ZU} results in instruction class SETcc.
  4. Understand the bddisasm Rust crate structure

    master

    The Rust bindings are split into two distinct crates following standard Rust conventions:

    1. bddisasm-sys: A low-level crate that follows the *-sys convention. It provides a raw interface by linking directly with libbddisasm.
    2. bddisasm: A high-level, idiomatic Rust crate built on top of bddisasm-sys. It provides a safer and more convenient API, though some parts (like the Mnemonic enum) are manually refined from auto-generated code.
  5. Configure decoding behavior with ND_CONTEXT

    master

    To control how instructions are decoded (e.g., setting preferred vendors or feature masks), use the ND_CONTEXT structure with the NdDecodeWithContext or NdDecodeWithContextMini APIs.

    Workflow:

    1. Initialize the context using NdInitContext(&ctx).
    2. Set the following fields:
      • DefCode: Default code mode (e.g., ND_CODE_64).
      • DefData: Default data mode (e.g., ND_DATA_64).
      • DefStack: Default stack mode (e.g., ND_STACK_64).
      • VendMode: Preferred vendor. Use ND_VEND_ANY to try to decode as much as possible.
      • FeatMode: Feature mask. ND_FEAT_ALL (default) includes instructions mapped to wide NOP space like MPX or CET. Use ND_FEAT_NONE to see NOPs instead of these instructions.
    3. Reuse the same ctx for multiple decoding calls.
    ND_CONTEXT ctx;
    NdInitContext(&ctx);
    
    ctx.DefCode = ND_CODE_64;
    ctx.DefData = ND_DATA_64;
    ctx.DefStack = ND_STACK_64;
    ctx.VendMode = ND_VEND_ANY;
    ctx.FeatMode = ND_FEAT_ALL;
    
    // Use ctx in subsequent calls
    NDSTATUS status = NdDecodeWithContext(&ix, code, sizeof(code), &ctx);
  6. Access instruction information from the INSTRUX structure

    master

    The INSTRUX structure is a comprehensive container for all decoded information. You do not need helper functions to extract metadata; instead, access the fields directly.

    Key information categories include:

    • Encoding: Prefixes, opcodes, modrm, sib, immediates, and displacement.
    • Operands: Type, size, access, and encoding for both explicit and implicit operands.
    • Meta Information: Instruction set, type, and class.
    • Modes: Supported modes (real, protected, long, ring 0/1/2/3, etc.).
    • Flags: Access types (tested, modified, cleared, set, undefined) for CPU and FPU flags.
    • Memory: Segment, base/index/scale registers, displacement, and VSIB info.
    • CPU Compatibility: CPUID leaf information to check instruction availability.
  7. Install bddisasm via vcpkg

    master

    The easiest way to install the Bitdefender disassembler is using the vcpkg package manager. This command installs both the bddisasm and bdshemu static libraries.

    Note: The version available on vcpkg may not always be the latest version available on GitHub.

    vcpkg install bddisasm
  8. Integrate bddisasm into your C project

    master

    To use the disassembler, include the bddisasm.h header and link against the appropriate library: bddisasm.lib on Windows or libbddisasm.a on Linux.

    Requirement: External Functions Because the library is designed to be OS and environment agnostic, you must provide definitions for nd_vsnprintf_s and nd_memset. This allows the integrator to use their own preferred implementations of these standard functions.

    // Example of required function definitions
    int nd_vsnprintf_s(
        char *buffer,
        size_t sizeOfBuffer,
        size_t count,
        const char *format,
        va_list argptr
    ) {
        return _vsnprintf_s(buffer, sizeOfBuffer, count, format, argptr);
    }
    
    void* nd_memset(void *s, int c, size_t n) {
        return memset(s, c, n);
    }
  9. Verify pre-compiled binaries using GitHub Attestation

    master

    You can verify the integrity of released static libraries and the disasmtool CLI using GitHub Artifact Attestation.

    To verify a specific component:

    $ gh attestation verify disasmtool -o bitdefender

    To verify an entire bundle (e.g., a zip file):

    $ gh attestation verify x86-windows-release.zip -o bitdefender

    Note: Attestation is not available for bddisasm versions 2.1.4 or older.