feat: parse and display security info (M3)
Implement security info parsing including RSA signature, encrypted AES key, image/region/media flags, load address, SHA-1 digests, and page descriptors with section type classification. Add comprehensive unit and integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ use crate::header::Xex2Header;
|
||||
use crate::optional::{
|
||||
format_hex_bytes, format_rating, format_timestamp, HeaderKey, OptionalHeaders,
|
||||
};
|
||||
use crate::security::SecurityInfo;
|
||||
|
||||
/// Prints the XEX2 main header in a human-readable format.
|
||||
pub fn display_header(header: &Xex2Header) {
|
||||
@@ -200,3 +201,91 @@ pub fn display_optional_headers(headers: &OptionalHeaders) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the security info in a human-readable format.
|
||||
pub fn display_security_info(security: &SecurityInfo) {
|
||||
println!();
|
||||
println!("=== Security Info ===");
|
||||
println!(
|
||||
"Header Size: 0x{:08X} ({} bytes)",
|
||||
security.header_size, security.header_size
|
||||
);
|
||||
println!(
|
||||
"Image Size: 0x{:08X} ({} bytes)",
|
||||
security.image_size, security.image_size
|
||||
);
|
||||
|
||||
// RSA signature — show first 8 and last 8 bytes
|
||||
let sig = &security.rsa_signature;
|
||||
println!(
|
||||
"RSA Signature: {}...{} (256 bytes)",
|
||||
sig[..4].iter().map(|b| format!("{b:02X}")).collect::<String>(),
|
||||
sig[252..].iter().map(|b| format!("{b:02X}")).collect::<String>()
|
||||
);
|
||||
|
||||
println!("Unknown (0x108): 0x{:08X}", security.unk_108);
|
||||
println!("Image Flags: {}", security.image_flags);
|
||||
println!("Load Address: 0x{:08X}", security.load_address);
|
||||
println!(
|
||||
"Section Digest: {}",
|
||||
format_hex_bytes(&security.section_digest)
|
||||
);
|
||||
println!("Import Table Count: {}", security.import_table_count);
|
||||
println!(
|
||||
"Import Table Digest: {}",
|
||||
format_hex_bytes(&security.import_table_digest)
|
||||
);
|
||||
println!(
|
||||
"XGD2 Media ID: {}",
|
||||
security
|
||||
.xgd2_media_id
|
||||
.iter()
|
||||
.map(|b| format!("{b:02X}"))
|
||||
.collect::<String>()
|
||||
);
|
||||
println!(
|
||||
"AES Key (encrypted): {}",
|
||||
format_hex_bytes(&security.aes_key)
|
||||
);
|
||||
|
||||
if security.export_table == 0 {
|
||||
println!("Export Table: 0x00000000 (none)");
|
||||
} else {
|
||||
println!("Export Table: 0x{:08X}", security.export_table);
|
||||
}
|
||||
|
||||
println!(
|
||||
"Header Digest: {}",
|
||||
format_hex_bytes(&security.header_digest)
|
||||
);
|
||||
println!("Region: {}", security.region);
|
||||
println!("Allowed Media Types: {}", security.allowed_media_types);
|
||||
|
||||
// Page descriptors
|
||||
println!();
|
||||
let page_size = security.image_flags.page_size();
|
||||
let page_size_label = if page_size == 0x1000 { "4KB" } else { "64KB" };
|
||||
println!(
|
||||
"Page Descriptors ({} entries, {} pages):",
|
||||
security.page_descriptor_count, page_size_label
|
||||
);
|
||||
|
||||
let mut address_offset: u64 = 0;
|
||||
for (i, desc) in security.page_descriptors.iter().enumerate() {
|
||||
let digest_preview: String = desc.data_digest[..6]
|
||||
.iter()
|
||||
.map(|b| format!("{b:02X}"))
|
||||
.collect();
|
||||
let size = desc.page_count as u64 * page_size as u64;
|
||||
println!(
|
||||
" #{i:<4} {:<10} {:<4} pages ({:>8} bytes) offset +0x{address_offset:08X} SHA1: {digest_preview}...",
|
||||
desc.section_type.to_string(),
|
||||
desc.page_count,
|
||||
size
|
||||
);
|
||||
address_offset += size;
|
||||
}
|
||||
println!(
|
||||
" Total mapped size: 0x{address_offset:X} ({address_offset} bytes)"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user