generate HTML page to show dex layout

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2026-02-11 15:10:45 +01:00
parent d991ac4dcd
commit 4eae524e5f
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
3 changed files with 125 additions and 9 deletions

View file

@ -23,18 +23,14 @@ fn main() {
&cli.dex.into_os_string().into_string().unwrap(), &cli.dex.into_os_string().into_string().unwrap(),
&data, &data,
|_, _, _| None, |_, _, _| None,
false, true,
) )
.unwrap(); .unwrap();
//load_apk(File::open(&cli.apk).unwrap(), |_, _, _| None, false).unwrap(); //load_apk(File::open(&cli.apk).unwrap(), |_, _, _| None, false).unwrap();
for (name, dex) in &apk.dex_files { for (_name, dex) in &apk.dex_files {
println!("{name}:"); //println!("{name}:");
#[cfg(feature = "map_dex_file")] #[cfg(feature = "map_dex_file")]
for (off, size, dscr) in dex.layout_map.iter() { println!("{}", dex.html_layout())
let end = off + *size as u32;
let mut dscr = dscr.clone();
dscr.truncate(100);
println!("0x{off:x} -> 0x{end:x}: {dscr}");
}
} }
} }

View file

@ -25,6 +25,8 @@ pub mod visitor;
#[cfg(feature = "code-analysis")] #[cfg(feature = "code-analysis")]
pub mod code_analysis; pub mod code_analysis;
#[cfg(feature = "map_dex_file")]
pub mod map_dex_file;
pub use annotation::*; pub use annotation::*;
pub use apk::*; pub use apk::*;

View file

@ -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!("<td class=\"hex_offset\">{i:08x}</td>"));
current_line.push("<td class=\"hex_space\"></td>".to_string());
}
if i % 16 == 8 {
current_line.push("<td class=\"hex_space\"></td>".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!(
"<td class=\"{}\">{:02x}</td>",
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!(
" <tr>
{cells}
</tr>
"
))
}
}
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!(
"<pre class=\"dex_dscr dscr_{classname}\"><code>{dscr}</code></pre>"
))
}
let chunk_style = chunk_style_lines.join("\n ");
let data = data_lines.join("\n ");
format!(
"<html>
<head>
<title>DEX layout</title>
<style>
{STYLE}
{chunk_style}
</style>
</head>
<body>
<table class=\"hex_table\">
{table}
</table>
<div class=\"dex_dscr_container\">
{data}
</div>
</body>
</html>"
)
}
}