From 4eae524e5ffdd7b0c1e7f04b637421a2a916be4a Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Wed, 11 Feb 2026 15:10:45 +0100 Subject: [PATCH] generate HTML page to show dex layout --- androscalpel/examples/map_layout.rs | 14 ++-- androscalpel/src/lib.rs | 2 + androscalpel/src/map_dex_file.rs | 118 ++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 androscalpel/src/map_dex_file.rs diff --git a/androscalpel/examples/map_layout.rs b/androscalpel/examples/map_layout.rs index 49291d7..88830f5 100644 --- a/androscalpel/examples/map_layout.rs +++ b/androscalpel/examples/map_layout.rs @@ -23,18 +23,14 @@ fn main() { &cli.dex.into_os_string().into_string().unwrap(), &data, |_, _, _| None, - false, + true, ) .unwrap(); //load_apk(File::open(&cli.apk).unwrap(), |_, _, _| None, false).unwrap(); - for (name, dex) in &apk.dex_files { - println!("{name}:"); + for (_name, dex) in &apk.dex_files { + //println!("{name}:"); + #[cfg(feature = "map_dex_file")] - for (off, size, dscr) in dex.layout_map.iter() { - let end = off + *size as u32; - let mut dscr = dscr.clone(); - dscr.truncate(100); - println!("0x{off:x} -> 0x{end:x}: {dscr}"); - } + println!("{}", dex.html_layout()) } } diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index f23e96d..5eb3f67 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -25,6 +25,8 @@ pub mod visitor; #[cfg(feature = "code-analysis")] pub mod code_analysis; +#[cfg(feature = "map_dex_file")] +pub mod map_dex_file; pub use annotation::*; pub use apk::*; diff --git a/androscalpel/src/map_dex_file.rs b/androscalpel/src/map_dex_file.rs new file mode 100644 index 0000000..9302c53 --- /dev/null +++ b/androscalpel/src/map_dex_file.rs @@ -0,0 +1,118 @@ +use crate::DexFile; + +static STYLE: &'static str = " +.hex_table { + border-collapse: collapse; + border: 1px solid grey; + + font-family: monospace; + padding: 1em; +} +.hex_offset { + background: #A2A2A2; + padding-right: 0; +} +.hex_space { + //padding-right: 1em; + padding-left: 1em; +} +.dex_dscr { + display: none; +} +.dex_dscr_container { + position: fixed; + display: block; + left: 25em; + top: 0px; +} +"; + +impl DexFile { + pub fn html_layout(&self) -> String { + assert!( + self.bin_cache.is_some(), + "cache must not be none to display layout" + ); + let mut lines = vec![]; + let mut current_line = vec![]; + let raw = self.bin_cache.as_ref().unwrap(); + let mut current_chunk = 0; + for i in 0..(raw.len() as u32) { + // We assumes that chunks are sorted by offset and non overlapping + while !((self.layout_map[current_chunk].0 <= i) + && (i < self.layout_map[current_chunk].0 + self.layout_map[current_chunk].1 as u32)) + && self.layout_map[current_chunk].0 <= i + { + current_chunk += 1; + } + let in_chunk = (self.layout_map[current_chunk].0 <= i) + && (i < self.layout_map[current_chunk].0 + self.layout_map[current_chunk].1 as u32); + if i % 16 == 0 { + current_line.push(format!("{i:08x}")); + current_line.push("".to_string()); + } + if i % 16 == 8 { + current_line.push("".to_string()); + } + let mut classes = vec!["hex_cel".to_string()]; + if in_chunk { + classes.push(format!( + "chunk_{}_{}", + self.layout_map[current_chunk].0, self.layout_map[current_chunk].1 + )); + } + current_line.push(format!( + "{:02x}", + classes.join(" "), + raw[i as usize] + )); + if (i % 16 == 15) || (i == raw.len() as u32 - 1) { + let cells = current_line.join("\n "); + current_line = vec![]; + lines.push(format!( + " + {cells} + +" + )) + } + } + let table = lines.join("\n"); + let mut chunk_style_lines = vec![]; + let mut data_lines = vec![]; + for (off, size, dscr) in &self.layout_map { + let classname = format!("chunk_{off}_{size}"); + chunk_style_lines.push(format!( + "html:has(.{classname}:hover) .{classname} {{ background-color: yellow; }}" + )); + chunk_style_lines.push(format!( + "html:has(.{classname}:hover) .dscr_{classname} {{ display: block; }}" + )); + data_lines.push(format!( + "
{dscr}
" + )) + } + let chunk_style = chunk_style_lines.join("\n "); + let data = data_lines.join("\n "); + + format!( + " + + DEX layout + + + + +{table} +
+
+ {data} +
+ +" + ) + } +}