add map layout feature for dex file
This commit is contained in:
parent
4b1cc379a4
commit
d991ac4dcd
8 changed files with 188 additions and 6 deletions
|
|
@ -7,3 +7,9 @@ license = "AGPL-3.0-or-later"
|
|||
[dependencies]
|
||||
androscalpel_serializer_derive = { path = "../androscalpel_serializer_derive" }
|
||||
log = "0.4.20"
|
||||
|
||||
[features]
|
||||
# Map sections of the binary dex file to the parsed value.
|
||||
# Aims to explore malformated / strange dex files, but slows
|
||||
# the parsing and consumes a lot of memory.
|
||||
map_dex_file = []
|
||||
|
|
|
|||
57
androscalpel_serializer/src/file_reader/map_dex_file.rs
Normal file
57
androscalpel_serializer/src/file_reader/map_dex_file.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//! Most of the logic for the map_dex_file feature.
|
||||
|
||||
use crate::DexFileReader;
|
||||
|
||||
impl<'a> DexFileReader<'a> {
|
||||
/// List the different structures of the dex file, in order of
|
||||
/// offset, including holes.
|
||||
pub fn get_chunks(&self) -> Vec<(u32, usize, String)> {
|
||||
let dex_size = self.data.len();
|
||||
let mut structs: Vec<_> = self
|
||||
.layout_map
|
||||
.lock()
|
||||
.expect("Failed to acquire mutex lock on layout_map")
|
||||
.iter()
|
||||
.map(|((off, size), desc)| (*off, *size, desc.clone()))
|
||||
.collect();
|
||||
structs.sort();
|
||||
let mut chunks = vec![];
|
||||
let mut last_off = 0;
|
||||
for (off, size, desc) in structs.into_iter() {
|
||||
if off > last_off {
|
||||
let size = (off - last_off) as usize;
|
||||
// ignore padding
|
||||
if (size < 4)
|
||||
&& self.data[last_off as usize..off as usize]
|
||||
.iter()
|
||||
.all(|&b| b == 0)
|
||||
{
|
||||
chunks.push((
|
||||
last_off,
|
||||
size,
|
||||
format!(
|
||||
"Padding: {:x?}",
|
||||
&self.data[last_off as usize..off as usize]
|
||||
),
|
||||
));
|
||||
} else {
|
||||
chunks.push((last_off, size, "Unreferenced Data".into()));
|
||||
}
|
||||
last_off = off;
|
||||
}
|
||||
// TODO: do something with overlapping struct?
|
||||
if off + size as u32 > last_off {
|
||||
last_off = off + size as u32;
|
||||
}
|
||||
chunks.push((off, size, desc));
|
||||
}
|
||||
if (last_off as usize) < dex_size {
|
||||
chunks.push((
|
||||
last_off,
|
||||
dex_size - last_off as usize,
|
||||
"Unreferenced Data".into(),
|
||||
));
|
||||
}
|
||||
chunks
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,12 @@ use log::{error, info, warn};
|
|||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
pub mod map_dex_file;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DexFileReader<'a> {
|
||||
// Ideally, this would be a Read+Seek, but Read+Seek is not thread safe, while we can
|
||||
|
|
@ -32,6 +38,8 @@ pub struct DexFileReader<'a> {
|
|||
method_handles: Vec<MethodHandleItem>,
|
||||
hiddenapi_class_data: Option<HiddenapiClassDataItem>,
|
||||
map_list: MapList,
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
layout_map: Mutex<HashMap<(u32, usize), String>>,
|
||||
}
|
||||
|
||||
impl<'a> DexFileReader<'a> {
|
||||
|
|
@ -53,7 +61,18 @@ impl<'a> DexFileReader<'a> {
|
|||
method_handles: vec![],
|
||||
hiddenapi_class_data: None,
|
||||
map_list: MapList { list: vec![] },
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
layout_map: Mutex::new(HashMap::new()),
|
||||
};
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
tmp_file
|
||||
.layout_map
|
||||
.lock()
|
||||
.expect("Failed to acquire mutex lock on layout_map")
|
||||
.insert(
|
||||
(0, tmp_file.header.size()),
|
||||
format!("{:x?}", tmp_file.header),
|
||||
);
|
||||
if tmp_file.header.map_off != 0 {
|
||||
tmp_file.map_list = tmp_file.get_struct_at_offset(tmp_file.header.map_off)?;
|
||||
}
|
||||
|
|
@ -381,7 +400,11 @@ impl<'a> DexFileReader<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_item_list<T: Serializable>(&self, offset: u32, size: u32) -> Result<Vec<T>> {
|
||||
fn get_item_list<T: Serializable + std::fmt::Debug>(
|
||||
&self,
|
||||
offset: u32,
|
||||
size: u32,
|
||||
) -> Result<Vec<T>> {
|
||||
if offset == 0 {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
|
@ -401,6 +424,17 @@ impl<'a> DexFileReader<'a> {
|
|||
pos
|
||||
))
|
||||
})?);
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
if let Some(ref item) = list.last() {
|
||||
let size = item.size();
|
||||
// Assume two != structs cannot be at the same offset with the same time
|
||||
// maybe add struct name to index?
|
||||
self.layout_map
|
||||
.lock()
|
||||
.expect("Failed to acquire mutex lock on layout_map")
|
||||
.entry((pos as u32, size))
|
||||
.or_insert_with(|| format!("{item:x?}"));
|
||||
}
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
|
|
@ -410,7 +444,10 @@ impl<'a> DexFileReader<'a> {
|
|||
/// # Warning
|
||||
///
|
||||
/// If the offset is invalid, UB.
|
||||
pub fn get_struct_at_offset<T: Serializable>(&self, offset: u32) -> Result<T> {
|
||||
pub fn get_struct_at_offset<T: Serializable + std::fmt::Debug>(
|
||||
&self,
|
||||
offset: u32,
|
||||
) -> Result<T> {
|
||||
let mut buffer = Cursor::new(self.data);
|
||||
buffer.seek(SeekFrom::Start(offset as u64)).unwrap();
|
||||
let r = T::deserialize(&mut buffer).map_err(|err| {
|
||||
|
|
@ -433,6 +470,17 @@ impl<'a> DexFileReader<'a> {
|
|||
buffer.position()
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "map_dex_file")]
|
||||
if let Ok(ref r) = r {
|
||||
let size = r.size();
|
||||
// Assume two != structs cannot be at the same offset with the same time
|
||||
// maybe add struct name to index?
|
||||
self.layout_map
|
||||
.lock()
|
||||
.expect("Failed to acquire mutex lock on layout_map")
|
||||
.entry((offset, size))
|
||||
.or_insert_with(|| format!("{r:x?}"));
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
|
@ -1,3 +1,16 @@
|
|||
//! This crate parse/write dalvik structures from binary to rust strucs.
|
||||
//! Those strucs are close to the binary representation and follow the dalvik as
|
||||
//! define by google: <https://source.android.com/docs/core/runtime/dex-format>
|
||||
//!
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! ### map_dex_file
|
||||
//!
|
||||
//! Map sections of the binary dex file to the parsed value.
|
||||
//! Aims to explore malformated / strange dex files, but slows
|
||||
//! the parsing and consumes a lot of memory.
|
||||
|
||||
pub mod annotation;
|
||||
pub mod array;
|
||||
pub mod consts;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue