Skip to main content

idalib/
lib.rs

1//! # idalib
2//!
3//! idalib is a Rust library providing idiomatic bindings for the IDA SDK, enabling the development
4//! of standalone analysis tools using IDA v9.x’s idalib.
5//!
6//! ## Usage
7//!
8//! To use idalib, add it as a dependency in your `Cargo.toml` and include a `build.rs` file in
9//! your project to properly link against IDA:
10//!
11//! ```toml
12//! [dependencies]
13//! idalib = "0.10"
14//!
15//! [build-dependencies]
16//! idalib-build = "0.10"
17//! ```
18//!
19//! Here is a basic example of a `build.rs` file:
20//!
21//! ```rust,ignore
22//! fn main() -> Result<(), Box<dyn std::error::Error>> {
23//!     idalib_build::configure_linkage()?;
24//!     Ok(())
25//! }
26//! ```
27//!
28//! This script uses the `idalib-build` crate to automatically configure the linkage against IDA.
29//! If IDA is installed in a non-default location, ensure that `IDADIR` is set to point to your
30//! installation directory, if you are linking against IDA's shared libraries, as opposed to the
31//! stub libraries distributed with the SDK.
32//!
33//! ## Setting Environment Variables
34//!
35//! ### On Linux/macOS
36//!
37//! You can set the environment variables in your terminal session or add them to your shell
38//! configuration file (e.g., `.bashrc`, `.zshrc`):
39//!
40//! ```sh,ignore
41//! export IDADIR=/path/to/ida/installation
42//! ```
43//!
44//! ### On Windows
45//!
46//! Set environment variables using Command Prompt, PowerShell, or System Properties.
47//!
48//! **Command Prompt:**
49//! ```cmd
50//! set IDADIR=C:\path\to\ida\installation
51//! ```
52//!
53//! **PowerShell:**
54//! ```powershell,ignore
55//! $env:IDADIR = "C:\path\to\ida\installation"
56//! ```
57//!
58//! **System Properties:**
59//! Go to "Environment Variables" in System Properties and add `IDADIR`.
60//!
61//! ## Example
62//!
63//! Here's a simple example of how to use idalib:
64//!
65//! ```rust,ignore
66//! use idalib::idb::IDB;
67//!
68//! fn main() -> Result<(), Box<dyn std::error::Error>> {
69//!     let idb = IDB::open("/path/to/binary")?;
70//!     // Perform analysis...
71//!     Ok(())
72//! }
73//! ```
74//!
75#![allow(clippy::needless_lifetimes)]
76
77use std::marker::PhantomData;
78use std::sync::{Mutex, MutexGuard, OnceLock};
79
80pub mod bookmarks;
81pub mod decompiler;
82pub mod func;
83pub mod idb;
84pub mod insn;
85pub mod license;
86pub mod meta;
87pub mod name;
88pub mod plugin;
89pub mod processor;
90pub mod segment;
91pub mod strings;
92pub mod typeinf;
93pub mod xref;
94
95pub use idalib_sys as ffi;
96
97pub use ffi::IDAError;
98pub use idb::IDB;
99#[cfg(not(feature = "plugin"))]
100pub use idb::IDBOpenOptions;
101pub use license::{LicenseId, is_valid_license, license_id};
102#[cfg(feature = "plugin")]
103pub use plugin::{IDAPlugin, PluginFlags};
104
105#[cfg(feature = "plugin")]
106pub use idalib_macros::plugin;
107
108pub type Address = u64;
109pub struct AddressFlags<'a> {
110    flags: ffi::bytes::flags64_t,
111    _marker: PhantomData<&'a IDB>,
112}
113
114impl<'a> AddressFlags<'a> {
115    pub(crate) fn new(flags: ffi::bytes::flags64_t) -> Self {
116        Self {
117            flags,
118            _marker: PhantomData,
119        }
120    }
121
122    pub fn is_code(&self) -> bool {
123        unsafe { ffi::bytes::is_code(self.flags) }
124    }
125
126    pub fn is_data(&self) -> bool {
127        unsafe { ffi::bytes::is_data(self.flags) }
128    }
129
130    pub fn is_byte(&self) -> bool {
131        unsafe { ffi::bytes::is_byte(self.flags) }
132    }
133
134    pub fn is_word(&self) -> bool {
135        unsafe { ffi::bytes::is_word(self.flags) }
136    }
137
138    pub fn is_dword(&self) -> bool {
139        unsafe { ffi::bytes::is_dword(self.flags) }
140    }
141
142    pub fn is_qword(&self) -> bool {
143        unsafe { ffi::bytes::is_qword(self.flags) }
144    }
145
146    pub fn is_oword(&self) -> bool {
147        unsafe { ffi::bytes::is_oword(self.flags) }
148    }
149
150    pub fn is_float(&self) -> bool {
151        unsafe { ffi::bytes::is_float(self.flags) }
152    }
153
154    pub fn is_double(&self) -> bool {
155        unsafe { ffi::bytes::is_double(self.flags) }
156    }
157
158    pub fn is_strlit(&self) -> bool {
159        unsafe { ffi::bytes::is_strlit(self.flags) }
160    }
161
162    pub fn is_off(&self, n: usize) -> bool {
163        unsafe { ffi::bytes::is_off(self.flags, (n as i32).into()) }
164    }
165}
166
167pub struct IDA;
168
169impl IDA {
170    pub fn new(_: &IDB) -> Self {
171        // NOTE: we take the IDB as an argument to ensure that the caller has access to it,
172        // therefore ensuring the library is correctly initialised.
173        Self
174    }
175
176    pub fn msg(&self, message: impl AsRef<str>) -> Result<(), IDAError> {
177        unsafe { ffi::ida::msg(message) }
178    }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182pub struct IDAVersion {
183    major: i32,
184    minor: i32,
185    build: i32,
186}
187
188impl IDAVersion {
189    pub fn major(&self) -> i32 {
190        self.major
191    }
192
193    pub fn minor(&self) -> i32 {
194        self.minor
195    }
196
197    pub fn build(&self) -> i32 {
198        self.build
199    }
200}
201
202static INIT: OnceLock<Mutex<()>> = OnceLock::new();
203
204#[cfg(not(any(target_os = "windows", feature = "plugin")))]
205unsafe extern "C" {
206    static mut batch: std::ffi::c_char;
207}
208
209pub(crate) type IDARuntimeHandle = MutexGuard<'static, ()>;
210
211#[cfg(not(feature = "plugin"))]
212pub fn force_batch_mode() {
213    #[cfg(not(target_os = "windows"))]
214    unsafe {
215        batch = 1;
216    }
217}
218
219#[cfg(feature = "plugin")]
220pub fn init_library() -> &'static Mutex<()> {
221    INIT.get_or_init(|| Mutex::new(()))
222}
223
224#[cfg(not(feature = "plugin"))]
225pub fn init_library() -> &'static Mutex<()> {
226    INIT.get_or_init(|| {
227        force_batch_mode();
228        ffi::ida::init_library().expect("IDA initialised successfully");
229        Mutex::new(())
230    })
231}
232
233pub(crate) fn prepare_library() -> IDARuntimeHandle {
234    let mutex = init_library();
235    mutex.lock().unwrap()
236}
237
238#[cfg(not(feature = "plugin"))]
239pub fn enable_console_messages(enabled: bool) {
240    init_library();
241    ffi::ida::enable_console_messages(enabled);
242}
243
244pub fn version() -> Result<IDAVersion, IDAError> {
245    ffi::ida::library_version().map(|(major, minor, build)| IDAVersion {
246        major,
247        minor,
248        build,
249    })
250}