From 9e5c7393bb5cdef6c7cc49be2a0cec5512112805 Mon Sep 17 00:00:00 2001 From: rbran Date: Tue, 5 Aug 2025 13:47:54 +0000 Subject: [PATCH 1/2] update idb_import idb-rs to 0.1.12 --- plugins/idb_import/Cargo.toml | 2 +- plugins/idb_import/src/addr_info.rs | 75 +++++++-------- plugins/idb_import/src/lib.rs | 142 ++++++++++++++++++++-------- plugins/idb_import/src/types.rs | 33 +++++-- 4 files changed, 162 insertions(+), 90 deletions(-) diff --git a/plugins/idb_import/Cargo.toml b/plugins/idb_import/Cargo.toml index 9456aaba16..cad56142d6 100644 --- a/plugins/idb_import/Cargo.toml +++ b/plugins/idb_import/Cargo.toml @@ -12,5 +12,5 @@ crate-type = ["cdylib"] anyhow = { version = "1.0.86", features = ["backtrace"] } binaryninja.workspace = true binaryninjacore-sys.workspace = true -idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.10" } +idb-rs = { git = "https://github.com/Vector35/idb-rs", tag = "0.1.12" } log = "0.4" diff --git a/plugins/idb_import/src/addr_info.rs b/plugins/idb_import/src/addr_info.rs index cb977496b9..9a05e6d38d 100644 --- a/plugins/idb_import/src/addr_info.rs +++ b/plugins/idb_import/src/addr_info.rs @@ -3,56 +3,49 @@ use std::collections::HashMap; use anyhow::Result; -use idb_rs::id0::ID0Section; -use idb_rs::{til, IDAKind}; +use idb_rs::addr_info::all_address_info; +use idb_rs::id0::{ID0Section, Netdelta}; +use idb_rs::id1::ID1Section; +use idb_rs::id2::ID2Section; +use idb_rs::{til, Address, IDAKind}; #[derive(Default)] pub struct AddrInfo<'a> { - // TODO does binja diferenciate comments types on the API? - pub comments: Vec<&'a [u8]>, - pub label: Option>, + // TODO does binja differentiate comments types on the API? + pub comments: Vec>, + pub label: Option>, // TODO make this a ref pub ty: Option, } -pub fn get_info( - id0: &ID0Section, - version: u16, -) -> Result>> { - use idb_rs::id0::FunctionsAndComments::*; - let mut addr_info: HashMap = HashMap::new(); - - // the old style comments, most likely empty on new versions - let old_comments = id0.functions_and_comments()?.filter_map(|fc| match fc { - Err(e) => Some(Err(e)), - Ok(Comment { address, comment }) => Some(Ok((address, comment))), - Ok(Name | Function(_) | Unknown { .. }) => None, - }); - for old_comment in old_comments { - let (addr, comment) = old_comment?; - let comment = comment.message(); - addr_info.entry(addr).or_default().comments.push(comment); - } +pub fn get_info<'a, K: IDAKind>( + id0: &'a ID0Section, + id1: &ID1Section, + id2: Option<&ID2Section>, + netdelta: Netdelta, +) -> Result, AddrInfo<'a>>> { + let mut addr_info: HashMap, AddrInfo> = HashMap::new(); // comments defined on the address information - for info in id0.address_info(version)? { - use idb_rs::id0::AddressInfo::*; - let (addr, info) = info?; - let entry = addr_info.entry(addr).or_default(); - match info { - Comment(comments) => entry.comments.push(comments.message()), - Label(name) => { - if let Some(_old) = entry.label.replace(name) { - panic!("Duplicated label for an address should be impossible this is most likelly a programing error") - } - } - TilType(ty) => { - if let Some(_old) = entry.ty.replace(ty) { - panic!("Duplicated type for an address should be impossible this is most likelly a programing error") - } - } - Other { .. } => {} - DefinedStruct(_) => {} + for (info, _info_size) in all_address_info(id0, id1, id2, netdelta) { + let entry = addr_info.entry(info.address()).or_default(); + if let Some(comment) = info.comment() { + entry.comments.push(comment.to_vec()); + } + if let Some(comment) = info.comment_repeatable() { + entry.comments.push(comment.to_vec()); + } + if let Some(comment) = info.comment_pre() { + entry.comments.extend(comment.map(|line| line.to_vec())); + } + if let Some(comment) = info.comment_post() { + entry.comments.extend(comment.map(|line| line.to_vec())); + } + if let Some(label) = info.label()? { + entry.label = Some(label); + } + if let Some(ty) = info.tinfo()? { + entry.ty = Some(ty); } } diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs index 37ae5ed90d..fac9deb149 100644 --- a/plugins/idb_import/src/lib.rs +++ b/plugins/idb_import/src/lib.rs @@ -1,5 +1,10 @@ mod types; -use idb_rs::{IDAKind, IDAUsize}; +use std::borrow::Cow; +use std::io::{BufRead, Cursor, Seek}; + +use idb_rs::id1::ID1Section; +use idb_rs::id2::{ID2Section, ID2SectionVariants}; +use idb_rs::{IDAKind, IDAUsize, IDBFormat}; use types::*; mod addr_info; use addr_info::*; @@ -9,13 +14,13 @@ use binaryninja::debuginfo::{ CustomDebugInfoParser, DebugFunctionInfo, DebugInfo, DebugInfoParser, }; -use idb_rs::id0::{ID0Section, IDBParam1, IDBParam2}; +use idb_rs::id0::{ID0Section, ID0SectionVariants}; use idb_rs::til::section::TILSection; use idb_rs::til::TypeVariant as TILTypeVariant; use log::{error, trace, warn, LevelFilter}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use binaryninja::logger::Logger; struct IDBDebugInfoParser; @@ -81,9 +86,12 @@ struct BinaryViewReader<'a> { impl std::io::Read for BinaryViewReader<'_> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { if !self.bv.offset_valid(self.offset) { - return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "")); + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unable to read at the current offset in BinaryViewReader", + )); } - let len = BinaryView::read(&self.bv, buf, self.offset); + let len = BinaryView::read(self.bv, buf, self.offset); self.offset += u64::try_from(len).unwrap(); Ok(len) } @@ -96,10 +104,17 @@ impl std::io::Seek for BinaryViewReader<'_> { std::io::SeekFrom::End(end) => self.bv.len().checked_add_signed(end), std::io::SeekFrom::Current(next) => self.offset.checked_add_signed(next), }; - let new_offset = - new_offset.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::UnexpectedEof, ""))?; + let new_offset = new_offset.ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unable to calculate new offset in BinaryViewReader", + ) + })?; if !self.bv.offset_valid(new_offset) { - return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "")); + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Try to set invalid offset in BinaryViewReader", + )); } self.offset = new_offset; Ok(new_offset) @@ -118,27 +133,73 @@ fn parse_idb_info( offset: 0, }; trace!("Parsing a IDB file"); - let file = std::io::BufReader::new(file); - let mut parser = idb_rs::IDBParserVariants::new(file)?; - if let Some(til_section) = parser.til_section_offset() { + let mut file = std::io::BufReader::new(file); + let idb_kind = idb_rs::identify_idb_file(&mut file)?; + match idb_kind { + idb_rs::IDBFormats::Separated(sep) => { + parse_idb_info_format(debug_info, bv, debug_file, sep, file, progress) + } + idb_rs::IDBFormats::InlineUncompressed(inline) => { + parse_idb_info_format(debug_info, bv, debug_file, inline, file, progress) + } + idb_rs::IDBFormats::InlineCompressed(compressed) => { + let mut buf = vec![]; + let inline = compressed.decompress_into_memory(&mut file, &mut buf)?; + parse_idb_info_format( + debug_info, + bv, + debug_file, + inline, + Cursor::new(&buf[..]), + progress, + ) + } + } +} + +fn parse_idb_info_format( + debug_info: &mut DebugInfo, + bv: &BinaryView, + debug_file: &BinaryView, + format: impl IDBFormat, + mut idb_data: impl BufRead + Seek, + progress: Box Result<(), ()>>, +) -> Result<()> { + let Some(id0_idx) = format.id0_location() else { + return Err(anyhow!("Unable to find the ID0 section")); + }; + let Some(id1_idx) = format.id1_location() else { + return Err(anyhow!("Unable to find the ID1 section")); + }; + let id2_idx = format.id2_location(); + + if let Some(til_idx) = format.til_location() { trace!("Parsing the TIL section"); - let til = parser.read_til_section(til_section)?; + let til = format.read_til(&mut idb_data, til_idx)?; // progress 0%-50% import_til_section(debug_info, debug_file, &til, progress)?; - } + }; - 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% - match id0 { - idb_rs::IDAVariants::IDA32(id0) => { - parse_id0_section_info::(debug_info, bv, debug_file, &id0)? - } - idb_rs::IDAVariants::IDA64(id0) => { - parse_id0_section_info::(debug_info, bv, debug_file, &id0)? - } + let id0 = format.read_id0(&mut idb_data, id0_idx)?; + let id1 = format.read_id1(&mut idb_data, id1_idx)?; + let id2 = id2_idx + .map(|id2_idx| format.read_id2(&mut idb_data, id2_idx)) + .transpose()?; + + match (id0, id2) { + (ID0SectionVariants::IDA32(id0), Some(ID2SectionVariants::IDA32(id2))) => { + parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, Some(&id2))? + } + (ID0SectionVariants::IDA32(id0), None) => { + parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, None)? + } + (ID0SectionVariants::IDA64(id0), Some(ID2SectionVariants::IDA64(id2))) => { + parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, Some(&id2))? } + (ID0SectionVariants::IDA64(id0), None) => { + parse_id0_section_info(debug_info, bv, debug_file, &id0, &id1, None)? + } + _ => unreachable!(), } Ok(()) @@ -231,23 +292,20 @@ fn parse_id0_section_info( bv: &BinaryView, debug_file: &BinaryView, id0: &ID0Section, + id1: &ID1Section, + id2: Option<&ID2Section>, ) -> Result<()> { - let (version, idb_baseaddr) = match id0.ida_info()? { - idb_rs::id0::IDBParam::V1(IDBParam1 { - version, baseaddr, .. - }) - | idb_rs::id0::IDBParam::V2(IDBParam2 { - version, baseaddr, .. - }) => (version, baseaddr.into_u64()), - }; - + let ida_info_idx = id0.root_node()?; + let ida_info = id0.ida_info(ida_info_idx)?; + let idb_baseaddr = ida_info.addresses.loading_base.into_u64(); let bv_baseaddr = bv.start(); + let netdelta = ida_info.netdelta(); // just addr this value to the address to translate from ida to bn - // NOTE this delta could wrapp here and while using translating + // NOTE this delta could wrap here and while using translating let addr_delta = bv_baseaddr.wrapping_sub(idb_baseaddr); - for (idb_addr, info) in get_info(id0, version)? { - let addr = addr_delta.wrapping_add(idb_addr.into_u64()); + for (idb_addr, info) in get_info(id0, id1, id2, netdelta)? { + let addr = addr_delta.wrapping_add(idb_addr.into_raw().into_u64()); // just in case we change this struct in the future, this line will for us to review this code // TODO merge this data with folder locations let AddrInfo { @@ -279,6 +337,8 @@ fn parse_id0_section_info( } }); + let label: Option> = + label.as_ref().map(Cow::as_ref).map(String::from_utf8_lossy); match (label, &ty, bnty) { (label, Some(ty), bnty) if matches!(&ty.type_variant, TILTypeVariant::Function(_)) => { if bnty.is_none() { @@ -287,7 +347,7 @@ fn parse_id0_section_info( if !debug_info.add_function(&DebugFunctionInfo::new( None, None, - label.map(|x| x.to_string()), + label.map(Cow::into_owned), bnty, Some(addr), None, @@ -298,15 +358,15 @@ fn parse_id0_section_info( } } (label, Some(_ty), Some(bnty)) => { - let label: Option<&str> = label.as_ref().map(|x| x.as_ref()); - if !debug_info.add_data_variable(addr, &bnty, label, &[]) { + if !debug_info.add_data_variable(addr, &bnty, label.as_ref().map(Cow::as_ref), &[]) + { error!("Unable to add the type at {addr:#x}") } } (label, Some(_ty), None) => { // TODO types come from the TIL sections, can we make all types be just NamedTypes? error!("Unable to convert type {addr:#x}"); - // TODO how to add a label without a type associacted with it? + // TODO how to add a label without a type associated with it? if let Some(name) = label { if !debug_info.add_data_variable( addr, @@ -319,7 +379,7 @@ fn parse_id0_section_info( } } (Some(name), None, None) => { - // TODO how to add a label without a type associacted with it? + // TODO how to add a label without a type associated with it? if !debug_info.add_data_variable( addr, &binaryninja::types::Type::void(), diff --git a/plugins/idb_import/src/types.rs b/plugins/idb_import/src/types.rs index b3c9bea059..77c089e910 100644 --- a/plugins/idb_import/src/types.rs +++ b/plugins/idb_import/src/types.rs @@ -13,6 +13,7 @@ use binaryninja::types::{ }; use idb_rs::til::function::CallingConvention as TILCallingConvention; use idb_rs::til::pointer::Pointer as TILPointer; +use idb_rs::til::r#enum::EnumMembers; 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, @@ -486,14 +487,32 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { fn translate_enum(&self, ty_enum: &TILEnum) -> Ref { let mut eb = EnumerationBuilder::new(); - for (i, member) in ty_enum.members.iter().enumerate() { - let name = member - .name - .as_ref() - .map(|name| name.as_utf8_lossy().to_string()) - .unwrap_or_else(|| format!("member_{i}")); - eb.insert(&name, member.value); + match &ty_enum.members { + EnumMembers::Regular(enum_members) => { + for (i, member) in enum_members.iter().enumerate() { + let name = member + .name + .as_ref() + .map(|name| name.as_utf8_lossy().to_string()) + .unwrap_or_else(|| format!("member_{i}")); + eb.insert(&name, member.value); + } + } + EnumMembers::Groups(enum_groups) => { + for group in enum_groups { + // TODO implement groups to the importer + for (i, member) in group.sub_fields.iter().enumerate() { + let name = member + .name + .as_ref() + .map(|name| name.as_utf8_lossy().to_string()) + .unwrap_or_else(|| format!("member_{i}")); + eb.insert(&name, member.value); + } + } + } } + Type::enumeration( &eb.finalize(), // TODO: This looks bad, look at the comment in [`Type::width`]. From d27a8a6bea6e2eef9be81894af2cde02c615ef4a Mon Sep 17 00:00:00 2001 From: rbran Date: Tue, 12 Aug 2025 13:21:56 +0000 Subject: [PATCH 2/2] fix idb_import invalid offset in EoF hit --- plugins/idb_import/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs index fac9deb149..b1643ea321 100644 --- a/plugins/idb_import/src/lib.rs +++ b/plugins/idb_import/src/lib.rs @@ -86,10 +86,9 @@ struct BinaryViewReader<'a> { impl std::io::Read for BinaryViewReader<'_> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { if !self.bv.offset_valid(self.offset) { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "Unable to read at the current offset in BinaryViewReader", - )); + // TODO check if this is truly a EoF hit, `self.bv.len()` is not + // reliable, it's returning a size bigger then the original file. + return Ok(0); } let len = BinaryView::read(self.bv, buf, self.offset); self.offset += u64::try_from(len).unwrap();