uglly fix

This commit is contained in:
Jean-Marie Mineau 2025-06-03 21:40:09 +02:00
parent 300c3156ec
commit 6aa848caea
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
3 changed files with 152 additions and 19 deletions

View file

@ -78,10 +78,9 @@ fn insert_code_model_class_loaders(apk: &mut Apk, runtime_data: &mut RuntimeData
})?;
}
assert!(
!class_loaders.contains_key(&dyn_data.classloader),
"The same class loader should not appear twice in runtime_data.dyn_code_load"
);
if class_loaders.contains_key(&dyn_data.classloader) {
panic!("The same class loader should not appear twice in runtime_data.dyn_code_load, found: {}", &dyn_data.classloader)
}
let classes = apk.list_classes();
let mut class_loader = ClassLoader {

View file

@ -8,7 +8,7 @@ use std::hash::{DefaultHasher, Hash, Hasher};
use crate::{dex_types::*, register_manipulation::*, runtime_data::*};
const DEBUG: bool = true;
const DEBUG: bool = false;
// Interesting stuff: https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/reg_type.h;drc=83db0626fad8c6e0508754fffcbbd58e539d14a5;l=94
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/method_verifier.cc;drc=83db0626fad8c6e0508754fffcbbd58e539d14a5;l=5328
@ -93,9 +93,11 @@ pub fn transform_method(
None
};
let mut new_insns = vec![];
let mut new_insns: Vec<Instruction> = vec![];
let mut iter = code.insns.iter();
let mut current_addr_label: Option<String> = None;
let mut current_try_block_index = None;
let mut old_try_block_end_label = None;
while let Some(ins) = iter.next() {
match ins {
Instruction::InvokeVirtual { method, args }
@ -153,6 +155,36 @@ pub fn transform_method(
Ok((mut save_insns, restore_insns)) => {
restore_reg = restore_insns;
new_insns.append(&mut save_insns);
if !restore_reg.is_empty() {
if let Some(current_try_block_index) = current_try_block_index {
if let Instruction::Try { end_label, .. } =
&mut new_insns[current_try_block_index]
{
old_try_block_end_label = Some(end_label.clone());
*end_label = format!(
"end_current_try_block_patching_at_{}",
addr_label.clone()
);
}
new_insns.push(Instruction::Label {
name: format!(
"end_current_try_block_patching_at_{}",
addr_label.clone()
),
});
new_insns.push(Instruction::Try {
end_label: format!(
"end_try_block_patching_at_{}",
addr_label.clone()
),
handlers: vec![],
default_handler: Some(format!(
"handler_try_block_patching_at_{}",
addr_label.clone()
)),
});
}
}
}
Err(err) => {
warn!(
@ -267,11 +299,102 @@ pub fn transform_method(
}
let end_label = Instruction::Label { name: end_label };
new_insns.push(end_label.clone());
// If we interupted a try block, catch all exception, restore reg, reopen the try
// block, then raise the exception inside of it
if !restore_reg.is_empty() {
if let Some(current_try_block_index) = current_try_block_index {
let old_try = if let Instruction::Try {
handlers,
default_handler,
..
} = &new_insns[current_try_block_index]
{
if let Some(old_try_block_end_label) = &old_try_block_end_label {
Instruction::Try {
end_label: old_try_block_end_label.clone(),
handlers: handlers.clone(),
default_handler: default_handler.clone(),
}
} else {
bail!(
"Should not happen: could not remember the value of the \
current try block end label"
);
}
} else {
bail!(
"Should not happen, the index of the current try block does \
not point to a try instruction"
);
};
if register_info.nb_arg_reg == 0 {
register_info.nb_arg_reg += 1;
}
let exception_reg = if register_info.first_arg > u8::MAX as u16 {
warn!(
"Failed to instrument reflection in {} at {}: no 8 bits register \
available to foward exception on try block",
method.__str__(),
addr_label,
);
bail!(
"Failed to instrument reflection in {} at {}: no 8 bits register \
available to foward exception on try block",
method.__str__(),
addr_label,
);
} else {
register_info.first_arg as u8
};
new_insns.append(&mut vec![
Instruction::Label {
name: format!("end_try_block_patching_at_{}", addr_label.clone()),
},
Instruction::Goto {
label: format!(
"end_handler_try_block_patching_at_{}",
addr_label.clone()
),
},
Instruction::Label {
name: format!(
"handler_try_block_patching_at_{}",
addr_label.clone()
),
},
Instruction::MoveException { to: exception_reg },
]);
new_insns.append(&mut restore_reg.clone());
new_insns.push(old_try);
new_insns.append(&mut vec![
Instruction::Throw { reg: exception_reg },
Instruction::Label {
name: format!(
"end_handler_try_block_patching_at_{}",
addr_label.clone()
),
},
]);
}
}
new_insns.append(&mut restore_reg);
current_addr_label = None;
}
Instruction::Label { name } if name.starts_with("THESEUS_ADDR_") => {
current_addr_label = Some(name.clone());
Instruction::Try { .. } => {
current_try_block_index = Some(new_insns.len());
new_insns.push(ins.clone());
}
Instruction::Label { name } => {
if name.starts_with("THESEUS_ADDR_") {
current_addr_label = Some(name.clone());
}
if let Some(Instruction::Try { end_label, .. }) =
current_try_block_index.map(|i| &new_insns[i])
{
if end_label == name {
current_try_block_index = None;
}
}
new_insns.push(ins.clone());
}
ins => {
@ -631,15 +754,26 @@ fn gen_tester_method(
args: vec![REG_TST_VAL as u16],
},
Instruction::MoveResultObject { to: REG_TST_VAL },
Instruction::ConstClass {
]);
if method_to_test.proto.get_return_type().is_void() {
insns.push(Instruction::ConstString {
reg: REG_CMP_VAL,
lit: method_to_test.proto.get_return_type(),
},
Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(),
args: vec![REG_CMP_VAL as u16],
},
Instruction::MoveResultObject { to: REG_CMP_VAL },
lit: "V".into(),
});
} else {
insns.append(&mut vec![
Instruction::ConstClass {
reg: REG_CMP_VAL,
lit: method_to_test.proto.get_return_type(),
},
Instruction::InvokeVirtual {
method: CLT_GET_DESCR_STRING.clone(),
args: vec![REG_CMP_VAL as u16],
},
Instruction::MoveResultObject { to: REG_CMP_VAL },
]);
}
insns.append(&mut vec![
Instruction::InvokeVirtual {
method: STR_EQ.clone(),
args: vec![REG_CMP_VAL as u16, REG_TST_VAL as u16],
@ -1242,7 +1376,7 @@ fn get_invoke_block(
});
insns.push(Instruction::InvokeStatic {
method: get_scalar_to_obj_method(&ret_ty).unwrap(),
args: vec![reg_inf.array_val as u16],
args: vec![reg_inf.array_val as u16, (reg_inf.array_val + 1) as u16],
});
insns.push(move_result);
insns.push(Instruction::CheckCast {

View file

@ -1,5 +1,5 @@
use androscalpel::{Instruction, RegType};
use anyhow::{Result, bail};
use anyhow::{bail, Result};
use log::debug;
/// Information about the register used.
@ -38,7 +38,7 @@ impl RegistersInfo {
/// second the instructions to restore the registers to their old values.
///
/// `used_reg` is a list of register that cannot be used because directly used by the invoke
/// instruction or the move-result ibstruction.
/// instruction or the move-result instruction.
/// `regs_type` is the type of the registers at this point in the code of the method.
pub fn tmp_reserve_reg(
&mut self,