work on classloader names

This commit is contained in:
Jean-Marie Mineau 2025-05-06 11:25:11 +02:00
parent 1884ff4ac8
commit e9f28419c9
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
4 changed files with 184 additions and 124 deletions

View file

@ -9,6 +9,7 @@ import sys
import tempfile import tempfile
import shutil import shutil
import lzma import lzma
import re
from pathlib import Path from pathlib import Path
from typing import TextIO, Any from typing import TextIO, Any
from collections.abc import Callable from collections.abc import Callable
@ -85,7 +86,7 @@ def handle_classloader_data(data: dict, data_storage: dict):
data["id"] = cl_id_to_string(data["id"]) data["id"] = cl_id_to_string(data["id"])
data["parent_id"] = cl_id_to_string(data["parent_id"]) data["parent_id"] = cl_id_to_string(data["parent_id"])
print(f"[+] Got classloader {data['id']}({data['str']})") print(f"[+] Got classloader {data['id']}({data['str']})")
data_storage["classloaders"].append(data) data_storage["classloaders"][data[id]] = data
def handle_invoke_data(data, data_storage: dict): def handle_invoke_data(data, data_storage: dict):
@ -236,11 +237,19 @@ def handle_load_dex(data, data_storage: dict, file_storage: Path):
) )
caml_pattern = re.compile(r"([a-z])([A-Z])")
def caml_to_snake_case(string: str) -> str:
return caml_pattern.sub(r"\1_\2", string).lower()
def handle_app_info(data, data_storage: dict): def handle_app_info(data, data_storage: dict):
data["actualSourceDir"] = data["sourceDir"].removesuffix("/base.apk") data["actualSourceDir"] = data["sourceDir"].removesuffix("/base.apk")
data_storage["app_info"] = data data_storage["app_info"] = {}
print("[+] Received app info:") print("[+] Received app info:")
for k in data.keys(): for k in data.keys():
data_storage["app_info"][caml_to_snake_case(k)] = data[k]
print(f" {k}: {data[k]}") print(f" {k}: {data[k]}")
@ -385,7 +394,8 @@ def collect_runtime(
"class_new_inst_data": [], "class_new_inst_data": [],
"cnstr_new_inst_data": [], "cnstr_new_inst_data": [],
"dyn_code_load": [], "dyn_code_load": [],
"classloaders": [], "classloaders": {},
"app_info": {},
} }
script.on( script.on(

View file

@ -122,6 +122,12 @@ pub(crate) static DELEGATE_LAST_CLASS_LOADER: LazyLock<IdType> =
pub(crate) static LOG_INFO: LazyLock<IdMethod> = LazyLock::new(|| { pub(crate) static LOG_INFO: LazyLock<IdMethod> = LazyLock::new(|| {
IdMethod::from_smali("Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I").unwrap() IdMethod::from_smali("Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I").unwrap()
}); });
pub(crate) static STRING_REPLACE_ALL: LazyLock<IdMethod> = LazyLock::new(|| {
IdMethod::from_smali(
"Ljava/lang/String;->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
)
.unwrap()
});
/// Get the method that convert a object to its scalar conterpart (eg `java.lang.Integer` to `int` with /// Get the method that convert a object to its scalar conterpart (eg `java.lang.Integer` to `int` with
/// `Ljava/lang/Integer;->intValue()I`) /// `Ljava/lang/Integer;->intValue()I`)

View file

@ -20,16 +20,15 @@ const DEBUG: bool = false;
/// they detect. /// they detect.
pub fn transform_method( pub fn transform_method(
meth: &mut Method, meth: &mut Method,
ref_data: &RuntimeData, runtime_data: &RuntimeData,
tester_methods_class: IdType, tester_methods_class: IdType,
tester_methods: &mut HashMap<IdMethod, Method>, tester_methods: &mut HashMap<IdMethod, Method>,
) -> Result<()> { ) -> Result<()> {
// checking meth.annotations might be usefull at some point // checking meth.annotations might be usefull at some point
//println!("{}", meth.descriptor.__str__()); //println!("{}", meth.descriptor.__str__());
let invoke_data = ref_data.get_invoke_data_for(&meth.descriptor); let invoke_data = runtime_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 = runtime_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 = runtime_data.get_cnstr_new_instance_data_for(&meth.descriptor);
let classloaders = ref_data.get_classloader_data();
let code = meth let code = meth
.code .code
@ -192,7 +191,7 @@ pub fn transform_method(
move_ret.clone(), move_ret.clone(),
tester_methods_class.clone(), tester_methods_class.clone(),
tester_methods, tester_methods,
&classloaders, runtime_data,
)? { )? {
new_insns.push(ins); new_insns.push(ins);
} }
@ -231,7 +230,7 @@ pub fn transform_method(
move_ret.clone(), move_ret.clone(),
tester_methods_class.clone(), tester_methods_class.clone(),
tester_methods, tester_methods,
&classloaders, runtime_data,
)? { )? {
new_insns.push(ins); new_insns.push(ins);
} }
@ -343,7 +342,7 @@ fn gen_tester_method(
method_to_test: IdMethod, method_to_test: IdMethod,
is_constructor: bool, is_constructor: bool,
classloader: Option<String>, classloader: Option<String>,
classloaders: &HashMap<String, ClassLoaderData>, runtime_data: &RuntimeData,
) -> Result<Method> { ) -> Result<Method> {
let mut hasher = DefaultHasher::new(); let mut hasher = DefaultHasher::new();
if let Some(ref id) = classloader { if let Some(ref id) = classloader {
@ -381,45 +380,67 @@ fn gen_tester_method(
); );
let mut method = Method::new(descriptor); let mut method = Method::new(descriptor);
let no_label: String = "lable_no".into(); let no_label: String = "lable_no".into();
let reg_arr = 0; const REG_ARR: u8 = 0;
let reg_arr_idx = 1; const REG_ARR_IDX: u8 = 1;
let reg_tst_val = 2; const REG_TST_VAL: u8 = 2;
let reg_def_type = 3; const REG_DEF_TYPE: u8 = 3;
let reg_cmp_val = 4; const REG_CMP_VAL: u8 = 4;
let reg_class_loader = 5; const REG_CLASS_LOADER: u8 = 5;
let reg_ref_method = 6; const REG_REGEX: u8 = 6;
const REG_REPLACE: u8 = 7;
const REG_REF_METHOD: u8 = 8;
fn sanityze_name(reg: u8, app_path: &str) -> Vec<Instruction> {
// TODO: InMemory cookie
vec![
Instruction::ConstString {
reg: REG_REGEX,
lit: app_path.into(),
},
Instruction::ConstString {
reg: REG_REPLACE,
lit: "APP_PATH".into(),
},
Instruction::InvokeVirtual {
method: STRING_REPLACE_ALL.clone(),
args: vec![reg as u16, REG_REGEX as u16, REG_REPLACE as u16],
},
Instruction::MoveResultObject { to: reg },
]
}
// Check for arg type // Check for arg type
let mut insns = if !is_constructor { let mut insns = if !is_constructor {
vec![ vec![
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: MTH_GET_PARAMS_TY.clone(), method: MTH_GET_PARAMS_TY.clone(),
args: vec![reg_ref_method], args: vec![REG_REF_METHOD as u16],
}, },
Instruction::MoveResultObject { to: reg_arr }, Instruction::MoveResultObject { to: REG_ARR },
] ]
} else { } else {
vec![ vec![
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CNSTR_GET_PARAMS_TY.clone(), method: CNSTR_GET_PARAMS_TY.clone(),
args: vec![reg_ref_method], args: vec![REG_REF_METHOD as u16],
}, },
Instruction::MoveResultObject { to: reg_arr }, Instruction::MoveResultObject { to: REG_ARR },
] ]
}; };
// First check the number of args // First check the number of args
// -------------------- // --------------------
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::ArrayLength { Instruction::ArrayLength {
dest: reg_arr_idx, dest: REG_ARR_IDX,
arr: reg_arr, arr: REG_ARR,
}, },
Instruction::Const { Instruction::Const {
reg: reg_tst_val, reg: REG_TST_VAL,
lit: method_to_test.proto.get_parameters().len() as i32, lit: method_to_test.proto.get_parameters().len() as i32,
}, },
Instruction::IfNe { Instruction::IfNe {
a: reg_arr_idx, a: REG_ARR_IDX,
b: reg_tst_val, b: REG_TST_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
]); ]);
@ -431,42 +452,42 @@ fn gen_tester_method(
.enumerate() .enumerate()
{ {
insns.push(Instruction::Const { insns.push(Instruction::Const {
reg: reg_arr_idx, reg: REG_ARR_IDX,
lit: i as i32, lit: i as i32,
}); });
insns.push(Instruction::AGetObject { insns.push(Instruction::AGetObject {
dest: reg_tst_val, dest: REG_TST_VAL,
arr: reg_arr, arr: REG_ARR,
idx: reg_arr_idx, idx: REG_ARR_IDX,
}); });
insns.push(Instruction::ConstClass { insns.push(Instruction::ConstClass {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: param, lit: param,
}); });
insns.push(Instruction::InvokeVirtual { insns.push(Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_cmp_val as u16], args: vec![REG_CMP_VAL as u16],
}); });
insns.push(Instruction::MoveResultObject { to: reg_cmp_val }); insns.push(Instruction::MoveResultObject { to: REG_CMP_VAL });
insns.push(Instruction::InvokeVirtual { insns.push(Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_tst_val as u16], args: vec![REG_TST_VAL as u16],
}); });
insns.push(Instruction::MoveResultObject { to: reg_tst_val }); insns.push(Instruction::MoveResultObject { to: REG_TST_VAL });
insns.push(Instruction::InvokeVirtual { insns.push(Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_cmp_val as u16, reg_tst_val as u16], args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
}); });
insns.push(Instruction::MoveResult { to: reg_cmp_val }); insns.push(Instruction::MoveResult { to: REG_CMP_VAL });
insns.push(Instruction::IfEqZ { insns.push(Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}); });
// Comparing Type does not work when different types share the same name (eg type from // Comparing Type does not work when different types share the same name (eg type from
// another class loader) // another class loader)
//insns.push(Instruction::IfNe { //insns.push(Instruction::IfNe {
// a: reg_arr_idx, // a: REG_ARR_IDX,
// b: reg_tst_val, // b: REG_TST_VAL,
// label: no_label.clone(), // label: no_label.clone(),
//}) //})
} }
@ -476,56 +497,56 @@ fn gen_tester_method(
// Check Name // Check Name
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: MTH_GET_NAME.clone(), method: MTH_GET_NAME.clone(),
args: vec![reg_ref_method], args: vec![REG_REF_METHOD as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::ConstString { Instruction::ConstString {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: method_to_test.name.clone(), lit: method_to_test.name.clone(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_tst_val as u16, reg_cmp_val as u16], args: vec![REG_TST_VAL as u16, REG_CMP_VAL as u16],
}, },
Instruction::MoveResult { to: reg_cmp_val }, Instruction::MoveResult { to: REG_CMP_VAL },
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
// Check Return Type // Check Return Type
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: MTH_GET_RET_TY.clone(), method: MTH_GET_RET_TY.clone(),
args: vec![reg_ref_method], args: vec![REG_REF_METHOD as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_tst_val as u16], args: vec![REG_TST_VAL as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::ConstClass { Instruction::ConstClass {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: method_to_test.proto.get_return_type(), lit: method_to_test.proto.get_return_type(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_cmp_val as u16], args: vec![REG_CMP_VAL as u16],
}, },
Instruction::MoveResultObject { to: reg_cmp_val }, Instruction::MoveResultObject { to: REG_CMP_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_cmp_val as u16, reg_tst_val as u16], args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
}, },
Instruction::MoveResult { to: reg_cmp_val }, Instruction::MoveResult { to: REG_CMP_VAL },
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
// Comparing Type does not work when different types share the same name (eg type from // Comparing Type does not work when different types share the same name (eg type from
// another class loader) // another class loader)
//Instruction::IfNe { //Instruction::IfNe {
// a: reg_arr_idx, // a: REG_ARR_IDX,
// b: reg_tst_val, // b: REG_TST_VAL,
// label: no_label.clone(), // label: no_label.clone(),
//}, //},
]); ]);
@ -534,18 +555,20 @@ fn gen_tester_method(
if is_constructor { if is_constructor {
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 as u16],
}); });
} else { } else {
insns.push(Instruction::InvokeVirtual { insns.push(Instruction::InvokeVirtual {
method: MTH_GET_DEC_CLS.clone(), method: MTH_GET_DEC_CLS.clone(),
args: vec![reg_ref_method], args: vec![REG_REF_METHOD as u16],
}); });
} }
insns.push(Instruction::MoveResultObject { to: reg_def_type }); insns.push(Instruction::MoveResultObject { to: REG_DEF_TYPE });
//Check the classloader //Check the classloader
let mut current_classloader = classloader.as_ref().and_then(|id| classloaders.get(id)); let mut current_classloader = classloader
.as_ref()
.and_then(|id| runtime_data.classloaders.get(id));
let check_class_loader = current_classloader.is_some(); let check_class_loader = current_classloader.is_some();
if check_class_loader { if check_class_loader {
insns.append(&mut vec![ insns.append(&mut vec![
@ -553,14 +576,15 @@ fn gen_tester_method(
// Not the ideal, but best cross execution classloader identifier we have. // Not the ideal, but best cross execution classloader identifier we have.
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: GET_CLASS_LOADER.clone(), method: GET_CLASS_LOADER.clone(),
args: vec![reg_def_type as u16], args: vec![REG_DEF_TYPE as u16],
}, },
Instruction::MoveResultObject { Instruction::MoveResultObject {
to: reg_class_loader, to: REG_CLASS_LOADER,
}, },
]); ]);
} }
while let Some(classloader) = current_classloader { while let Some(classloader) = current_classloader {
// TODO: check class and if platform
if classloader.cname == *BOOT_CLASS_LOADER_TY { if classloader.cname == *BOOT_CLASS_LOADER_TY {
// Ljava/lang/BootClassLoader; is complicated. // Ljava/lang/BootClassLoader; is complicated.
// It's string rep is "java.lang.BootClassLoader@7e2aeab" where "7e2aeab" is it's // It's string rep is "java.lang.BootClassLoader@7e2aeab" where "7e2aeab" is it's
@ -570,35 +594,35 @@ fn gen_tester_method(
// null pointer as a valid value. // null pointer as a valid value.
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_class_loader, a: REG_CLASS_LOADER,
label: "label_end_classloader_test".into(), label: "label_end_classloader_test".into(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: GET_CLASS.clone(), method: GET_CLASS.clone(),
args: vec![reg_class_loader as u16], args: vec![REG_CLASS_LOADER as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_tst_val as u16], args: vec![REG_TST_VAL as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::ConstClass { Instruction::ConstClass {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: BOOT_CLASS_LOADER_TY.clone(), lit: BOOT_CLASS_LOADER_TY.clone(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_cmp_val as u16], args: vec![REG_CMP_VAL as u16],
}, },
Instruction::MoveResultObject { to: reg_cmp_val }, Instruction::MoveResultObject { to: REG_CMP_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_cmp_val as u16, reg_tst_val as u16], args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
}, },
Instruction::MoveResult { to: reg_cmp_val }, Instruction::MoveResult { to: REG_CMP_VAL },
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
Instruction::Label { Instruction::Label {
@ -609,42 +633,53 @@ fn gen_tester_method(
} }
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_class_loader, a: REG_CLASS_LOADER,
label: no_label.clone(), label: no_label.clone(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: TO_STRING.clone(), method: TO_STRING.clone(),
args: vec![reg_class_loader as u16], args: vec![REG_CLASS_LOADER as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::ConstString { Instruction::ConstString {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: classloader.string_representation.as_str().into(), lit: classloader.string_representation.as_str().into(),
}, },
]);
insns.append(&mut sanityze_name(
REG_CMP_VAL,
&runtime_data.app_info.actual_source_dir,
));
insns.append(&mut sanityze_name(
REG_TST_VAL,
&runtime_data.app_info.actual_source_dir,
));
insns.append(&mut vec![
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_cmp_val as u16, reg_tst_val as u16], args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
}, },
Instruction::MoveResult { to: reg_cmp_val }, Instruction::MoveResult { to: REG_CMP_VAL },
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: GET_PARENT.clone(), method: GET_PARENT.clone(),
args: vec![reg_class_loader as u16], args: vec![REG_CLASS_LOADER as u16],
}, },
Instruction::MoveResultObject { Instruction::MoveResultObject {
to: reg_class_loader, to: REG_CLASS_LOADER,
}, },
]); ]);
let parent_id = classloader.parent_id.clone(); let parent_id = classloader.parent_id.clone();
// If parent_id is None, the parent is in fact the boot class loader (except for the // If parent_id is None, the parent is in fact the boot class loader (except for the
// boot class loader itself, already handled at the start of the loop). // boot class loader itself, already handled at the start of the loop).
current_classloader = if let Some(ref id) = parent_id { current_classloader = if let Some(ref id) = parent_id {
classloaders.get(id) runtime_data.classloaders.get(id)
} else { } else {
classloaders runtime_data
.classloaders
.values() .values()
.find(|cl| cl.cname == *BOOT_CLASS_LOADER_TY) .find(|cl| cl.cname == *BOOT_CLASS_LOADER_TY)
}; };
@ -653,44 +688,44 @@ fn gen_tester_method(
// Check Declaring Type // Check Declaring Type
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::ConstClass { Instruction::ConstClass {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: method_to_test.class_.clone(), lit: method_to_test.class_.clone(),
}, },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_cmp_val as u16], args: vec![REG_CMP_VAL as u16],
}, },
Instruction::MoveResultObject { to: reg_cmp_val }, Instruction::MoveResultObject { to: REG_CMP_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(), method: CLT_GET_DESCR_STRING.clone(),
args: vec![reg_def_type as u16], args: vec![REG_DEF_TYPE as u16],
}, },
Instruction::MoveResultObject { to: reg_tst_val }, Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::InvokeVirtual { Instruction::InvokeVirtual {
method: STR_EQ.clone(), method: STR_EQ.clone(),
args: vec![reg_cmp_val as u16, reg_tst_val as u16], args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
}, },
Instruction::MoveResult { to: reg_cmp_val }, Instruction::MoveResult { to: REG_CMP_VAL },
Instruction::IfEqZ { Instruction::IfEqZ {
a: reg_cmp_val, a: REG_CMP_VAL,
label: no_label.clone(), label: no_label.clone(),
}, },
// Comparing Type does not work when different types share the same name (eg type from // Comparing Type does not work when different types share the same name (eg type from
// another class loader) // another class loader)
//Instruction::IfNe { //Instruction::IfNe {
// a: reg_arr_idx, // a: REG_ARR_IDX,
// b: reg_tst_val, // b: REG_TST_VAL,
// label: no_label.clone(), // label: no_label.clone(),
//}, //},
]); ]);
if DEBUG { if DEBUG {
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::ConstString { Instruction::ConstString {
reg: reg_tst_val, reg: REG_TST_VAL,
lit: "THESEUS".into(), lit: "THESEUS".into(),
}, },
Instruction::ConstString { Instruction::ConstString {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: format!( lit: format!(
"T.{method_test_name}() (test of {}) returned true", "T.{method_test_name}() (test of {}) returned true",
method_to_test method_to_test
@ -701,26 +736,26 @@ fn gen_tester_method(
}, },
Instruction::InvokeStatic { Instruction::InvokeStatic {
method: LOG_INFO.clone(), method: LOG_INFO.clone(),
args: vec![reg_tst_val as u16, reg_cmp_val as u16], args: vec![REG_TST_VAL as u16, REG_CMP_VAL as u16],
}, },
]); ]);
} }
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::Const { Instruction::Const {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: 1, lit: 1,
}, },
Instruction::Return { reg: reg_cmp_val }, Instruction::Return { reg: REG_CMP_VAL },
Instruction::Label { name: no_label }, Instruction::Label { name: no_label },
]); ]);
if DEBUG { if DEBUG {
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::ConstString { Instruction::ConstString {
reg: reg_tst_val, reg: REG_TST_VAL,
lit: "THESEUS".into(), lit: "THESEUS".into(),
}, },
Instruction::ConstString { Instruction::ConstString {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: format!( lit: format!(
"T.{method_test_name}() (test of {}) returned false", "T.{method_test_name}() (test of {}) returned false",
method_to_test method_to_test
@ -731,16 +766,16 @@ fn gen_tester_method(
}, },
Instruction::InvokeStatic { Instruction::InvokeStatic {
method: LOG_INFO.clone(), method: LOG_INFO.clone(),
args: vec![reg_tst_val as u16, reg_cmp_val as u16], args: vec![REG_TST_VAL as u16, REG_CMP_VAL as u16],
}, },
]); ]);
} }
insns.append(&mut vec![ insns.append(&mut vec![
Instruction::Const { Instruction::Const {
reg: reg_cmp_val, reg: REG_CMP_VAL,
lit: 0, lit: 0,
}, },
Instruction::Return { reg: reg_cmp_val }, Instruction::Return { reg: REG_CMP_VAL },
]); ]);
method.is_static = true; method.is_static = true;
@ -775,7 +810,7 @@ fn test_method(
tester_methods_class: IdType, tester_methods_class: IdType,
tester_methods: &mut HashMap<IdMethod, Method>, tester_methods: &mut HashMap<IdMethod, Method>,
classloader: Option<String>, classloader: Option<String>,
classloaders: &HashMap<String, ClassLoaderData>, runtime_data: &RuntimeData,
) -> 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()) {
@ -785,7 +820,7 @@ fn test_method(
id_method, id_method,
false, false,
classloader, classloader,
classloaders, runtime_data,
)?), )?),
} }
.descriptor .descriptor
@ -838,7 +873,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>, runtime_data: &RuntimeData,
) -> 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)
@ -877,7 +912,7 @@ fn get_invoke_block(
tester_methods_class, tester_methods_class,
tester_methods, tester_methods,
classloader, classloader,
classloaders, runtime_data,
)?; )?;
if !ref_data.is_static { if !ref_data.is_static {
@ -1057,7 +1092,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>, runtime_data: &RuntimeData,
) -> 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)
@ -1092,7 +1127,7 @@ fn get_cnstr_new_inst_block(
tester_methods_class, tester_methods_class,
tester_methods, tester_methods,
classloader, classloader,
classloaders, runtime_data,
)?; )?;
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?
@ -1152,7 +1187,7 @@ fn test_cnstr(
tester_methods_class: IdType, tester_methods_class: IdType,
tester_methods: &mut HashMap<IdMethod, Method>, tester_methods: &mut HashMap<IdMethod, Method>,
classloader: Option<String>, classloader: Option<String>,
classloaders: &HashMap<String, ClassLoaderData>, runtime_data: &RuntimeData,
) -> 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()) {
@ -1162,7 +1197,7 @@ fn test_cnstr(
id_method, id_method,
true, true,
classloader, classloader,
classloaders, runtime_data,
)?), )?),
} }
.descriptor .descriptor

View file

@ -13,7 +13,9 @@ pub struct RuntimeData {
/// 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. /// Additionnal classloader data.
pub classloaders: Vec<ClassLoaderData>, pub classloaders: HashMap<String, ClassLoaderData>,
/// Additionnal application data.
pub app_info: AppInfo,
} }
impl RuntimeData { impl RuntimeData {
@ -89,14 +91,6 @@ 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
@ -212,3 +206,18 @@ pub struct ClassLoaderData {
/// The class of the class loader. /// The class of the class loader.
pub cname: IdType, pub cname: IdType,
} }
/// Structure storing application information
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct AppInfo {
pub data_dir: String,
pub device_protected_data_dir: String,
pub native_library_dir: String,
pub public_source_dir: String,
//pub shared_library_files: Option<Vec<String>>,
pub source_dir: String,
//pub split_names: Option<Vec<String>>,
pub split_public_source_dirs: Option<Vec<String>>,
pub split_source_dirs: Option<String>,
pub actual_source_dir: String,
}