debugging

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2025-03-03 17:40:24 +01:00
parent e16252907a
commit ed3385e611
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
5 changed files with 105 additions and 18 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
demo_env.sh
test

4
patcher/Cargo.lock generated
View file

@ -35,7 +35,6 @@ dependencies = [
[[package]]
name = "androscalpel"
version = "0.1.0"
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
dependencies = [
"adler",
"androscalpel_serializer",
@ -51,7 +50,6 @@ dependencies = [
[[package]]
name = "androscalpel_serializer"
version = "0.1.0"
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
dependencies = [
"androscalpel_serializer_derive",
"log",
@ -60,7 +58,6 @@ dependencies = [
[[package]]
name = "androscalpel_serializer_derive"
version = "0.1.0"
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
dependencies = [
"proc-macro2",
"quote",
@ -129,7 +126,6 @@ dependencies = [
[[package]]
name = "apk_frauder"
version = "0.1.0"
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
dependencies = [
"androscalpel_serializer",
"flate2",

View file

@ -6,9 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "f15ad78", features = ["code-analysis"] }
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "f15ad78"}
anyhow = "1.0.95"
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "ff2d630", features = ["code-analysis"] }
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "ff2d630"}
anyhow = { version = "1.0.95", features = ["backtrace"] }
clap = { version = "4.5.27", features = ["derive"] }
env_logger = "0.11.6"
reqwest = { version = "0.12.12", default-features = false, features = ["blocking", "rustls-tls"] }

View file

@ -262,7 +262,7 @@ impl RegistersInfo {
from: reg_save,
to: i as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
if regs_type[i + 1] == RegType::Object {
save_reg_insns.push(Instruction::MoveObject {
from: (i + 1) as u16,
@ -284,7 +284,7 @@ impl RegistersInfo {
from: reg_save,
to: (i + 1) as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
found = true;
break;
}
@ -336,7 +336,7 @@ impl RegistersInfo {
from: reg_save,
to: i as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
if regs_type[i + 1] == RegType::Object {
save_reg_insns.push(Instruction::MoveObject {
from: (i + 1) as u16,
@ -358,7 +358,7 @@ impl RegistersInfo {
from: reg_save,
to: (i + 1) as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
found = true;
break;
}
@ -428,7 +428,7 @@ impl RegistersInfo {
from: reg_save,
to: i as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
found = true;
break;
}
@ -502,6 +502,7 @@ impl RegistersInfo {
used_reg.push(i as u16);
if regs_type[i] == RegType::FirstWideScalar
|| regs_type[i] == RegType::SecondWideScalar
|| regs_type[i] == RegType::SimpleScalar
{
save_reg_insns.push(Instruction::Move {
from: i as u16,
@ -511,7 +512,7 @@ impl RegistersInfo {
from: reg_save,
to: i as u16,
});
}
} // else RegType::Undefined, do nothing, just use it
found = true;
break;
}
@ -604,6 +605,22 @@ static OBJ_TO_SCAL_FLOAT: LazyLock<IdMethod> =
LazyLock::new(|| IdMethod::from_smali("Ljava/lang/Float;->floatValue()F").unwrap());
static OBJ_TO_SCAL_DOUBLE: LazyLock<IdMethod> =
LazyLock::new(|| IdMethod::from_smali("Ljava/lang/Double;->doubleValue()D").unwrap());
static OBJ_OF_SCAL_BOOL: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Boolean;").unwrap());
static OBJ_OF_SCAL_BYTE: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Byte;").unwrap());
static OBJ_OF_SCAL_SHORT: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Short;").unwrap());
static OBJ_OF_SCAL_CHAR: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Character;").unwrap());
static OBJ_OF_SCAL_INT: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Integer;").unwrap());
static OBJ_OF_SCAL_LONG: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Long;").unwrap());
static OBJ_OF_SCAL_FLOAT: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Float;").unwrap());
static OBJ_OF_SCAL_DOUBLE: LazyLock<IdType> =
LazyLock::new(|| IdType::from_smali("Ljava/lang/Double;").unwrap());
static SCAL_TO_OBJ_BOOL: LazyLock<IdMethod> = LazyLock::new(|| {
IdMethod::from_smali("Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;").unwrap()
});
@ -640,7 +657,13 @@ pub fn labeling(_mth: &IdMethod, ins: &Instruction, addr: usize) -> Option<Strin
{
Some(format!("THESEUS_ADDR_{addr:08X}"))
}
_ => None,
_ => {
if addr == 0 {
Some(format!("DEBUG_{addr:08X}"))
} else {
None
}
}
}
}
@ -682,9 +705,9 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
register_info.first_arg = code.registers_size + 4;
register_info.nb_arg_reg = 0;
let regs_type = if register_info.array_val_save.is_none()
|| register_info.array_index_save.is_none()
|| register_info.array_save.is_none()
let regs_type = if register_info.array_val_save.is_some()
|| register_info.array_index_save.is_some()
|| register_info.array_save.is_some()
{
Some(meth.get_cfg()?.get_reg_types())
} else {
@ -732,10 +755,32 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
}
match register_info.tmp_reserve_reg(&used_reg, regs_type) {
Ok((mut save_insns, restore_insns)) => {
new_insns
.append(&mut debug_info(&format!("Reg saved:\n{regs_type:?}")));
new_insns.append(&mut debug_info(&format!(
"Reg saved:\n{register_info:#?}"
)));
new_insns.append(&mut debug_info(&format!(
"save reg insns:\n{}",
save_insns
.iter()
.map(|i| " # ".to_string() + i.__str__().as_str())
.collect::<Vec<_>>()
.join("\n")
)));
new_insns.append(&mut debug_info(&format!(
"restore reg insns:\n{}",
restore_insns
.iter()
.map(|i| " # ".to_string() + i.__str__().as_str())
.collect::<Vec<_>>()
.join("\n")
)));
restore_reg = restore_insns;
new_insns.append(&mut save_insns);
}
Err(err) => {
new_insns.append(&mut debug_info(&format!("WTF?: {err}")));
warn!(
"Failed to instrument reflection in {} at {}: {}",
method.__str__(),
@ -754,6 +799,11 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
}
}
}
} else {
new_insns.append(&mut debug_info(&format!(
"regs_type is none: {regs_type:#?}"
)));
new_insns.append(&mut debug_info(&format!("Reg used:\n{register_info:#?}")));
}
// TODO: recover from failure
if method == &*MTH_INVOKE {
@ -827,6 +877,14 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
code.insns = vec![];
// Start the method by moving the parameter to their registers pre-transformation.
let mut i = 0;
if !meth.is_static {
// Non static method take 'this' as first argument
code.insns.push(Instruction::MoveObject {
from: code.registers_size - code.ins_size + i + register_info.get_nb_added_reg(),
to: code.registers_size - code.ins_size + i,
});
i += 1;
}
for arg in &meth.descriptor.proto.get_parameters() {
if arg.is_class() || arg.is_array() {
code.insns.push(Instruction::MoveObject {
@ -1028,6 +1086,31 @@ pub fn get_obj_to_scalar_method(scalar_ty: &IdType) -> Result<IdMethod> {
}
}
/// Get the object associated to a scalar (eg `java.lang.Integer` for `int`)
///
/// `scalar_ty` is the type of the scalar (eg `I`)
pub fn get_obj_of_scalar(scalar_ty: &IdType) -> Result<IdType> {
if scalar_ty == &IdType::boolean() {
Ok(OBJ_OF_SCAL_BOOL.clone())
} else if scalar_ty == &IdType::byte() {
Ok(OBJ_OF_SCAL_BYTE.clone())
} else if scalar_ty == &IdType::short() {
Ok(OBJ_OF_SCAL_SHORT.clone())
} else if scalar_ty == &IdType::char() {
Ok(OBJ_OF_SCAL_CHAR.clone())
} else if scalar_ty == &IdType::int() {
Ok(OBJ_OF_SCAL_INT.clone())
} else if scalar_ty == &IdType::long() {
Ok(OBJ_OF_SCAL_LONG.clone())
} else if scalar_ty == &IdType::float() {
Ok(OBJ_OF_SCAL_FLOAT.clone())
} else if scalar_ty == &IdType::double() {
Ok(OBJ_OF_SCAL_DOUBLE.clone())
} else {
bail!("{} is not a scalar", scalar_ty.__str__())
}
}
/// Get the method that convert a scalar to its object conterpart (eg `int` to `java.lang.Integer` with
/// `Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;`)
///
@ -1101,6 +1184,10 @@ fn get_args_from_obj_arr(
});
reg_count += 1;
} else if param.is_double() || param.is_long() {
insns.push(Instruction::CheckCast {
reg: reg_inf.array_val,
lit: get_obj_of_scalar(param).unwrap(),
});
insns.push(Instruction::InvokeVirtual {
method: get_obj_to_scalar_method(param).unwrap(),
args: vec![reg_inf.array_val as u16],
@ -1114,6 +1201,10 @@ fn get_args_from_obj_arr(
});
reg_count += 2;
} else {
insns.push(Instruction::CheckCast {
reg: reg_inf.array_val,
lit: get_obj_of_scalar(param).unwrap(),
});
insns.push(Instruction::InvokeVirtual {
method: get_obj_to_scalar_method(param).unwrap(),
args: vec![reg_inf.array_val as u16],

View file

@ -1 +0,0 @@
{"invoke_data": [{"method": "Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;)Ljava/lang/String;", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectCall()V", "addr": 43}, {"method": "Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;)Ljava/lang/String;", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callConstructorVirtualMethodReflectConstr()V", "addr": 56}, {"method": "Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;)Ljava/lang/String;", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectOldConst()V", "addr": 40}, {"method": "Lcom/example/theseus/reflection/Reflectee;->transfer(ZBSCIJFDLjava/lang/String;)Ljava/lang/String;", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectCallAllScalar()V", "addr": 153}, {"method": "Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectVarArg()V", "addr": 65}], "class_new_inst_data": [{"constructor": "Landroid/app/Application;-><init>()V", "caller_method": "Landroid/app/AppComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;", "addr": 4}, {"constructor": "Lcom/example/theseus/reflection/MainActivity;-><init>()V", "caller_method": "Landroid/app/AppComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;", "addr": 4}, {"constructor": "Lcom/example/theseus/reflection/Reflectee;-><init>()V", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectOldConst()V", "addr": 18}], "cnstr_new_inst_data": [{"constructor": "Lcom/example/theseus/reflection/Reflectee;-><init>(Ljava/lang/String;)V", "caller_method": "Lcom/example/theseus/reflection/MainActivity;->callConstructorVirtualMethodReflectConstr()V", "addr": 34}]}