add support for read hiddenapi

This commit is contained in:
Jean-Marie Mineau 2024-06-10 18:20:45 +02:00
parent df9d258780
commit 437ecbeecc
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
17 changed files with 764 additions and 92 deletions

View file

@ -1,9 +1,9 @@
//! Parser for a .dex file.
use crate::{
CallSiteIdItem, ClassDefItem, EndianConstant, Error, FieldIdItem, HeaderItem, MapItemType,
MapList, MethodHandleItem, MethodIdItem, ProtoIdItem, Result, Serializable, StringDataItem,
StringIdItem, TypeIdItem,
CallSiteIdItem, ClassDataItem, ClassDefItem, EndianConstant, Error, FieldIdItem, HeaderItem,
HiddenApiFlags, HiddenapiClassDataItem, MapItemType, MapList, MethodHandleItem, MethodIdItem,
ProtoIdItem, Result, Serializable, StringDataItem, StringIdItem, TypeIdItem,
};
use log::{error, info, warn};
use std::io::{Cursor, Seek, SeekFrom};
@ -28,6 +28,7 @@ pub struct DexFileReader<'a> {
class_defs: Vec<ClassDefItem>,
call_site_ids: Vec<CallSiteIdItem>,
method_handles: Vec<MethodHandleItem>,
hiddenapi_class_data: Option<HiddenapiClassDataItem>,
map_list: MapList,
}
@ -48,6 +49,7 @@ impl<'a> DexFileReader<'a> {
class_defs: vec![],
call_site_ids: vec![],
method_handles: vec![],
hiddenapi_class_data: None,
map_list: MapList { list: vec![] },
};
if tmp_file.header.map_off != 0 {
@ -99,6 +101,15 @@ impl<'a> DexFileReader<'a> {
tmp_file.method_handles =
tmp_file.get_item_list::<MethodHandleItem>(item.offset, item.size)?
}
if let Some(item) = tmp_file
.map_list
.list
.iter()
.find(|item| item.type_ == MapItemType::HiddenapiClassDataItem)
{
tmp_file.hiddenapi_class_data =
Some(tmp_file.get_struct_at_offset::<HiddenapiClassDataItem>(item.offset)?);
}
tmp_file.sanity_check()?;
Ok(tmp_file)
}
@ -107,39 +118,39 @@ impl<'a> DexFileReader<'a> {
pub fn get_header(&self) -> &HeaderItem {
&self.header
}
/// Retunr the file [`StringIdItem`] list.
/// Return the file [`StringIdItem`] list.
pub fn get_string_ids(&self) -> &[StringIdItem] {
&self.string_ids
}
/// Retunr the file [`TypeIdItem`] list.
/// Return the file [`TypeIdItem`] list.
pub fn get_type_ids(&self) -> &[TypeIdItem] {
&self.type_ids
}
/// Retunr the file [`ProtoIdItem`] list.
/// Return the file [`ProtoIdItem`] list.
pub fn get_proto_ids(&self) -> &[ProtoIdItem] {
&self.proto_ids
}
/// Retunr the file [`FieldIdItem`] list.
/// Return the file [`FieldIdItem`] list.
pub fn get_field_ids(&self) -> &[FieldIdItem] {
&self.field_ids
}
/// Retunr the file [`MethodIdItem`] list.
/// Return the file [`MethodIdItem`] list.
pub fn get_method_ids(&self) -> &[MethodIdItem] {
&self.method_ids
}
/// Retunr the file [`ClassDefItem`] list.
/// Return the file [`ClassDefItem`] list.
pub fn get_class_defs(&self) -> &[ClassDefItem] {
&self.class_defs
}
/// Retunr the file [`CallSiteIdItem`] list.
/// Return the file [`CallSiteIdItem`] list.
pub fn get_call_site_ids(&self) -> &[CallSiteIdItem] {
&self.call_site_ids
}
/// Retunr the file [`MethodHandleItem`] list.
/// Return the file [`MethodHandleItem`] list.
pub fn get_method_handles(&self) -> &[MethodHandleItem] {
&self.method_handles
}
/// Retunr the file [`MapList`].
/// Return the file [`MapList`].
pub fn get_map_list(&self) -> &MapList {
&self.map_list
}
@ -421,6 +432,45 @@ impl<'a> DexFileReader<'a> {
r
}
/// Return the hiddenapi flags list for the given class.
///
/// The list of flags is composed of one [`HiddenApiFlags`] for each static field, instance
/// field, direct method and virtual method of the class, in that order.
///
/// `class_def_item_idx` if the idx of the `class_def_item`, **not** the `class_idx` (contrary
/// to what <https://source.android.com/docs/core/runtime/dex-format#hiddenapi-class-data-item>
/// says)
pub fn get_class_hiddenapi_flags(
&self,
class_def_item_idx: usize,
) -> Result<Option<Vec<HiddenApiFlags>>> {
if class_def_item_idx >= self.class_defs.len() {
return Err(Error::InconsistantStruct(format!(
"idx 0x{class_def_item_idx:x} is out of bound of class_defs"
)));
}
let class_def = self.class_defs[class_def_item_idx];
if class_def.class_data_off == 0 {
if self.hiddenapi_class_data.is_some() {
return Ok(Some(vec![]));
} else {
return Ok(None);
}
}
let class_data = self.get_struct_at_offset::<ClassDataItem>(class_def.class_data_off)?;
let nb_flags = class_data.static_fields.len()
+ class_data.instance_fields.len()
+ class_data.direct_methods.len()
+ class_data.virtual_methods.len();
if let Some(hidden_api_data) = &self.hiddenapi_class_data {
hidden_api_data
.get_flags(nb_flags, class_def_item_idx)
.map(Some)
} else {
Ok(None)
}
}
/// Return the strings that where not referenced.
pub fn get_not_resolved_strings(&mut self) -> Result<Vec<StringDataItem>> {
// use `&mut self` because using this method at the same time as performing