Skip to content

Commit e0679a5

Browse files
committed
[IDB Import] Fix some misc bugs
- In certain IDBs the loading base is zeroed but the info is not relative, in this case we now fallback to rebasing based off the lowest section address specified by `min_ea`. - In certain IDBs the info is relative, we ignore both the loading base and `min_ea` and compute the absolute address using the base address in the binary view - Fixed data exports being recognized as functions - Retrieve post, pre comments from dirtree - Fix mapping in extern section (which is tool specific in how it is setup) - Properly mark exported data as global binding
1 parent c6a2416 commit e0679a5

File tree

2 files changed

+213
-23
lines changed

2 files changed

+213
-23
lines changed

plugins/idb_import/src/mapper.rs

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
//! Map the IDB data we parsed into the [`BinaryView`].
22
3-
use crate::parse::{CommentInfo, FunctionInfo, IDBInfo, LabelInfo, NameInfo, SegmentInfo};
3+
use crate::parse::{
4+
BaseAddressInfo, CommentInfo, ExportInfo, FunctionInfo, IDBInfo, LabelInfo, NameInfo,
5+
SegmentInfo,
6+
};
47
use crate::translate::TILTranslator;
58
use binaryninja::architecture::Architecture;
69
use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt};
710
use binaryninja::qualified_name::QualifiedName;
811
use binaryninja::rc::Ref;
912
use binaryninja::section::{SectionBuilder, Semantics};
10-
use binaryninja::symbol::{Symbol, SymbolType};
13+
use binaryninja::symbol::{Binding, Symbol, SymbolType};
1114
use binaryninja::types::Type;
1215
use idb_rs::id0::SegmentType;
16+
use idb_rs::til::TypeVariant;
1317
use std::collections::HashSet;
1418

