uglly fix
This commit is contained in:
parent
300c3156ec
commit
6aa848caea
3 changed files with 152 additions and 19 deletions
|
|
@ -78,10 +78,9 @@ fn insert_code_model_class_loaders(apk: &mut Apk, runtime_data: &mut RuntimeData
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
if class_loaders.contains_key(&dyn_data.classloader) {
|
||||||
!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)
|
||||||
"The same class loader should not appear twice in runtime_data.dyn_code_load"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
let classes = apk.list_classes();
|
let classes = apk.list_classes();
|
||||||
let mut class_loader = ClassLoader {
|
let mut class_loader = ClassLoader {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
|
|
||||||
use crate::{dex_types::*, register_manipulation::*, runtime_data::*};
|
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
|
// 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
|
// 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
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_insns = vec![];
|
let mut new_insns: Vec<Instruction> = vec![];
|
||||||
let mut iter = code.insns.iter();
|
let mut iter = code.insns.iter();
|
||||||
let mut current_addr_label: Option<String> = None;
|
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() {
|
while let Some(ins) = iter.next() {
|
||||||
match ins {
|
match ins {
|
||||||
Instruction::InvokeVirtual { method, args }
|
Instruction::InvokeVirtual { method, args }
|
||||||
|
|
@ -153,6 +155,36 @@ pub fn transform_method(
|
||||||
Ok((mut save_insns, restore_insns)) => {
|
Ok((mut save_insns, restore_insns)) => {
|
||||||
restore_reg = restore_insns;
|
restore_reg = restore_insns;
|
||||||
new_insns.append(&mut save_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) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
|
|
@ -267,11 +299,102 @@ pub fn transform_method(
|
||||||
}
|
}
|
||||||
let end_label = Instruction::Label { name: end_label };
|
let end_label = Instruction::Label { name: end_label };
|
||||||
new_insns.push(end_label.clone());
|
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);
|
new_insns.append(&mut restore_reg);
|
||||||
current_addr_label = None;
|
current_addr_label = None;
|
||||||
}
|
}
|
||||||
Instruction::Label { name } if name.starts_with("THESEUS_ADDR_") => {
|
Instruction::Try { .. } => {
|
||||||
current_addr_label = Some(name.clone());
|
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());
|
new_insns.push(ins.clone());
|
||||||
}
|
}
|
||||||
ins => {
|
ins => {
|
||||||
|
|
@ -631,15 +754,26 @@ fn gen_tester_method(
|
||||||
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 {
|
]);
|
||||||
|
if method_to_test.proto.get_return_type().is_void() {
|
||||||
|
insns.push(Instruction::ConstString {
|
||||||
reg: REG_CMP_VAL,
|
reg: REG_CMP_VAL,
|
||||||
lit: method_to_test.proto.get_return_type(),
|
lit: "V".into(),
|
||||||
},
|
});
|
||||||
Instruction::InvokeVirtual {
|
} else {
|
||||||
method: CLT_GET_DESCR_STRING.clone(),
|
insns.append(&mut vec![
|
||||||
args: vec![REG_CMP_VAL as u16],
|
Instruction::ConstClass {
|
||||||
},
|
reg: REG_CMP_VAL,
|
||||||
Instruction::MoveResultObject { to: 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 {
|
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],
|
||||||
|
|
@ -1242,7 +1376,7 @@ fn get_invoke_block(
|
||||||
});
|
});
|
||||||
insns.push(Instruction::InvokeStatic {
|
insns.push(Instruction::InvokeStatic {
|
||||||
method: get_scalar_to_obj_method(&ret_ty).unwrap(),
|
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(move_result);
|
||||||
insns.push(Instruction::CheckCast {
|
insns.push(Instruction::CheckCast {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use androscalpel::{Instruction, RegType};
|
use androscalpel::{Instruction, RegType};
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{bail, Result};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
/// Information about the register used.
|
/// Information about the register used.
|
||||||
|
|
@ -38,7 +38,7 @@ impl RegistersInfo {
|
||||||
/// second the instructions to restore the registers to their old values.
|
/// 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
|
/// `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.
|
/// `regs_type` is the type of the registers at this point in the code of the method.
|
||||||
pub fn tmp_reserve_reg(
|
pub fn tmp_reserve_reg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue