Skip to content

Commit

Permalink
Parse functions and comments in IDB import
Browse files Browse the repository at this point in the history
  • Loading branch information
rbran authored and emesare committed Sep 17, 2024
1 parent 6af1a38 commit 4b947a7
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 15 deletions.
2 changes: 1 addition & 1 deletion rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/examples/idb_import/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ crate-type = ["cdylib"]
[dependencies]
anyhow = "1.0.86"
binaryninja = { path = "../../" }
idb-rs = { git = "https://github.com/Vector35/idb-rs" }
idb-rs = { git = "https://github.com/Vector35/idb-rs", rev = "fec57b6" }
log = "0.4.20"
126 changes: 113 additions & 13 deletions rust/examples/idb_import/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ use std::collections::HashMap;
use binaryninja::architecture::CoreArchitecture;
use binaryninja::binaryninjacore_sys::{BNMemberAccess, BNMemberScope};
use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt};
use binaryninja::debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser};
use binaryninja::debuginfo::{
CustomDebugInfoParser, DebugFunctionInfo, DebugInfo, DebugInfoParser,
};
use binaryninja::logger;
use binaryninja::rc::Ref;
use binaryninja::types::{
Conf, EnumerationBuilder, FunctionParameter, NamedTypeReferenceClass, StructureBuilder,
StructureType, Type,
};

use idb_rs::id0::ID0Section;
use idb_rs::til::{
array::Array as TILArray, function::Function as TILFunction, r#enum::Enum as TILEnum,
r#struct::Struct as TILStruct, r#struct::StructMember as TILStructMember, section::TILSection,
Expand Down Expand Up @@ -86,11 +89,11 @@ impl CustomDebugInfoParser for IDBDebugInfoParser {
fn parse_info(
&self,
debug_info: &mut DebugInfo,
_bv: &BinaryView,
bv: &BinaryView,
debug_file: &BinaryView,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
) -> bool {
match parse_idb_info(debug_info, debug_file, progress) {
match parse_idb_info(debug_info, bv, debug_file, progress) {
Ok(()) => true,
Err(error) => {
error!("Unable to parse IDB file: {error}");
Expand Down Expand Up @@ -159,6 +162,7 @@ impl std::io::Seek for BinaryViewReader<'_> {

fn parse_idb_info(
debug_info: &mut DebugInfo,
bv: &BinaryView,
debug_file: &BinaryView,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
) -> Result<()> {
Expand All @@ -170,12 +174,26 @@ fn parse_idb_info(
trace!("Parsing a IDB file");
let file = std::io::BufReader::new(file);
let mut parser = idb_rs::IDBParser::new(file)?;
let Some(til_section) = parser.til_section_offset() else {
return Ok(());
};
trace!("Parsing the TIL section");
let til = parser.read_til_section(til_section)?;
parse_til_section_info(debug_info, debug_file, til, progress)
if let Some(til_section) = parser.til_section_offset() {
trace!("Parsing the TIL section");
let til = parser.read_til_section(til_section)?;
// progress 0%-50%
parse_til_section_info(debug_info, debug_file, til, |value, total| {
progress(value, total.wrapping_mul(2))
})?;
}

if let Some(id0_section) = parser.id0_section_offset() {
trace!("Parsing the ID0 section");
let id0 = parser.read_id0_section(id0_section)?;
// progress 50%-100%
parse_id0_section_info(debug_info, bv, debug_file, id0, |value, old_total| {
let new_total = old_total.wrapping_mul(2);
progress(value + old_total, new_total)
})?;
}

Ok(())
}

fn translate_enum(members: &[(Option<String>, u64)], bytesize: u64) -> Ref<Type> {
Expand Down Expand Up @@ -259,11 +277,11 @@ struct TranslatesIDBType<'a> {
is_symbol: bool,
}

struct TranslateIDBTypes<'a> {
struct TranslateIDBTypes<'a, F: Fn(usize, usize) -> Result<(), ()>> {
arch: CoreArchitecture,
debug_info: &'a mut DebugInfo,
_debug_file: &'a BinaryView,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
progress: F,
til: &'a TILSection,
// note it's mapped 1:1 with the same index from til types.chain(symbols)
types: Vec<TranslatesIDBType<'a>>,
Expand All @@ -273,7 +291,7 @@ struct TranslateIDBTypes<'a> {
types_by_name: HashMap<String, usize>,
}

impl TranslateIDBTypes<'_> {
impl<F: Fn(usize, usize) -> Result<(), ()>> TranslateIDBTypes<'_, F> {
fn find_typedef_by_ordinal(&self, ord: u64) -> Option<TranslateTypeResult> {
self.types_by_ord
.get(&ord)
Expand Down Expand Up @@ -683,7 +701,7 @@ fn parse_til_section_info(
debug_info: &mut DebugInfo,
debug_file: &BinaryView,
til: TILSection,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
progress: impl Fn(usize, usize) -> Result<(), ()>,
) -> Result<()> {
let total = til.symbols.len() + til.types.len();
let mut types = Vec::with_capacity(total);
Expand Down Expand Up @@ -854,6 +872,88 @@ fn parse_til_section_info(
Ok(())
}

fn parse_id0_section_info(
debug_info: &mut DebugInfo,
bv: &BinaryView,
_debug_file: &BinaryView,
id0: ID0Section,
progress: impl Fn(usize, usize) -> Result<(), ()>,
) -> Result<()> {
// TODO verify the best way to add comments, try to use the debug_info instead
for fc in id0.functions_and_comments()? {
match fc? {
idb_rs::id0::FunctionsAndComments::Name => {}
// function will be create bellow using the entry points
idb_rs::id0::FunctionsAndComments::Function(_) => {}
idb_rs::id0::FunctionsAndComments::RepeatableComment { address, value }
| idb_rs::id0::FunctionsAndComments::Comment { address, value } => {
let funcs_at = bv.functions_at(address);
if !funcs_at.is_empty() {
for function in &funcs_at {
function.set_comment(value);
}
} else {
// No functions directly at the address we can annotate containing functions instead.
for function in &bv.functions_containing(address) {
function.set_comment_at(address, value);
}
}
}
idb_rs::id0::FunctionsAndComments::Unknown { .. } => {}
}
}

#[derive(Debug, Default)]
struct ID0Function {
address: Option<u64>,
name: Option<String>,
symbol: Option<String>,
}
let mut functions: HashMap<u64, ID0Function> = HashMap::new();
for entry_point in id0.entry_points()? {
// TODO check for duplication
match entry_point? {
idb_rs::id0::EntryPoint::Name => {}
idb_rs::id0::EntryPoint::Unknown { .. } => {}
// TODO take ordinal in consideration if the order of the functions is important
idb_rs::id0::EntryPoint::Ordinal { .. } => {}
idb_rs::id0::EntryPoint::Function { key, address } => {
let fun = functions.entry(key).or_default();
let _ = fun.address.insert(address);
}
idb_rs::id0::EntryPoint::ForwardedSymbol { key, symbol } => {
let fun = functions.entry(key).or_default();
let _ = fun.symbol.insert(symbol.to_string());
}
idb_rs::id0::EntryPoint::FunctionName { key, name } => {
let fun = functions.entry(key).or_default();
let _ = fun.name.insert(name.to_string());
}
}
}
let total = functions.len();
for (i, function) in functions.into_values().enumerate() {
if progress(i, total).is_err() {
warn!("Aborted while adding the functions");
break;
}
let name = function.name.clone();
if !debug_info.add_function(DebugFunctionInfo::new(
None,
None,
function.name.clone(),
None,
function.address,
None,
vec![],
vec![],
)) {
error!("Unable to add the function {name:?}")
}
}
Ok(())
}

#[no_mangle]
pub extern "C" fn CorePluginInit() -> bool {
let _logger = logger::init(LevelFilter::Error);
Expand Down

0 comments on commit 4b947a7

Please sign in to comment.