check classloader string representation
This commit is contained in:
parent
566b423c6b
commit
59d6caabd8
5 changed files with 194 additions and 14 deletions
|
|
@ -4,6 +4,7 @@ use std::fs::File;
|
||||||
use androscalpel::{Apk, DexString, IdType, VisitorMut};
|
use androscalpel::{Apk, DexString, IdType, VisitorMut};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
|
use log::{debug, info};
|
||||||
|
|
||||||
use crate::dex_types::DELEGATE_LAST_CLASS_LOADER;
|
use crate::dex_types::DELEGATE_LAST_CLASS_LOADER;
|
||||||
use crate::runtime_data::RuntimeData;
|
use crate::runtime_data::RuntimeData;
|
||||||
|
|
@ -262,9 +263,9 @@ impl ClassLoader<'_> {
|
||||||
};
|
};
|
||||||
let new_name = loop {
|
let new_name = loop {
|
||||||
let prefix: DexString = if i == 0 {
|
let prefix: DexString = if i == 0 {
|
||||||
format!("theseus-dedup/{}/", self.id).into()
|
format!("theseus/dedup/{}/", self.id).into()
|
||||||
} else {
|
} else {
|
||||||
format!("theseus-dedup/{}-{i}/", self.id).into()
|
format!("theseus/dedup/{}/{i}/", self.id).into()
|
||||||
};
|
};
|
||||||
let new_name = IdType::class_from_dex_string(&prefix.concatenate(&name));
|
let new_name = IdType::class_from_dex_string(&prefix.concatenate(&name));
|
||||||
if self.apk().get_class(&new_name).is_none() {
|
if self.apk().get_class(&new_name).is_none() {
|
||||||
|
|
@ -305,9 +306,9 @@ impl ClassLoader<'_> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
println!("rename for {}", self.id);
|
info!("types rename for {}", self.id);
|
||||||
for (old, new) in &r {
|
for (old, new) in &r {
|
||||||
println!(" {} -> {}", old.__str__(), new.__str__());
|
info!(" {} -> {}", old.__str__(), new.__str__());
|
||||||
}
|
}
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
@ -326,18 +327,42 @@ impl ClassLoader<'_> {
|
||||||
) -> Option<IdType> {
|
) -> Option<IdType> {
|
||||||
if ty.is_platform_class() {
|
if ty.is_platform_class() {
|
||||||
// Platform classes have precedence for all android SDK classloader.
|
// Platform classes have precedence for all android SDK classloader.
|
||||||
|
debug!("Class {} is a platform class, no renaming", ty.__str__());
|
||||||
return Some(ty.clone());
|
return Some(ty.clone());
|
||||||
}
|
}
|
||||||
if self.class == *DELEGATE_LAST_CLASS_LOADER {
|
if self.class == *DELEGATE_LAST_CLASS_LOADER {
|
||||||
if let Some(new_ty) = self.renamed_classes.get(ty) {
|
if let Some(new_ty) = self.renamed_classes.get(ty) {
|
||||||
|
debug!(
|
||||||
|
"Class {} found in {} ({}) in renamed class before delagation, use name {}",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id,
|
||||||
|
new_ty.__str__()
|
||||||
|
);
|
||||||
return Some(new_ty.clone());
|
return Some(new_ty.clone());
|
||||||
} else if self.apk().get_class(ty).is_some() {
|
} else if self.apk().get_class(ty).is_some() {
|
||||||
|
debug!(
|
||||||
|
"Class {} found in {} ({}) in unique classes before delagation, use name {}",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id,
|
||||||
|
ty.__str__()
|
||||||
|
);
|
||||||
return Some(ty.clone());
|
return Some(ty.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref parent_id) = self.parent {
|
if let Some(ref parent_id) = self.parent {
|
||||||
if let Some(parent) = class_loaders.get(parent_id) {
|
if let Some(parent) = class_loaders.get(parent_id) {
|
||||||
if let Some(new_ty) = parent.get_ref_new_name(ty, class_loaders) {
|
if let Some(new_ty) = parent.get_ref_new_name(ty, class_loaders) {
|
||||||
|
debug!(
|
||||||
|
"Class {} found by delegating to parent ({}) \
|
||||||
|
of {}({}), use name {}",
|
||||||
|
ty.__str__(),
|
||||||
|
parent_id,
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id,
|
||||||
|
new_ty.__str__()
|
||||||
|
);
|
||||||
return Some(new_ty);
|
return Some(new_ty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -350,13 +375,39 @@ impl ClassLoader<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.class == *DELEGATE_LAST_CLASS_LOADER {
|
if self.class == *DELEGATE_LAST_CLASS_LOADER {
|
||||||
|
debug!(
|
||||||
|
"Class {} not found by {}({})",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(new_ty) = self.renamed_classes.get(ty) {
|
if let Some(new_ty) = self.renamed_classes.get(ty) {
|
||||||
|
debug!(
|
||||||
|
"Class {} found in {} ({}) in renamed class after delagation, use name {}",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id,
|
||||||
|
new_ty.__str__()
|
||||||
|
);
|
||||||
Some(new_ty.clone())
|
Some(new_ty.clone())
|
||||||
} else if self.apk().get_class(ty).is_some() {
|
} else if self.apk().get_class(ty).is_some() {
|
||||||
|
debug!(
|
||||||
|
"Class {} found in {} ({}) in unique classes after delagation, use name {}",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id,
|
||||||
|
ty.__str__()
|
||||||
|
);
|
||||||
Some(ty.clone())
|
Some(ty.clone())
|
||||||
} else {
|
} else {
|
||||||
|
debug!(
|
||||||
|
"Class {} not found by {}({})",
|
||||||
|
ty.__str__(),
|
||||||
|
self.class.__str__(),
|
||||||
|
self.id
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use androscalpel::{IdMethod, IdType};
|
use androscalpel::{IdMethod, IdType};
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{bail, Result};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub(crate) static MTH_INVOKE: LazyLock<IdMethod> = LazyLock::new(|| {
|
pub(crate) static MTH_INVOKE: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
|
|
@ -99,6 +99,12 @@ pub(crate) static SCAL_TO_OBJ_FLOAT: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
pub(crate) static SCAL_TO_OBJ_DOUBLE: LazyLock<IdMethod> = LazyLock::new(|| {
|
pub(crate) static SCAL_TO_OBJ_DOUBLE: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
IdMethod::from_smali("Ljava/lang/Double;->valueOf(D)Ljava/lang/Double;").unwrap()
|
IdMethod::from_smali("Ljava/lang/Double;->valueOf(D)Ljava/lang/Double;").unwrap()
|
||||||
});
|
});
|
||||||
|
pub(crate) static GET_CLASS_LOADER: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
|
IdMethod::from_smali("Ljava/lang/Class;->getClassLoader()Ljava/lang/ClassLoader;").unwrap()
|
||||||
|
});
|
||||||
|
pub(crate) static TO_STRING: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
|
IdMethod::from_smali("Ljava/lang/Object;->toString()Ljava/lang/String;").unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
pub(crate) static OBJECT_TY: LazyLock<IdType> =
|
pub(crate) static OBJECT_TY: LazyLock<IdType> =
|
||||||
LazyLock::new(|| IdType::from_smali("Ljava/lang/Object;").unwrap());
|
LazyLock::new(|| IdType::from_smali("Ljava/lang/Object;").unwrap());
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ pub fn transform_method(
|
||||||
let invoke_data = ref_data.get_invoke_data_for(&meth.descriptor);
|
let invoke_data = ref_data.get_invoke_data_for(&meth.descriptor);
|
||||||
let class_new_inst_data = ref_data.get_class_new_instance_data_for(&meth.descriptor);
|
let class_new_inst_data = ref_data.get_class_new_instance_data_for(&meth.descriptor);
|
||||||
let cnstr_new_inst_data = ref_data.get_cnstr_new_instance_data_for(&meth.descriptor);
|
let cnstr_new_inst_data = ref_data.get_cnstr_new_instance_data_for(&meth.descriptor);
|
||||||
|
let classloaders = ref_data.get_classloader_data();
|
||||||
|
|
||||||
let code = meth
|
let code = meth
|
||||||
.code
|
.code
|
||||||
|
|
@ -189,6 +190,7 @@ pub fn transform_method(
|
||||||
move_ret.clone(),
|
move_ret.clone(),
|
||||||
tester_methods_class.clone(),
|
tester_methods_class.clone(),
|
||||||
tester_methods,
|
tester_methods,
|
||||||
|
&classloaders,
|
||||||
)? {
|
)? {
|
||||||
new_insns.push(ins);
|
new_insns.push(ins);
|
||||||
}
|
}
|
||||||
|
|
@ -227,6 +229,7 @@ pub fn transform_method(
|
||||||
move_ret.clone(),
|
move_ret.clone(),
|
||||||
tester_methods_class.clone(),
|
tester_methods_class.clone(),
|
||||||
tester_methods,
|
tester_methods,
|
||||||
|
&classloaders,
|
||||||
)? {
|
)? {
|
||||||
new_insns.push(ins);
|
new_insns.push(ins);
|
||||||
}
|
}
|
||||||
|
|
@ -337,8 +340,14 @@ fn gen_tester_method(
|
||||||
tester_methods_class: IdType,
|
tester_methods_class: IdType,
|
||||||
method_to_test: IdMethod,
|
method_to_test: IdMethod,
|
||||||
is_constructor: bool,
|
is_constructor: bool,
|
||||||
|
classloader: Option<&ClassLoaderData>,
|
||||||
) -> Result<Method> {
|
) -> Result<Method> {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
|
if let Some(classloader) = classloader {
|
||||||
|
classloader.id.hash(&mut hasher);
|
||||||
|
} else {
|
||||||
|
"00000000".hash(&mut hasher);
|
||||||
|
}
|
||||||
method_to_test.hash(&mut hasher);
|
method_to_test.hash(&mut hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
let m_name: String = (&method_to_test.name).try_into()?;
|
let m_name: String = (&method_to_test.name).try_into()?;
|
||||||
|
|
@ -522,20 +531,70 @@ fn gen_tester_method(
|
||||||
// b: reg_arr_val,
|
// b: reg_arr_val,
|
||||||
// label: no_label.clone(),
|
// label: no_label.clone(),
|
||||||
//},
|
//},
|
||||||
// Check Declaring Type
|
|
||||||
Instruction::InvokeVirtual {
|
|
||||||
method: MTH_GET_DEC_CLS.clone(),
|
|
||||||
args: vec![reg_ref_method],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
// Get Declaring Type
|
||||||
if is_constructor {
|
if is_constructor {
|
||||||
// Check Declaring Type
|
|
||||||
insns.push(Instruction::InvokeVirtual {
|
insns.push(Instruction::InvokeVirtual {
|
||||||
method: CNSTR_GET_DEC_CLS.clone(),
|
method: CNSTR_GET_DEC_CLS.clone(),
|
||||||
args: vec![reg_ref_method],
|
args: vec![reg_ref_method],
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
insns.push(Instruction::InvokeVirtual {
|
||||||
|
method: MTH_GET_DEC_CLS.clone(),
|
||||||
|
args: vec![reg_ref_method],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
//Check the classloader
|
||||||
|
if let Some(classloader) = classloader {
|
||||||
|
insns.append(&mut vec![
|
||||||
|
// Get the string representation of the classloader.
|
||||||
|
// Not the ideal, but best cross execution classloader identifier we have.
|
||||||
|
Instruction::MoveResultObject {
|
||||||
|
to: reg_arr_idx, // wrong name, but available for tmp val
|
||||||
|
},
|
||||||
|
Instruction::InvokeVirtual {
|
||||||
|
method: GET_CLASS_LOADER.clone(),
|
||||||
|
args: vec![reg_arr_idx as u16],
|
||||||
|
},
|
||||||
|
Instruction::MoveResultObject { to: reg_arr_idx },
|
||||||
|
Instruction::InvokeVirtual {
|
||||||
|
method: TO_STRING.clone(),
|
||||||
|
args: vec![reg_arr_idx as u16],
|
||||||
|
},
|
||||||
|
Instruction::MoveResultObject {
|
||||||
|
to: reg_arr_idx, // wrong name, but available for tmp val
|
||||||
|
},
|
||||||
|
Instruction::ConstString {
|
||||||
|
reg: reg_arr_val,
|
||||||
|
lit: classloader.string_representation.as_str().into(),
|
||||||
|
},
|
||||||
|
Instruction::InvokeVirtual {
|
||||||
|
method: STR_EQ.clone(),
|
||||||
|
args: vec![reg_arr_idx as u16, reg_arr_val as u16],
|
||||||
|
},
|
||||||
|
Instruction::MoveResult {
|
||||||
|
to: reg_arr_idx, // wrong name, but available for tmp val
|
||||||
|
},
|
||||||
|
Instruction::IfEqZ {
|
||||||
|
a: reg_arr_idx,
|
||||||
|
label: no_label.clone(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// Get Declaring Type
|
||||||
|
if is_constructor {
|
||||||
|
insns.push(Instruction::InvokeVirtual {
|
||||||
|
method: CNSTR_GET_DEC_CLS.clone(),
|
||||||
|
args: vec![reg_ref_method],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
insns.push(Instruction::InvokeVirtual {
|
||||||
|
method: MTH_GET_DEC_CLS.clone(),
|
||||||
|
args: vec![reg_ref_method],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check Declaring Type
|
||||||
insns.append(&mut vec![
|
insns.append(&mut vec![
|
||||||
Instruction::MoveResultObject {
|
Instruction::MoveResultObject {
|
||||||
to: reg_arr_idx, // wrong name, but available for tmp val
|
to: reg_arr_idx, // wrong name, but available for tmp val
|
||||||
|
|
@ -604,6 +663,10 @@ fn gen_tester_method(
|
||||||
/// - `tester_methods`: the methods used to test if a `java.lang.reflect.Method` is a specific method.
|
/// - `tester_methods`: the methods used to test if a `java.lang.reflect.Method` is a specific method.
|
||||||
/// Methods are indexed by the IdMethod they detect, and have a name derived from the method
|
/// Methods are indexed by the IdMethod they detect, and have a name derived from the method
|
||||||
/// they detect.
|
/// they detect.
|
||||||
|
/// - `classloader`: is the runtime data of the classloader that loaded the class defining the
|
||||||
|
/// reflected method. If None, the classloader is not tested. Platform classes should probably
|
||||||
|
/// not be tested (the bootclassloader can be represented with a null reference, which may
|
||||||
|
/// lead to a null pointer exception).
|
||||||
fn test_method(
|
fn test_method(
|
||||||
method_obj_reg: u16,
|
method_obj_reg: u16,
|
||||||
id_method: IdMethod,
|
id_method: IdMethod,
|
||||||
|
|
@ -611,11 +674,17 @@ fn test_method(
|
||||||
reg_inf: &mut RegistersInfo,
|
reg_inf: &mut RegistersInfo,
|
||||||
tester_methods_class: IdType,
|
tester_methods_class: IdType,
|
||||||
tester_methods: &mut HashMap<IdMethod, Method>,
|
tester_methods: &mut HashMap<IdMethod, Method>,
|
||||||
|
classloader: Option<&ClassLoaderData>,
|
||||||
) -> Result<Vec<Instruction>> {
|
) -> Result<Vec<Instruction>> {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
let tst_descriptor = match tester_methods.entry(id_method.clone()) {
|
let tst_descriptor = match tester_methods.entry(id_method.clone()) {
|
||||||
Entry::Occupied(e) => e.into_mut(),
|
Entry::Occupied(e) => e.into_mut(),
|
||||||
Entry::Vacant(e) => e.insert(gen_tester_method(tester_methods_class, id_method, false)?),
|
Entry::Vacant(e) => e.insert(gen_tester_method(
|
||||||
|
tester_methods_class,
|
||||||
|
id_method,
|
||||||
|
false,
|
||||||
|
classloader,
|
||||||
|
)?),
|
||||||
}
|
}
|
||||||
.descriptor
|
.descriptor
|
||||||
.clone();
|
.clone();
|
||||||
|
|
@ -658,6 +727,7 @@ fn get_move_result<'a>(
|
||||||
(vec![], None)
|
(vec![], None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn get_invoke_block(
|
fn get_invoke_block(
|
||||||
ref_data: &ReflectionInvokeData,
|
ref_data: &ReflectionInvokeData,
|
||||||
invoke_arg: &[u16],
|
invoke_arg: &[u16],
|
||||||
|
|
@ -666,6 +736,7 @@ fn get_invoke_block(
|
||||||
move_result: Option<Instruction>,
|
move_result: Option<Instruction>,
|
||||||
tester_methods_class: IdType,
|
tester_methods_class: IdType,
|
||||||
tester_methods: &mut HashMap<IdMethod, Method>,
|
tester_methods: &mut HashMap<IdMethod, Method>,
|
||||||
|
classloaders: &HashMap<String, ClassLoaderData>,
|
||||||
) -> Result<Vec<Instruction>> {
|
) -> Result<Vec<Instruction>> {
|
||||||
let (method_obj, obj_inst, arg_arr) = if let &[a, b, c] = invoke_arg {
|
let (method_obj, obj_inst, arg_arr) = if let &[a, b, c] = invoke_arg {
|
||||||
(a, b, c)
|
(a, b, c)
|
||||||
|
|
@ -691,6 +762,11 @@ fn get_invoke_block(
|
||||||
ref_data.method.try_to_smali()?,
|
ref_data.method.try_to_smali()?,
|
||||||
ref_data.addr
|
ref_data.addr
|
||||||
);
|
);
|
||||||
|
let classloader = if ref_data.method.class_.is_platform_class() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
classloaders.get(&ref_data.method_cl_id)
|
||||||
|
};
|
||||||
let mut insns = test_method(
|
let mut insns = test_method(
|
||||||
method_obj,
|
method_obj,
|
||||||
ref_data.method.clone(),
|
ref_data.method.clone(),
|
||||||
|
|
@ -698,6 +774,7 @@ fn get_invoke_block(
|
||||||
reg_inf,
|
reg_inf,
|
||||||
tester_methods_class,
|
tester_methods_class,
|
||||||
tester_methods,
|
tester_methods,
|
||||||
|
classloader,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !ref_data.is_static {
|
if !ref_data.is_static {
|
||||||
|
|
@ -868,6 +945,7 @@ fn get_args_from_obj_arr(
|
||||||
insns
|
insns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn get_cnstr_new_inst_block(
|
fn get_cnstr_new_inst_block(
|
||||||
ref_data: &ReflectionCnstrNewInstData,
|
ref_data: &ReflectionCnstrNewInstData,
|
||||||
invoke_arg: &[u16],
|
invoke_arg: &[u16],
|
||||||
|
|
@ -876,6 +954,7 @@ fn get_cnstr_new_inst_block(
|
||||||
move_result: Option<Instruction>,
|
move_result: Option<Instruction>,
|
||||||
tester_methods_class: IdType,
|
tester_methods_class: IdType,
|
||||||
tester_methods: &mut HashMap<IdMethod, Method>,
|
tester_methods: &mut HashMap<IdMethod, Method>,
|
||||||
|
classloaders: &HashMap<String, ClassLoaderData>,
|
||||||
) -> Result<Vec<Instruction>> {
|
) -> Result<Vec<Instruction>> {
|
||||||
let (cnst_reg, arg_arr) = if let &[a, b] = invoke_arg {
|
let (cnst_reg, arg_arr) = if let &[a, b] = invoke_arg {
|
||||||
(a, b)
|
(a, b)
|
||||||
|
|
@ -897,6 +976,11 @@ fn get_cnstr_new_inst_block(
|
||||||
ref_data.addr
|
ref_data.addr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let classloader = if ref_data.constructor.class_.is_platform_class() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
classloaders.get(&ref_data.constructor_cl_id)
|
||||||
|
};
|
||||||
let mut insns = test_cnstr(
|
let mut insns = test_cnstr(
|
||||||
cnst_reg,
|
cnst_reg,
|
||||||
ref_data.constructor.clone(), // TODO: what if args are renammed?
|
ref_data.constructor.clone(), // TODO: what if args are renammed?
|
||||||
|
|
@ -904,6 +988,7 @@ fn get_cnstr_new_inst_block(
|
||||||
reg_inf,
|
reg_inf,
|
||||||
tester_methods_class,
|
tester_methods_class,
|
||||||
tester_methods,
|
tester_methods,
|
||||||
|
classloader,
|
||||||
)?;
|
)?;
|
||||||
insns.append(&mut get_args_from_obj_arr(
|
insns.append(&mut get_args_from_obj_arr(
|
||||||
&ref_data.constructor.proto.get_parameters(), // TODO: what if args are renammed?
|
&ref_data.constructor.proto.get_parameters(), // TODO: what if args are renammed?
|
||||||
|
|
@ -947,6 +1032,13 @@ fn get_cnstr_new_inst_block(
|
||||||
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
||||||
/// - `id_method`: the expected [`IdMethod`].
|
/// - `id_method`: the expected [`IdMethod`].
|
||||||
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
||||||
|
/// - `tester_methods_class`: the class used to define the methods in `tester_methods`
|
||||||
|
/// - `tester_methods`: the methods used to test if a `java.lang.reflect.Method` is a specific method.
|
||||||
|
/// Methods are indexed by the IdMethod they detect, and have a name derived from the method
|
||||||
|
/// they detect.
|
||||||
|
/// - `classloader`: is the runtime data of the classloader that loaded the. If None, the classloader
|
||||||
|
/// is not tested. Platform classes should probably not be tested (the bootclassloader can be
|
||||||
|
/// represented with a null reference, which may lead to a null pointer exception).
|
||||||
fn test_cnstr(
|
fn test_cnstr(
|
||||||
cnst_reg: u16,
|
cnst_reg: u16,
|
||||||
id_method: IdMethod,
|
id_method: IdMethod,
|
||||||
|
|
@ -954,11 +1046,17 @@ fn test_cnstr(
|
||||||
reg_inf: &mut RegistersInfo,
|
reg_inf: &mut RegistersInfo,
|
||||||
tester_methods_class: IdType,
|
tester_methods_class: IdType,
|
||||||
tester_methods: &mut HashMap<IdMethod, Method>,
|
tester_methods: &mut HashMap<IdMethod, Method>,
|
||||||
|
classloader: Option<&ClassLoaderData>,
|
||||||
) -> Result<Vec<Instruction>> {
|
) -> Result<Vec<Instruction>> {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
let tst_descriptor = match tester_methods.entry(id_method.clone()) {
|
let tst_descriptor = match tester_methods.entry(id_method.clone()) {
|
||||||
Entry::Occupied(e) => e.into_mut(),
|
Entry::Occupied(e) => e.into_mut(),
|
||||||
Entry::Vacant(e) => e.insert(gen_tester_method(tester_methods_class, id_method, true)?),
|
Entry::Vacant(e) => e.insert(gen_tester_method(
|
||||||
|
tester_methods_class,
|
||||||
|
id_method,
|
||||||
|
true,
|
||||||
|
classloader,
|
||||||
|
)?),
|
||||||
}
|
}
|
||||||
.descriptor
|
.descriptor
|
||||||
.clone();
|
.clone();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use androscalpel::{Instruction, RegType};
|
use androscalpel::{Instruction, RegType};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{Result, bail};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
/// Information about the register used.
|
/// Information about the register used.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ pub struct RuntimeData {
|
||||||
pub dyn_code_load: Vec<DynamicCodeLoadingData>,
|
pub dyn_code_load: Vec<DynamicCodeLoadingData>,
|
||||||
/// The id of the class loader of the apk (the main classloader)
|
/// The id of the class loader of the apk (the main classloader)
|
||||||
pub apk_cl_id: Option<String>,
|
pub apk_cl_id: Option<String>,
|
||||||
|
/// Additionnal classloader data.
|
||||||
|
pub classloaders: Vec<ClassLoaderData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RuntimeData {
|
impl RuntimeData {
|
||||||
|
|
@ -87,6 +89,14 @@ impl RuntimeData {
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get classloader data, indexed by id.
|
||||||
|
pub fn get_classloader_data(&self) -> HashMap<String, ClassLoaderData> {
|
||||||
|
self.classloaders
|
||||||
|
.iter()
|
||||||
|
.map(|data| (data.id.clone(), data.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Structure storing the runtime information of a reflection call using
|
/// Structure storing the runtime information of a reflection call using
|
||||||
|
|
@ -187,3 +197,18 @@ pub struct DynamicCodeLoadingData {
|
||||||
/// The path to the files storing the .dex/.apk/other bytecode loaded.
|
/// The path to the files storing the .dex/.apk/other bytecode loaded.
|
||||||
pub files: Vec<PathBuf>,
|
pub files: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structure storing the runtime information of a classloader.
|
||||||
|
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct ClassLoaderData {
|
||||||
|
/// Id of the classloader. This value is unique for *one* run of the apk.
|
||||||
|
pub id: String,
|
||||||
|
/// The Id of the parent classloader if it exists.
|
||||||
|
pub parent_id: Option<String>,
|
||||||
|
/// The string representation of the classloader. Not verry relayable but our best option to
|
||||||
|
/// distinguish classloader at runtime.
|
||||||
|
#[serde(rename = "str")]
|
||||||
|
pub string_representation: String,
|
||||||
|
/// The class of the class loader.
|
||||||
|
pub cname: String, // TODO: IdType,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue