"The road to exploitable bugs is paved with unexploitable bugs."
-- Mark Dowd
Rhabdomancer is a blazing-fast IDA headless plugin that locates calls to potentially insecure API functions in a binary file. Auditors can backtrace from these candidate points to find pathways allowing access to untrusted input.
- Blazing-fast, headless user experience courtesy of IDA 9.x and idalib-rs Rust bindings.
- Support for C/C++ binary targets compiled for any architecture implemented by IDA.
- Bad API function call locations are printed to stdout and marked in the IDB.
- Call locations in library code recognized by IDA (e.g., a statically linked runtime matched by FLIRT signatures) are
labeled
(lib). - Calls through stubs (e.g., the
.pltentries of ELF binaries or the import stubs of PE and Mach-O binaries, listed as thunks) are traced back to their callers. - In ELF binaries, a function is deliberately listed twice with the same call locations: once as its
.pltstub (marked as thunk) and once as its import. Each call location is marked only once in the IDB.
- Call locations in library code recognized by IDA (e.g., a statically linked runtime matched by FLIRT signatures) are
labeled
- Known bad API functions are grouped in tiers of badness to help prioritize the audit work.
- [BAD 0] High priority - Functions that are generally considered insecure.
- [BAD 1] Medium priority - Interesting functions that should be checked for insecure use cases.
- [BAD 2] Low priority - Code paths involving these functions should be carefully checked.
- The list of known bad API functions is built in and can be easily customized with a configuration file based on
conf/rhabdomancer.toml. - Function names are matched without these decorations: leading dots and underscores (e.g.,
_strcpy), the prefixes of library aliases (e.g.,__o_mallocin the Universal CRT,__libc_systemand__GI___snprintfin glibc), and, for stubs and such aliases only, the numeric suffix that IDA appends to names already in use (e.g.,memset_0).
Note
Fortified functions (e.g., __strcpy_chk, used instead of strcpy when building with _FORTIFY_SOURCE) are
deliberately not matched, since they are the checked variants of the listed functions. To also mark their calls,
add them explicitly to a custom configuration (e.g., "__strcpy_chk" with the same priority as strcpy).
- https://hex-rays.com/blog/streamlining-vulnerability-research-idalib-rust-bindings
- https://hnsecurity.it/blog/streamlining-vulnerability-research-with-ida-pro-and-rust
- https://github.com/0xdea/ghidra-scripts/blob/main/Rhabdomancer.java
- https://docs.hex-rays.com/release-notes/9_0#headless-processing-with-idalib
- https://github.com/idalib-rs/idalib
- https://books.google.it/books/about/The_Art_of_Software_Security_Assessment.html
The easiest way to get the latest release is via crates.io:
- Download, install, and configure IDA (see https://hex-rays.com/ida-pro).
- Install LLVM/Clang (see https://rust-lang.github.io/rust-bindgen/requirements.html).
- On Linux/macOS, install as follows:
On Windows, instead, use the following commands:
export IDADIR=/path/to/ida # if not set, the build script will check common locations cargo install rhabdomancer --locked
$env:LIBCLANG_PATH="\path\to\clang+llvm\bin" $env:PATH="\path\to\ida;$env:PATH" $env:IDADIR="\path\to\ida" # if not set, the build script will check common locations cargo install rhabdomancer --locked
Alternatively, you can build from source:
- Download, install, and configure IDA (see https://hex-rays.com/ida-pro).
- Install LLVM/Clang (see https://rust-lang.github.io/rust-bindgen/requirements.html).
- On Linux/macOS, compile as follows:
On Windows, instead, use the following commands:
git clone --depth 1 https://github.com/0xdea/rhabdomancer cd rhabdomancer export IDADIR=/path/to/ida # if not set, the build script will check common locations cargo build --release --locked
git clone --depth 1 https://github.com/0xdea/rhabdomancer cd rhabdomancer $env:LIBCLANG_PATH="\path\to\clang+llvm\bin" $env:PATH="\path\to\ida;$env:PATH" $env:IDADIR="\path\to\ida" # if not set, the build script will check common locations cargo build --release --locked
- Make sure IDA is properly configured with a valid license.
- Optionally customize the list of known bad API functions: copy
conf/rhabdomancer.toml(pick the tag that matches your installed version for its exact built-in list), edit the copy, and set theRHABDOMANCER_CONFIGenvironment variable to its path. The file must define thehigh,medium, andlowarrays, and no other keys. Otherwise, the built-in list is used, which is embedded in the binary at build time fromconf/rhabdomancer.toml(editing that file requires a rebuild). - Make sure the
IDADIRenvironment variable is set if your IDA installation is in a non-standard location. - Run as follows:
Any existing
rhabdomancer <binary_file>
.i64IDB file will be updated; otherwise, a new IDB file will be created. - Open the resulting
.i64IDB file with IDA. - Select
View>Open subviews>Bookmarks - Enjoy your results conveniently collected into an IDA window.
Note
Rhabdomancer also adds comments at marked call locations. Both bookmarks and comments are tagged as
[BAD n] <function_name>, where n is the priority tier (0 = high, 1 = medium, 2 = low), so that scripts can
search IDBs for them. This format is stable across releases.
Only the latest IDA release is officially supported, but older versions may work as well. The following table summarizes the latest compatible release for each IDA version:
| IDA version | Latest compatible release |
|---|---|
| v9.0.240925 | v0.2.4 |
| v9.0.241217 | v0.3.5 |
| v9.1.250226 | v0.6.2 |
| v9.2.250908 | v0.7.6 |
| v9.3.260213 | v0.8.1 |
| v9.3.260327 | v0.9.0 |
| v9.3.260421 | v0.9.3 |
| v9.4.260714 | current release |
| v9.4.260915 | current release |
Note
Check the idalib-rs documentation for additional information.
This project's development has been supported by the following organizations:
- HN Security
- Hex-Rays via their Contributor Program
- Further enrich the known bad API function list (see https://github.com/0xdea/semgrep-rules).
- Follow calls through thunks outside
.pltsegments (e.g., MSVC incremental-linkingj_thunks). - Consider skipping marking call locations in library code recognized by IDA (now only labeled
(lib)). - Implement serialized output to facilitate automated parsing and analysis.
- Implement a basic ruleset in the style of VulFi and VulnFanatic.
