feat: add export database and import record decoding (M7)

- New src/exports.rs: embeds doc/xbox360_exports.md via include_str!
  and lazily parses it into a lookup table (OnceLock). Covers 2,913
  exports across xboxkrnl.exe, xam.xex, and xbdm.xex.
- New src/imports.rs: decodes import records from extracted PE images
  by reading the u32 at each import address, extracting record type
  (variable/thunk) and ordinal, and resolving against the export DB.
- inspect command now shows a full resolved imports table with names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-03-29 17:32:49 +02:00
parent dee636c09f
commit 0d42fc1b06
8 changed files with 514 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
/// Pretty-print formatting for parsed XEX2 structures.
use crate::crypto;
use crate::header::Xex2Header;
use crate::imports::ResolvedImport;
use crate::optional::{
format_hex_bytes, format_rating, format_timestamp, CompressionInfo, HeaderKey, OptionalHeaders,
};
@@ -314,3 +315,44 @@ pub fn display_security_info(security: &SecurityInfo) {
" Total mapped size: 0x{address_offset:X} ({address_offset} bytes)"
);
}
/// Prints resolved import records grouped by library.
pub fn display_resolved_imports(imports: &[ResolvedImport]) {
// Count per library
let mut lib_counts: Vec<(String, usize)> = Vec::new();
for imp in imports {
if let Some(entry) = lib_counts.iter_mut().find(|(name, _)| *name == imp.library) {
entry.1 += 1;
} else {
lib_counts.push((imp.library.clone(), 1));
}
}
let summary: Vec<String> = lib_counts
.iter()
.map(|(name, count)| format!("{name}: {count}"))
.collect();
println!();
println!(
"=== Resolved Imports ({}) ===",
summary.join(", ")
);
let mut current_lib = "";
for imp in imports {
if imp.library != current_lib {
println!();
println!(" [{}]", imp.library);
current_lib = &imp.library;
}
let name = imp
.export
.as_ref()
.map_or("<unknown>", |e| &e.name);
println!(
" 0x{:08X} {:>8} ordinal 0x{:04X} {}",
imp.record.address, imp.record.record_type, imp.record.ordinal, name
);
}
}