idalib

repository·master·Indexed 43 days ago

https://github.com/idalib-rs/idalib

Idiomatic Rust bindings for the IDA SDK, enabling the development of standalone analysis tools using the IDA Pro v9.x idalib engine. Includes support for database lifecycle management, Hex-Rays decompilation, and plugin implementation via the PlugMod trait. Version 0.10.1 is compatible with IDA Pro v9.4.

Tokens
16K
Snippets
59
Records
82
Agent score
55%

What's inside idalib

  1. Ensure FFI safety with IDB lifetimes

    master

    When calling FFI functions in methods that operate on an IDB (or derived types), you must bind the owning type to the lifetime of the IDB to ensure memory safety. This is typically achieved using PhantomData to carry the lifetime.

    pub struct MyStruct<'a> {
        _marker: PhantomData<&'a IDB>,
    }
  2. Follow Rust style guidelines for IDALIB

    master

    When contributing to the IDALIB Rust bindings, you must adhere to specific coding standards regarding structure, imports, error handling, and type usage. Failure to follow these guidelines will result in a failed review.

    Key Guidelines:

    • Encapsulation: Avoid pub fields in structs. Instead, provide accessors and mutators (e.g., fn timeout(&self) and fn set_timeout(&mut self, ...)).
    • Error Handling: Never silently ignore errors. Use the ? operator for propagating errors and unwrapping values instead of .unwrap() or .expect().
    • Error Messages: Use lower-case for error messages unless starting with a proper noun or acronym (e.g., "component not found: reason").
    • Type Usage:
      • Prefer borrowed types over owned variants (e.g., &str over &String, &[u8] over &Vec<u8>, &Path over &PathBuf).
      • Use impl AsRef<T> where appropriate.
      • Avoid annotating types via let bindings; use turbo-fish syntax or type inference (e.g., let value = Vec::<u8>::new();).
    • String Formatting: Use named arguments in format strings (e.g., format!("Hello, {name}!")) rather than positional arguments.
  3. Organize Rust imports according to project standards

    master

    Imports must be organized into three distinct groups separated by whitespace, in the following order:

    1. Standard library imports (std)
    2. External library imports
    3. Same crate imports (crate)

    Rules for imports:

    • Do not nest modules in imports (e.g., avoid use module1::blah::{module2::bleep::Type}).
    • Do not use single-line nested braces for multiple standard library imports (e.g., avoid use std::{collections::{HashMap, HashSet}, path::{Path, PathBuf}};).
    • Use separate use statements for different paths within the same group.
    // CORRECT
    use std::collections::{HashMap, HashSet};
    use std::path::{Path, PathBuf};
    
    use serde::Serialize;
    use tokio::fs;
    
    use crate::models::DataModel;
    use crate::utils::helper;
  4. Use linting and formatting tools for IDALIB Rust code

    master

    Use the following commands to enforce the project's style and linting requirements:

    • Formatting: Use cargo fmt with specific configuration for import granularity and grouping.
    • Linting: Use cargo clippy to find issues and cargo clippy --fix to resolve them automatically.
    • Custom Lints: Use dylint with the project's specific pattern to run custom style checks.
    # Format code
    cargo fmt -- --config imports_granularity=Module,group_imports=StdExternalCrate
    
    # Lint code
    cargo clippy --no-deps
    cargo clippy --fix
    
    # Run custom lints
    cargo dylint --git https://github.com/xorpse/rust-style --pattern '*'
    
    # If dylint is not installed
    cargo install cargo-dylint dylint-link
  5. Install idalib-rs skills via Claude

    master

    To use the specialized skills for contributing to idalib-rs projects within the Claude environment, install the idalib plugin and the idalib-rust-skills package using the following commands:

    1. Add the idalib-rs/idalib plugin to the marketplace.
    2. Install the idalib-rust-skills@idalib-rs package.

    After installation, you can invoke the style guidelines by running /idalib-rust-style.

    /plugin marketplace add idalib-rs/idalib
    /plugin install idalib-rust-skills@idalib-rs
    /idalib-rust-style
  6. Install and set up idalib

    master

    To use idalib, you need the IDA SDK and a recent version of LLVM/Clang (for binding generation).

    Compatibility Matrix

    Ensure your idalib version matches your IDA Pro version:

    IDA Pro versionLatest compatible idalib
    v9.40.10.1
    v9.3sp10.9.0
    v9.30.8.1
    v9.20.7.2
    v9.10.6.1
    v9.0sp10.4.1
    v9.00.3.0

    Environment Variables

    During build, the crates attempt to locate an IDA installation. You can explicitly set the IDADIR environment variable to the directory containing the ida executable.

    • macOS example: /Applications/IDA Professional v9.x/Contents/macOS
    • Linux example: $HOME/ida-pro-9.x
  7. How to extend idalib

    master

    To expose new IDA SDK functionality that is not currently implemented in idalib:

    1. Modify the idasdk-sys crate to include the new low-level bindings.
    2. Add appropriate high-level Rust wrappers in the idalib crate.
    3. Submit a pull request.

    Note: Before starting development, you must ensure the IDA SDK submodule is checked out:

    git submodule update --init --recursive
  8. Create a minimal idalib project

    master

    A minimal working project requires idalib as a dependency and idalib-build as a build dependency. You must use a build.rs file to configure linkage.

    Cargo.toml

    [dependencies]
    idalib = "0.10"
    
    [build-dependencies]
    idalib-build = "0.10"

    build.rs

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        idalib_build::configure_linkage()?;
        Ok(())
    }

    src/main.rs

    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let idb = idalib::IDB::open("/path/to/binary")?;
    
        // ...
    
        Ok(())
    }
  9. How the IDAPlugin lifecycle works

    master

    The idalib plugin system follows a structured lifecycle managed by a bridge (via PlugmodWrapper).

    1. Initialization (init): The plugin is instantiated. The init method is responsible for taking the initial IDA and IDB contexts and returning the plugin instance.
    2. Execution (run): The run method is invoked with a usize argument. The bridge automatically handles retrieving the current IDB and creating a new IDA instance to pass to your plugin.
    3. Termination (term): When the plugin is being unloaded or closed, term is called to allow for graceful cleanup.

    If run or term returns an Err, the error is formatted and sent to the IDA message log using the internal msg function, prefixed with the plugin's name.

  10. Core Decompiler Types: CFunction, CBlock, and CInsn

    master

    The decompiler API provides three primary abstractions for interacting with Hex-Rays decompilation data:

    1. CFunction: Represents a decompiled function. It is the entry point for accessing the function's pseudocode or its structural body.
    2. CBlock: Represents a basic block within a function's control flow graph.
    3. CInsn: Represents an individual instruction within a CBlock.
  11. Initialize the idalib library

    master

    Before performing any IDA operations, you must initialize the library. This must be called from the main thread. Calling it from any other thread will trigger an assertion failure. Initialization sets the TVHEADLESS environment variable to 1 internally.

    use idalib::ida;
    
    fn main() -> Result<(), idalib::IDAError> {
        ida::init_library()?;
        // ... perform IDA tasks
        Ok(())
    }
  12. Open an IDB database with IDBOpenOptions

    master

    When not running as an IDA plugin, you can use IDBOpenOptions to configure how a database is opened. This allows you to specify a custom IDB path, a specific file type, whether to save changes on close, and whether to enable automatic analysis.

    Use the builder pattern to configure these options before calling .open(path).

    use idalib::IDB;
    use std::path::Path;
    
    let mut options = IDBOpenOptions::new()
        .idb(Path::new("my_database.i64"))
        .file_type("i64")
        .save(true)
        .auto_analyse(true);
    
    let idb = options.open(Path::new("input_file"))?;