Access, extend, and automate IDA through a first-class Rust API.
idakit drives IDA's analysis kernel from safe Rust:
const SINKS: &[&str] = &["strcpy", "system", "memcpy", "sprintf"];
for function in db.functions().take(300) {
// Decompile to a C syntax tree; skip anything that won't decompile.
let Some(tree) = function.decompile().ok().and_then(|d| d.ctree().ok()) else { continue };
for (_, callee, _) in tree.calls() {
// Resolve the call target to a name, then match it against the list.
let Some((_, Some(name))) = tree.kind(callee).as_obj() else { continue };
if SINKS.iter().any(|s| name.contains(s)) {
println!("{} calls {name}", function.name());
}
}
}Ida: brings the kernel up and marshals work onto its thread.Database: the open database, and the root of every read and write.Function: a function's name, bytes, chunks, instructions, and decompilation.Segment: a segment's range, permissions, and class.Type: an owned type snapshot, comparable across databases viatypes::diff.Ctree: a decompiled function's syntax tree, walkable off the kernel thread.Xref: a cross-reference edge between two addresses.
IDA's kernel initializes once per process and runs on a single thread. The example above
used Ida::here, which initializes it on the current thread and hands
the database back directly, a good fit for a tool or test that owns its thread.
When the current thread must stay free, such as a GUI event loop or an async runtime,
Ida::run hosts the kernel on its own dedicated thread instead. It hands
your closure an Ida handle whose Ida::call marshals work onto the
kernel from any thread:
use idakit::prelude::*;
Ida::run(|ida| {
ida.call(|db: &mut Database| -> Result<()> {
db.open("path/to/database.i64").call()?;
for function in db.functions() {
println!("{:#x} {}", function.address().get(), function.name());
}
db.close(false);
Ok(())
})?
})??;The open database is a single-owner kernel (Database is Send + !Sync), so it can move
between threads but is never shared. Reads borrow it and return lightweight views like
Function and Segment; writes take it by mutable reference, so a read can't outlive a
mutation.
Only one database is live at a time. Ida::here and
Ida::run return InitError::AlreadyRunning
while one is already open; drop it and you can start another.
For lower-level control, idakit_sys exposes IDA's raw C bindings directly.
Both crates carry #[doc(alias)] tags mapping items to their IDA SDK names, so a rustdoc search
resolves an SDK spelling like SEGPERM_READ or netnode::altval to the binding. Aliases are per
crate: idakit_sys carries the raw-binding names, idakit carries the idiomatic
wrappers.
A handful of shapes recur across every domain:
- A borrowed view (
Function,Segment) is a cheapCopyhandle that borrows theDatabaseand re-queries the kernel per accessor. - A lazy iterator (
Segments,function::Functions) walks a domain without collecting. - An owned snapshot (
Type,StackFrame,Ctree) is aSendvalue detached from the kernel and analyzable on any thread; aSnapshotsuffix (function::FunctionSnapshot) marks one taken from a view. - A kernel-handle owner (
Pattern,decompiler::DecompiledFunction) holds an IDA resource it frees onDrop, so it stays!Sendon the kernel thread.
- IDA Pro 9.3. A local install is needed to build, since idakit links its libraries, and a valid license to run, since IDA checks it when the kernel initializes.
- A 64-bit host running Linux, macOS, or Windows.
- Rust 1.88 or newer.
- A C++17 compiler for the build: g++ or Clang on Linux and macOS, MSVC on Windows.
git, to fetch the SDK headers that match your install, unless you supply a local SDK checkout withIDA_SDK_DIR.- 64-bit databases. idakit works with
.i64and can't open a 32-bit.idb.- You don't have to bring one, though: it can analyze a binary from scratch.
- A 32-bit binary is fine, since the limitation is the database format, not the target.
idakit locates your IDA install automatically, in order:
IDADIR, if set.idat64on yourPATH.- The platform's default install locations:
~/ida-pro-*and/opt/on Linux,/Applications/on macOS,Program Fileson Windows.
If none match, set IDADIR to the directory holding IDA's runtime library.
The SDK headers are fetched to match your installed IDA version, so a normal build needs no extra flags. Two variables override that:
IDA_SDK_DIRbuilds against a local SDK checkout instead of fetching.IDA_SDK_CACHE_DIRrelocates the fetch cache.
Databases must be 64-bit .i64, since the facade is compiled __EA64__.
The bindings are MIT licensed. The IDA SDK and runtime are proprietary to Hex-Rays; idakit links against your own install and redistributes none of it.
