A lot more section-address-aware refactoring

This commit is contained in:
2023-08-23 23:13:12 -04:00
parent 5843ee021e
commit 3f63f1ef47
29 changed files with 10110 additions and 1206 deletions

View File

@@ -1,7 +1,10 @@
use anyhow::{anyhow, Result};
use anyhow::{anyhow, bail, Result};
use crate::{
analysis::{cfa::AnalyzerState, read_u32},
analysis::{
cfa::{AnalyzerState, SectionAddress},
read_address,
},
obj::{
ObjInfo, ObjSectionKind, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
ObjSymbolKind,
@@ -189,189 +192,230 @@ const SIGNATURES: &[(&str, &str)] = &[
];
const POST_SIGNATURES: &[(&str, &str)] = &[
("RSOStaticLocateObject", include_str!("../../assets/signatures/RSOStaticLocateObject.yml")),
// ("GXInit", include_str!("../../assets/signatures/GXInit.yml")),
("GXInit", include_str!("../../assets/signatures/GXInit.yml")),
("__register_fragment", include_str!("../../assets/signatures/__register_fragment.yml")),
("__unregister_fragment", include_str!("../../assets/signatures/__unregister_fragment.yml")),
("__register_atexit", include_str!("../../assets/signatures/__register_atexit.yml")),
(
"__register_global_object",
include_str!("../../assets/signatures/__register_global_object.yml"),
),
];
fn apply_signature_for_symbol(obj: &mut ObjInfo, name: &str, sig_str: &str) -> Result<()> {
let Some((_, symbol)) = obj.symbols.by_name(name)? else {
return Ok(());
};
let Some(section_index) = symbol.section else {
return Ok(());
};
let addr = symbol.address as u32;
let section = &obj.sections[section_index];
if let Some(signature) = check_signatures_str(section, addr, sig_str)? {
apply_signature(obj, SectionAddress::new(section_index, addr), &signature)?;
}
Ok(())
}
fn apply_ctors_signatures(obj: &mut ObjInfo) -> Result<()> {
let Some((_, symbol)) = obj.symbols.by_name("_ctors")? else {
return Ok(());
};
// First entry of ctors is __init_cpp_exceptions
let ctors_section_index =
symbol.section.ok_or_else(|| anyhow!("Missing _ctors symbol section"))?;
let ctors_section = &obj.sections[ctors_section_index];
// __init_cpp_exceptions_reference + null pointer
if ctors_section.size < 8 {
return Ok(());
}
let Some(target) = read_address(obj, ctors_section, symbol.address as u32).ok() else {
return Ok(());
};
let Some(signature) = check_signatures_str(
&obj.sections[target.section],
target.address,
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
)?
else {
return Ok(());
};
let address = symbol.address;
apply_signature(obj, target, &signature)?;
obj.symbols.add(
ObjSymbol {
name: "__init_cpp_exceptions_reference".to_string(),
demangled_name: None,
address,
section: Some(ctors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
if obj.sections[ctors_section_index].splits.for_address(address as u32).is_none() {
obj.add_split(ctors_section_index, address as u32, ObjSplit {
unit: "__init_cpp_exceptions.cpp".to_string(),
end: address as u32 + 4,
align: None,
common: false,
autogenerated: true,
})?;
}
Ok(())
}
fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
let Some((_, symbol)) = obj.symbols.by_name("_dtors")? else {
for symbol in obj.symbols.iter() {
println!("{:?} {:#010X} {}", symbol.section, symbol.address, symbol.name);
}
bail!("Missing _dtors symbol");
// return Ok(());
};
let dtors_section_index =
symbol.section.ok_or_else(|| anyhow!("Missing _dtors symbol section"))?;
let dtors_section = &obj.sections[dtors_section_index];
// __destroy_global_chain_reference + null pointer
if dtors_section.size < 8 {
return Ok(());
}
let address = symbol.address;
let dgc_target = read_address(obj, dtors_section, address as u32).ok();
let fce_target = read_address(obj, dtors_section, address as u32 + 4).ok();
let mut found_dgc = false;
let mut found_fce = false;
// First entry of dtors is __destroy_global_chain
if let Some(dgc_target) = dgc_target {
if let Some(signature) = check_signatures_str(
&obj.sections[dgc_target.section],
dgc_target.address,
include_str!("../../assets/signatures/__destroy_global_chain.yml"),
)? {
apply_signature(obj, dgc_target, &signature)?;
obj.add_symbol(
ObjSymbol {
name: "__destroy_global_chain_reference".to_string(),
demangled_name: None,
address,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
found_dgc = true;
} else {
log::warn!("Failed to match __destroy_global_chain signature ({:#010X})", dgc_target);
}
}
// Second entry of dtors is __fini_cpp_exceptions
if let Some(fce_target) = fce_target {
if let Some(signature) = check_signatures_str(
&obj.sections[fce_target.section],
fce_target.address,
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
)? {
apply_signature(obj, fce_target, &signature)?;
obj.add_symbol(
ObjSymbol {
name: "__fini_cpp_exceptions_reference".to_string(),
demangled_name: None,
address: address + 4,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
found_fce = true;
}
}
if found_dgc {
let mut end = address as u32 + 4;
if found_fce {
end += 4;
}
if obj.sections[dtors_section_index].splits.for_address(address as u32).is_none() {
obj.add_split(dtors_section_index, address as u32, ObjSplit {
unit: "__init_cpp_exceptions.cpp".to_string(),
end,
align: None,
common: false,
autogenerated: true,
})?;
}
}
Ok(())
}
fn apply_init_user_signatures(obj: &mut ObjInfo) -> Result<()> {
let Some((_, symbol)) = obj.symbols.by_name("__init_user")? else {
return Ok(());
};
let Some(section_index) = symbol.section else {
return Ok(());
};
// __init_user can be overridden, but we can still look for __init_cpp from it
let mut analyzer = AnalyzerState::default();
analyzer.process_function_at(obj, SectionAddress::new(section_index, symbol.address as u32))?;
for addr in analyzer.function_entries {
let section = &obj.sections[addr.section];
if let Some(signature) = check_signatures_str(
section,
addr.address,
include_str!("../../assets/signatures/__init_cpp.yml"),
)? {
apply_signature(obj, SectionAddress::new(section_index, addr.address), &signature)?;
break;
}
}
Ok(())
}
pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
let entry = obj.entry as u32;
let (entry_section_index, entry_section) = obj.sections.at_address(entry)?;
if let Some(signature) = check_signatures_str(
entry_section,
entry,
include_str!("../../assets/signatures/__start.yml"),
)? {
apply_signature(obj, entry_section_index, entry, &signature)?;
if let Some(entry) = obj.entry.map(|n| n as u32) {
let (entry_section_index, entry_section) = obj.sections.at_address(entry)?;
if let Some(signature) = check_signatures_str(
entry_section,
entry,
include_str!("../../assets/signatures/__start.yml"),
)? {
apply_signature(obj, SectionAddress::new(entry_section_index, entry), &signature)?;
}
}
for &(name, sig_str) in SIGNATURES {
if let Some((_, symbol)) = obj.symbols.by_name(name)? {
let addr = symbol.address as u32;
let section_index =
symbol.section.ok_or_else(|| anyhow!("Symbol '{}' missing section", name))?;
let section = &obj.sections[section_index];
if let Some(signature) = check_signatures_str(section, addr, sig_str)? {
apply_signature(obj, section_index, addr, &signature)?;
}
}
}
if let Some((_, symbol)) = obj.symbols.by_name("__init_user")? {
// __init_user can be overridden, but we can still look for __init_cpp from it
let mut analyzer = AnalyzerState::default();
analyzer.process_function_at(obj, symbol.address as u32)?;
for addr in analyzer.function_entries {
let (section_index, section) = obj.sections.at_address(addr)?;
if let Some(signature) = check_signatures_str(
section,
addr,
include_str!("../../assets/signatures/__init_cpp.yml"),
)? {
apply_signature(obj, section_index, addr, &signature)?;
break;
}
}
}
if let Some((_, symbol)) = obj.symbols.by_name("_ctors")? {
// First entry of ctors is __init_cpp_exceptions
let ctors_section_index =
symbol.section.ok_or_else(|| anyhow!("Missing _ctors symbol section"))?;
let ctors_section = &obj.sections[ctors_section_index];
let target =
read_u32(&ctors_section.data, symbol.address as u32, ctors_section.address as u32)
.ok_or_else(|| anyhow!("Failed to read _ctors data"))?;
if target != 0 {
let (target_section_index, target_section) = obj.sections.at_address(target)?;
if let Some(signature) = check_signatures_str(
target_section,
target,
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
)? {
let address = symbol.address;
apply_signature(obj, target_section_index, target, &signature)?;
obj.symbols.add(
ObjSymbol {
name: "__init_cpp_exceptions_reference".to_string(),
demangled_name: None,
address,
section: Some(ctors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
if obj.sections[ctors_section_index].splits.for_address(address as u32).is_none() {
obj.add_split(ctors_section_index, address as u32, ObjSplit {
unit: "__init_cpp_exceptions.cpp".to_string(),
end: address as u32 + 4,
align: None,
common: false,
autogenerated: true,
})?;
}
}
}
}
if let Some((_, symbol)) = obj.symbols.by_name("_dtors")? {
let dtors_section_index =
symbol.section.ok_or_else(|| anyhow!("Missing _dtors symbol section"))?;
let dtors_section = &obj.sections[dtors_section_index];
let address = symbol.address;
let section_address = dtors_section.address;
// First entry of dtors is __destroy_global_chain
let dgc_target = read_u32(&dtors_section.data, address as u32, section_address as u32)
.ok_or_else(|| anyhow!("Failed to read _dtors data"))?;
let fce_target = read_u32(&dtors_section.data, address as u32 + 4, section_address as u32)
.ok_or_else(|| anyhow!("Failed to read _dtors data"))?;
let mut found_dgc = false;
let mut found_fce = false;
if dgc_target != 0 {
let (target_section_index, target_section) = obj.sections.at_address(dgc_target)?;
if let Some(signature) = check_signatures_str(
target_section,
dgc_target,
include_str!("../../assets/signatures/__destroy_global_chain.yml"),
)? {
apply_signature(obj, target_section_index, dgc_target, &signature)?;
obj.add_symbol(
ObjSymbol {
name: "__destroy_global_chain_reference".to_string(),
demangled_name: None,
address,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
found_dgc = true;
} else {
log::warn!(
"Failed to match __destroy_global_chain signature ({:#010X})",
dgc_target
);
}
}
// Second entry of dtors is __fini_cpp_exceptions
if fce_target != 0 {
let (target_section_index, target_section) = obj.sections.at_address(fce_target)?;
if let Some(signature) = check_signatures_str(
target_section,
fce_target,
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
)? {
apply_signature(obj, target_section_index, fce_target, &signature)?;
obj.add_symbol(
ObjSymbol {
name: "__fini_cpp_exceptions_reference".to_string(),
demangled_name: None,
address: address + 4,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
kind: ObjSymbolKind::Object,
align: None,
data_kind: Default::default(),
},
true,
)?;
found_fce = true;
}
}
if found_dgc {
let mut end = address as u32 + 4;
if found_fce {
end += 4;
}
if obj.sections[dtors_section_index].splits.for_address(address as u32).is_none() {
obj.add_split(dtors_section_index, address as u32, ObjSplit {
unit: "__init_cpp_exceptions.cpp".to_string(),
end,
align: None,
common: false,
autogenerated: true,
})?;
}
}
apply_signature_for_symbol(obj, name, sig_str)?
}
apply_init_user_signatures(obj)?;
apply_ctors_signatures(obj)?;
apply_dtors_signatures(obj)?;
Ok(())
}
pub fn apply_signatures_post(obj: &mut ObjInfo) -> Result<()> {
log::info!("Checking post CFA signatures...");
log::debug!("Checking post CFA signatures");
for &(_name, sig_str) in POST_SIGNATURES {
let signatures = parse_signatures(sig_str)?;
let mut found_signature = None;
@@ -391,13 +435,10 @@ pub fn apply_signatures_post(obj: &mut ObjInfo) -> Result<()> {
}
if let Some((symbol_index, signature)) = found_signature {
let symbol = &obj.symbols[symbol_index];
let section_index = symbol
.section
.ok_or_else(|| anyhow!("Symbol '{}' missing section", symbol.name))?;
let address = symbol.address as u32;
apply_signature(obj, section_index, address, &signature)?;
let symbol_addr = SectionAddress::new(symbol.section.unwrap(), symbol.address as u32);
apply_signature(obj, symbol_addr, &signature)?;
}
}
log::info!("Done!");
log::debug!("Done!");
Ok(())
}