1519
/// Maps IDB data into a [`BinaryView`].
@@ -36,8 +40,28 @@ impl IDBMapper {
3640

3741
// Rebase the address from ida -> binja without this rebased views will fail to map.
3842
let bn_base_address = view.start();
39-
let ida_base_address = id0.base_address.unwrap_or(bn_base_address);
40-
let base_address_delta = bn_base_address.wrapping_sub(ida_base_address);
43+
let base_address_delta = match id0.base_address {
44+
// There is no base address in the IDA file, so we assume everything is relative and rebase.
45+
BaseAddressInfo::None => bn_base_address,
46+
BaseAddressInfo::BaseSegment(start_addr) => bn_base_address.wrapping_sub(start_addr),
47+
BaseAddressInfo::BaseSection(section_addr) => {
48+
let bn_section_addr = view
49+
.sections()
50+
.iter()
51+
.min_by_key(|s| s.start())
52+
.map(|s| s.start());
53+
match bn_section_addr {
54+
Some(bn_section) => bn_section.wrapping_sub(section_addr),
55+
None => bn_base_address,
56+
}
57+
}
58+
};
59+
60+
tracing::debug!(
61+
"Rebasing for {:0x} with delta {:0x}",
62+
bn_base_address,
63+
base_address_delta
64+
);
4165
let rebase = |addr: u64| -> u64 { addr.wrapping_add(base_address_delta) };
4266

4367
for segment in &id0.segments {
@@ -70,10 +94,16 @@ impl IDBMapper {
7094
self.map_func_to_view(view, &til_translator, &rebased_func);
7195
}
7296

97+
for export in &id0.exports {
98+
let mut rebased_export = export.clone();
99+
rebased_export.address = rebase(export.address);
100+
self.map_export_to_view(view, &til_translator, &rebased_export);
101+
}
102+
73103
// TODO: The below undo and ignore is not thread safe, this means that the mapper itself
74104
// TODO: should be the only thing running at the time of the mapping process.
75105
let undo = view.file().begin_undo_actions(true);
76-
for comment in &id0.comments {
106+
for comment in &self.info.merged_comments() {
77107
let mut rebased_comment = comment.clone();
78108
rebased_comment.address = rebase(comment.address);
79109
self.map_comment_to_view(view, &rebased_comment);
@@ -103,11 +133,11 @@ impl IDBMapper {
103133
}
104134
match til_translator.translate_type_info(&ty.tinfo) {
105135
Ok(bn_ty) => {
106-
tracing::debug!("Mapping type: {:?}", ty);
136+
tracing::debug!("Mapping type: {}", ty.name);
107137
view.define_auto_type(&ty_name, "IDA", &bn_ty);
108138
}
109139
Err(err) => {
110-
tracing::warn!("Failed to map type {:?}: {}", ty, err)
140+
tracing::warn!("Failed to map type {}: {}", ty.name, err)
111141
}
112142
}
113143
}
@@ -183,6 +213,11 @@ impl IDBMapper {
183213
pub fn map_segment_to_view(&self, view: &BinaryView, segment: &SegmentInfo) {
184214
let semantics = match segment.ty {
185215
SegmentType::Norm => Semantics::DefaultSection,
216+
// One issue is that an IDA section named 'extern' is _actually_ a synthetic section, so we
217+
// should not map it.
218+
SegmentType::Xtrn if segment.name == "extern" => {
219+
return;
220+
}
186221
SegmentType::Xtrn => {
187222
// IDA definition of extern is an actual section like '.idata' whereas extern in BN
188223
// is a synthetic section, do NOT use [`Semantics::External`].
@@ -226,12 +261,62 @@ impl IDBMapper {
226261
view.add_section(section);
227262
}
228263

264+
pub fn map_export_to_view(
265+
&self,
266+
view: &BinaryView,
267+
til_translator: &TILTranslator,
268+
export: &ExportInfo,
269+
) {
270+
let within_code_section = view
271+
.sections_at(export.address)
272+
.iter()
273+
.find(|s| s.semantics() == Semantics::ReadOnlyCode)
274+
.is_some();
275+
let is_func_ty = export
276+
.ty
277+
.as_ref()
278+
.is_some_and(|ty| matches!(ty.type_variant, TypeVariant::Function(_)));
279+
280+
if within_code_section && is_func_ty {
281+
tracing::debug!("Mapping function export: {:0x}", export.address);
282+
let func_info = FunctionInfo {
283+
name: Some(export.name.clone()),
284+
ty: export.ty.clone(),
285+
address: export.address,
286+
is_library: false,
287+
is_no_return: false,
288+
};
289+
self.map_func_to_view(view, til_translator, &func_info);
290+
} else {
291+
tracing::debug!("Mapping data export: {:0x}", export.address);
292+
let name_info = NameInfo {
293+
label: Some(export.name.clone()),
294+
ty: export.ty.clone(),
295+
address: export.address,
296+
exported: true,
297+
};
298+
self.map_name_to_view(view, til_translator, &name_info);
299+
}
300+
}
301+
229302
pub fn map_func_to_view(
230303
&self,
231304
view: &BinaryView,
232305
til_translator: &TILTranslator,
233306
func: &FunctionInfo,
234307
) {
308+
// We need to skip things that hit the extern section, since they do not have a bearing in the
309+
// actual context of the binary, and can be derived differently between IDA and Binja.
310+
let within_extern_section = view
311+
.sections_at(func.address)
312+
.iter()
313+
.find(|s| s.semantics() == Semantics::External)
314+
.is_some();
315+
if within_extern_section {
316+
tracing::debug!("Skipping function in extern section: {:0x}", func.address);
317+
return;
318+
}
319+
235320
let Some(bn_func) = view.add_auto_function(func.address) else {
236321
tracing::warn!("Failed to add function for {:0x}", func.address);
237322
return;
@@ -277,6 +362,18 @@ impl IDBMapper {
277362
til_translator: &TILTranslator,
278363
name: &NameInfo,
279364
) {
365+
// We need to skip things that hit the extern section, since they do not have a bearing in the
366+
// actual context of the binary, and can be derived differently between IDA and Binja.
367+
let within_extern_section = view
368+
.sections_at(name.address)
369+
.iter()
370+
.find(|s| s.semantics() == Semantics::External)
371+
.is_some();
372+
if within_extern_section {
373+
tracing::debug!("Skipping name in extern section: {:0x}", name.address);
374+
return;
375+
}
376+
280377
// Currently, we only want to use name info to map data variables, so skip anything in code.
281378
let within_code_section = view
282379
.sections_at(name.address)
@@ -289,7 +386,13 @@ impl IDBMapper {
289386
}
290387

291388
if let Some(label) = &name.label {
292-
let symbol = Symbol::builder(SymbolType::Data, &label, name.address).create();
389+
let binding = name
390+
.exported
391+
.then_some(Binding::Global)
392+
.unwrap_or(Binding::None);
393+
let symbol = Symbol::builder(SymbolType::Data, &label, name.address)
394+
.binding(binding)
395+
.create();
293396
tracing::debug!("Mapping name label: {:0x} => {}", name.address, symbol);
294397
view.define_auto_symbol(&symbol);
295398
}

0 commit comments

Comments
 (0)