start automagication
This commit is contained in:
parent
5fdeb25682
commit
81c85763fd
5 changed files with 263 additions and 76 deletions
8
patcher/Cargo.lock
generated
8
patcher/Cargo.lock
generated
|
|
@ -35,7 +35,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel"
|
name = "androscalpel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=095ce2ce9340a7050aceb11ba626a1a9a966436a#095ce2ce9340a7050aceb11ba626a1a9a966436a"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7#5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
"androscalpel_serializer",
|
"androscalpel_serializer",
|
||||||
|
|
@ -51,7 +51,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel_serializer"
|
name = "androscalpel_serializer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=095ce2ce9340a7050aceb11ba626a1a9a966436a#095ce2ce9340a7050aceb11ba626a1a9a966436a"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7#5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"androscalpel_serializer_derive",
|
"androscalpel_serializer_derive",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -60,7 +60,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel_serializer_derive"
|
name = "androscalpel_serializer_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=095ce2ce9340a7050aceb11ba626a1a9a966436a#095ce2ce9340a7050aceb11ba626a1a9a966436a"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7#5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -129,7 +129,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "apk_frauder"
|
name = "apk_frauder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=095ce2ce9340a7050aceb11ba626a1a9a966436a#095ce2ce9340a7050aceb11ba626a1a9a966436a"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7#5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"androscalpel_serializer",
|
"androscalpel_serializer",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "095ce2ce9340a7050aceb11ba626a1a9a966436a" }
|
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7" }
|
||||||
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "095ce2ce9340a7050aceb11ba626a1a9a966436a"}
|
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "5d687081fb4a5cbf69dcc976dcb5ffae4d85fef7"}
|
||||||
anyhow = "1.0.95"
|
anyhow = "1.0.95"
|
||||||
clap = { version = "4.5.27", features = ["derive"] }
|
clap = { version = "4.5.27", features = ["derive"] }
|
||||||
env_logger = "0.11.6"
|
env_logger = "0.11.6"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
use androscalpel::Apk;
|
use androscalpel::Apk;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use std::fs::{read_to_string, File};
|
use std::fs::{read_to_string, File};
|
||||||
|
use std::io::Cursor;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::labeling;
|
||||||
|
|
||||||
#[derive(Clone, Args, Debug)]
|
#[derive(Clone, Args, Debug)]
|
||||||
pub struct ApkLocation {
|
pub struct ApkLocation {
|
||||||
#[arg(short, long, conflicts_with = "sha256")]
|
#[arg(short, long, conflicts_with = "sha256")]
|
||||||
|
|
@ -79,11 +82,16 @@ pub fn get_apk(location: &ApkLocation) -> Apk {
|
||||||
reqwest::StatusCode::OK => (),
|
reqwest::StatusCode::OK => (),
|
||||||
s => panic!("Failed to download apk: {:?}", s),
|
s => panic!("Failed to download apk: {:?}", s),
|
||||||
}
|
}
|
||||||
Apk::load_apk_bin(&res.bytes().expect("Failed to get APK bytes"), false, false).unwrap()
|
Apk::load_apk(
|
||||||
|
&mut Cursor::new(res.bytes().expect("Failed to get APK bytes")),
|
||||||
|
labeling,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
ApkLocation {
|
ApkLocation {
|
||||||
path: Some(path), ..
|
path: Some(path), ..
|
||||||
} => Apk::load_apk(File::open(path).unwrap(), |_, _, _| None, false).unwrap(),
|
} => Apk::load_apk(File::open(path).unwrap(), labeling, false).unwrap(),
|
||||||
_ => panic!("Don't know what to do with:\n{:#?}", location),
|
_ => panic!("Don't know what to do with:\n{:#?}", location),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use androscalpel::SmaliName;
|
use androscalpel::SmaliName;
|
||||||
use androscalpel::{IdMethod, Instruction, Method};
|
use androscalpel::{IdMethod, Instruction, Method};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub mod get_apk;
|
pub mod get_apk;
|
||||||
|
|
@ -10,19 +11,124 @@ pub mod get_apk;
|
||||||
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/reflection.cc;drc=83db0626fad8c6e0508754fffcbbd58e539d14a5;l=698
|
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/reflection.cc;drc=83db0626fad8c6e0508754fffcbbd58e539d14a5;l=698
|
||||||
// does.
|
// does.
|
||||||
|
|
||||||
/// Structure storing the runtime information of a reflection call.
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub struct ReflectionData {
|
||||||
|
pub invoke_data: Vec<ReflectionInvokeData>,
|
||||||
|
pub class_new_inst_data: Vec<ReflectionClassNewInstData>,
|
||||||
|
pub cnstr_new_inst_data: Vec<ReflectionCnstrNewInstData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReflectionData {
|
||||||
|
/// List all the methods that made reflection calls.
|
||||||
|
pub fn get_method_referenced(&self) -> HashSet<IdMethod> {
|
||||||
|
self.invoke_data
|
||||||
|
.iter()
|
||||||
|
.map(|data| data.caller_method.clone())
|
||||||
|
.chain(
|
||||||
|
self.class_new_inst_data
|
||||||
|
.iter()
|
||||||
|
.map(|data| data.caller_method.clone())
|
||||||
|
.chain(
|
||||||
|
self.cnstr_new_inst_data
|
||||||
|
.iter()
|
||||||
|
.map(|data| data.caller_method.clone()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List all data collected from called to `java.lang.reflect.Method.invoke()` made by
|
||||||
|
/// `method`.
|
||||||
|
pub fn get_invoke_data_for(
|
||||||
|
&self,
|
||||||
|
method: &IdMethod,
|
||||||
|
) -> HashMap<String, Vec<ReflectionInvokeData>> {
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
for val in self
|
||||||
|
.invoke_data
|
||||||
|
.iter()
|
||||||
|
.filter(|data| &data.caller_method == method)
|
||||||
|
{
|
||||||
|
let key = format!("THESEUS_ADDR_{:08X}", val.addr);
|
||||||
|
let entry = data.entry(key).or_insert(vec![]);
|
||||||
|
entry.push(val.clone());
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
/// List all data collected from called to `java.lang.Class.newInstance()` made by
|
||||||
|
/// `method`.
|
||||||
|
pub fn get_class_new_instance_data_for(
|
||||||
|
&self,
|
||||||
|
method: &IdMethod,
|
||||||
|
) -> HashMap<String, Vec<ReflectionClassNewInstData>> {
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
for val in self
|
||||||
|
.class_new_inst_data
|
||||||
|
.iter()
|
||||||
|
.filter(|data| &data.caller_method == method)
|
||||||
|
{
|
||||||
|
let key = format!("THESEUS_ADDR_{:08X}", val.addr);
|
||||||
|
let entry = data.entry(key).or_insert(vec![]);
|
||||||
|
entry.push(val.clone());
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
/// List all data collected from called to `java.lang.reflect.Constructor.newInstance()` made by
|
||||||
|
/// `method`.
|
||||||
|
pub fn get_cnstr_new_instance_data_for(
|
||||||
|
&self,
|
||||||
|
method: &IdMethod,
|
||||||
|
) -> HashMap<String, Vec<ReflectionCnstrNewInstData>> {
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
for val in self
|
||||||
|
.cnstr_new_inst_data
|
||||||
|
.iter()
|
||||||
|
.filter(|data| &data.caller_method == method)
|
||||||
|
{
|
||||||
|
let key = format!("THESEUS_ADDR_{:08X}", val.addr);
|
||||||
|
let entry = data.entry(key).or_insert(vec![]);
|
||||||
|
entry.push(val.clone());
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Structure storing the runtime information of a reflection call using
|
||||||
|
/// `java.lang.reflect.Method.invoke()`.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct ReflectionInvokeData {
|
pub struct ReflectionInvokeData {
|
||||||
|
/// The method called by `java.lang.reflect.Method.invoke()`
|
||||||
pub method: IdMethod,
|
pub method: IdMethod,
|
||||||
|
/// The method calling `java.lang.reflect.Method.invoke()`
|
||||||
|
pub caller_method: IdMethod,
|
||||||
|
/// Address where the call to `java.lang.reflect.Method.invoke()` was made in `caller_method`.
|
||||||
|
pub addr: usize,
|
||||||
// TODO: variable number of args?
|
// TODO: variable number of args?
|
||||||
// TODO: type of invoke?
|
// TODO: type of invoke?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structure storing the runtime information of a reflection instanciation using
|
||||||
|
/// `java.lang.Class.newInstance()`.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct ReflectionClassNewInstData {
|
pub struct ReflectionClassNewInstData {
|
||||||
|
/// The constructor called by `java.lang.Class.newInstance()`
|
||||||
pub constructor: IdMethod,
|
pub constructor: IdMethod,
|
||||||
|
/// The method calling `java.lang.Class.newInstance()`
|
||||||
|
pub caller_method: IdMethod,
|
||||||
|
/// Address where the call to `java.lang.Class.newInstance()` was made in `caller_method`.
|
||||||
|
pub addr: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structure storing the runtime information of a reflection instanciation using
|
||||||
|
/// `java.lang.reflect.Constructor.newInstance()`.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct ReflectionCnstrNewInstData {
|
pub struct ReflectionCnstrNewInstData {
|
||||||
|
/// The constructor calleb by `java.lang.reflect.Constructor.newInstance()`
|
||||||
pub constructor: IdMethod,
|
pub constructor: IdMethod,
|
||||||
|
/// The method calling `java.lang.reflect.Constructor.newInstance()`
|
||||||
|
pub caller_method: IdMethod,
|
||||||
|
/// Address where the call to `java.lang.Class.newInstance()` was made in `caller_method`.
|
||||||
|
pub addr: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RegistersInfo {
|
pub struct RegistersInfo {
|
||||||
|
|
@ -84,15 +190,29 @@ static CNSTR_GET_DEC_CLS: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Function passed to [`androscalpel::Apk::load_apk`] to label the instructions of interest.
|
||||||
|
fn labeling(_mth: &IdMethod, ins: &Instruction, addr: usize) -> Option<String> {
|
||||||
|
match ins {
|
||||||
|
Instruction::InvokeVirtual { method, .. }
|
||||||
|
if method == &*MTH_INVOKE
|
||||||
|
|| method == &*CLASS_NEW_INST
|
||||||
|
|| method == &*CNSTR_NEW_INST =>
|
||||||
|
{
|
||||||
|
Some(format!("THESEUS_ADDR_{addr:08X}"))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
pub fn transform_method(
|
pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<()> {
|
||||||
meth: &mut Method,
|
|
||||||
ref_invoke_data: &ReflectionInvokeData,
|
|
||||||
ref_class_new_inst_data: &ReflectionClassNewInstData,
|
|
||||||
ref_cnstr_new_inst_data: &ReflectionCnstrNewInstData,
|
|
||||||
) -> Result<()> {
|
|
||||||
// checking meth.annotations might be usefull at some point
|
// checking meth.annotations might be usefull at some point
|
||||||
|
//println!("{}", meth.descriptor.__str__());
|
||||||
|
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 cnstr_new_inst_data = ref_data.get_cnstr_new_instance_data_for(&meth.descriptor);
|
||||||
|
|
||||||
let code = meth
|
let code = meth
|
||||||
.code
|
.code
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
|
@ -111,13 +231,16 @@ pub fn transform_method(
|
||||||
};
|
};
|
||||||
let mut new_insns = vec![];
|
let mut new_insns = vec![];
|
||||||
let mut iter = code.insns.iter();
|
let mut iter = code.insns.iter();
|
||||||
|
let mut current_addr_label: Option<String> = 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 }
|
||||||
if method == &*MTH_INVOKE
|
if (method == &*MTH_INVOKE
|
||||||
|| method == &*CLASS_NEW_INST
|
|| method == &*CLASS_NEW_INST
|
||||||
|| method == &*CNSTR_NEW_INST =>
|
|| method == &*CNSTR_NEW_INST)
|
||||||
|
&& current_addr_label.is_some() =>
|
||||||
{
|
{
|
||||||
|
let addr_label = current_addr_label.as_ref().unwrap();
|
||||||
let (pseudo_insns, move_ret) = get_move_result(iter.clone());
|
let (pseudo_insns, move_ret) = get_move_result(iter.clone());
|
||||||
if move_ret.is_some() {
|
if move_ret.is_some() {
|
||||||
while move_ret.as_ref() != iter.next() {}
|
while move_ret.as_ref() != iter.next() {}
|
||||||
|
|
@ -130,36 +253,45 @@ pub fn transform_method(
|
||||||
panic!("Should not happen!")
|
panic!("Should not happen!")
|
||||||
};
|
};
|
||||||
// TODO: recover from failure
|
// TODO: recover from failure
|
||||||
let ins_block = if method == &*MTH_INVOKE {
|
if method == &*MTH_INVOKE {
|
||||||
get_invoke_block(
|
for ref_data in invoke_data.get(addr_label).unwrap_or(&vec![]) {
|
||||||
ref_invoke_data,
|
for ins in get_invoke_block(
|
||||||
args.as_slice(),
|
ref_data,
|
||||||
&mut register_info,
|
args.as_slice(),
|
||||||
&end_label,
|
&mut register_info,
|
||||||
move_ret.clone(),
|
&end_label,
|
||||||
)?
|
move_ret.clone(),
|
||||||
|
)? {
|
||||||
|
new_insns.push(ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if method == &*CLASS_NEW_INST {
|
} else if method == &*CLASS_NEW_INST {
|
||||||
get_class_new_inst_block(
|
for ref_data in class_new_inst_data.get(addr_label).unwrap_or(&vec![]) {
|
||||||
ref_class_new_inst_data,
|
for ins in get_class_new_inst_block(
|
||||||
args.as_slice(),
|
ref_data,
|
||||||
&mut register_info,
|
args.as_slice(),
|
||||||
&end_label,
|
&mut register_info,
|
||||||
move_ret.clone(),
|
&end_label,
|
||||||
)?
|
move_ret.clone(),
|
||||||
|
)? {
|
||||||
|
new_insns.push(ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if method == &*CNSTR_NEW_INST {
|
} else if method == &*CNSTR_NEW_INST {
|
||||||
get_cnstr_new_inst_block(
|
for ref_data in cnstr_new_inst_data.get(addr_label).unwrap_or(&vec![]) {
|
||||||
ref_cnstr_new_inst_data,
|
for ins in get_cnstr_new_inst_block(
|
||||||
args.as_slice(),
|
ref_data,
|
||||||
&mut register_info,
|
args.as_slice(),
|
||||||
&end_label,
|
&mut register_info,
|
||||||
move_ret.clone(),
|
&end_label,
|
||||||
)?
|
move_ret.clone(),
|
||||||
|
)? {
|
||||||
|
new_insns.push(ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("Should not happen!")
|
panic!("Should not happen!")
|
||||||
};
|
};
|
||||||
for ins in ins_block.into_iter() {
|
|
||||||
new_insns.push(ins);
|
|
||||||
}
|
|
||||||
new_insns.push(ins.clone());
|
new_insns.push(ins.clone());
|
||||||
if let Some(move_ret) = move_ret {
|
if let Some(move_ret) = move_ret {
|
||||||
for ins in pseudo_insns.into_iter() {
|
for ins in pseudo_insns.into_iter() {
|
||||||
|
|
@ -169,8 +301,16 @@ 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());
|
||||||
|
current_addr_label = None;
|
||||||
|
}
|
||||||
|
Instruction::Label { name } if name.starts_with("THESEUS_ADDR_") => {
|
||||||
|
current_addr_label = Some(name.clone());
|
||||||
|
new_insns.push(ins.clone());
|
||||||
}
|
}
|
||||||
ins => {
|
ins => {
|
||||||
|
if !ins.is_pseudo_ins() {
|
||||||
|
current_addr_label = None;
|
||||||
|
}
|
||||||
new_insns.push(ins.clone());
|
new_insns.push(ins.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ use std::collections::HashMap;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use androscalpel::{IdMethod, IdType};
|
use androscalpel::IdMethod;
|
||||||
|
|
||||||
use patcher::get_apk::{get_apk, ApkLocation};
|
use patcher::get_apk::{get_apk, ApkLocation};
|
||||||
use patcher::{
|
use patcher::{
|
||||||
transform_method, ReflectionClassNewInstData, ReflectionCnstrNewInstData, ReflectionInvokeData,
|
transform_method, ReflectionClassNewInstData, ReflectionCnstrNewInstData, ReflectionData,
|
||||||
|
ReflectionInvokeData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
@ -31,44 +32,82 @@ fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let mut apk = get_apk(&cli.apk);
|
let mut apk = get_apk(&cli.apk);
|
||||||
//println!("{:#?}", apk.list_classes());
|
//println!("{:#?}", apk.list_classes());
|
||||||
let class = apk
|
let reflection_data = ReflectionData {
|
||||||
.get_class_mut(
|
invoke_data: vec![
|
||||||
&IdType::new("Lcom/example/theseus/reflection/MainActivity;".into()).unwrap(),
|
ReflectionInvokeData {
|
||||||
)
|
method: IdMethod::from_smali(
|
||||||
.unwrap();
|
"Lcom/example/theseus/reflection/Reflectee;\
|
||||||
//println!("{:#?}", class.direct_methods.keys());
|
->transfer\
|
||||||
//println!("{:#?}", class.virtual_methods.keys());
|
(Ljava/lang/String;)Ljava/lang/String;",
|
||||||
for m in [
|
)
|
||||||
"Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectCall()V",
|
.unwrap(),
|
||||||
"Lcom/example/theseus/reflection/MainActivity;->callConstructorVirtualMethodReflectConstr()V",
|
caller_method: IdMethod::from_smali(
|
||||||
"Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectOldConst()V",
|
"Lcom/example/theseus/reflection/MainActivity;\
|
||||||
] {
|
->callVirtualMethodReflectCall()V",
|
||||||
let method = class
|
)
|
||||||
.virtual_methods
|
.unwrap(),
|
||||||
.get_mut(&IdMethod::from_smali(m).unwrap())
|
addr: 0x2B,
|
||||||
.unwrap();
|
},
|
||||||
transform_method(
|
ReflectionInvokeData {
|
||||||
method,
|
method: IdMethod::from_smali(
|
||||||
&ReflectionInvokeData {
|
"Lcom/example/theseus/reflection/Reflectee;\
|
||||||
method: IdMethod::from_smali(
|
->transfer(Ljava/lang/String;)Ljava/lang/String;",
|
||||||
"Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;)Ljava/lang/String;",
|
)
|
||||||
)
|
.unwrap(),
|
||||||
.unwrap(),
|
caller_method: IdMethod::from_smali(
|
||||||
},
|
"Lcom/example/theseus/reflection/MainActivity;\
|
||||||
&ReflectionClassNewInstData {
|
->callConstructorVirtualMethodReflectConstr()V",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
addr: 0x38,
|
||||||
|
},
|
||||||
|
ReflectionInvokeData {
|
||||||
|
method: IdMethod::from_smali(
|
||||||
|
"Lcom/example/theseus/reflection/Reflectee;\
|
||||||
|
->transfer(Ljava/lang/String;)Ljava/lang/String;",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
caller_method: IdMethod::from_smali(
|
||||||
|
"Lcom/example/theseus/reflection/MainActivity;\
|
||||||
|
->callVirtualMethodReflectOldConst()V",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
addr: 0x28,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
class_new_inst_data: vec![ReflectionClassNewInstData {
|
||||||
constructor: IdMethod::from_smali(
|
constructor: IdMethod::from_smali(
|
||||||
"Lcom/example/theseus/reflection/Reflectee;-><init>()V",
|
"Lcom/example/theseus/reflection/Reflectee;\
|
||||||
|
-><init>()V",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
caller_method: IdMethod::from_smali(
|
||||||
&ReflectionCnstrNewInstData{
|
"Lcom/example/theseus/reflection/MainActivity;\
|
||||||
|
->callVirtualMethodReflectOldConst()V",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
addr: 0x12,
|
||||||
|
}],
|
||||||
|
cnstr_new_inst_data: vec![ReflectionCnstrNewInstData {
|
||||||
constructor: IdMethod::from_smali(
|
constructor: IdMethod::from_smali(
|
||||||
"Lcom/example/theseus/reflection/Reflectee;-><init>(Ljava/lang/String;)V",
|
"Lcom/example/theseus/reflection/Reflectee;\
|
||||||
|
-><init>(Ljava/lang/String;)V",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
caller_method: IdMethod::from_smali(
|
||||||
)
|
"Lcom/example/theseus/reflection/MainActivity;\
|
||||||
.unwrap();
|
->callConstructorVirtualMethodReflectConstr()V",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
addr: 0x22,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
for method in reflection_data.get_method_referenced().iter() {
|
||||||
|
let class = apk.get_class_mut(&method.class_).unwrap();
|
||||||
|
//println!("{:#?}", class.direct_methods.keys());
|
||||||
|
//println!("{:#?}", class.virtual_methods.keys());
|
||||||
|
let method = class.virtual_methods.get_mut(method).unwrap();
|
||||||
|
transform_method(method, &reflection_data).unwrap();
|
||||||
}
|
}
|
||||||
let mut dex_files = vec![];
|
let mut dex_files = vec![];
|
||||||
let mut files = apk.gen_raw_dex().unwrap();
|
let mut files = apk.gen_raw_dex().unwrap();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue