99 lines
2.9 KiB
Rust
99 lines
2.9 KiB
Rust
use std::collections::HashMap;
|
|
use std::io::Cursor;
|
|
use std::path::PathBuf;
|
|
|
|
use androscalpel::{IdMethod, IdType};
|
|
|
|
use patcher::get_apk::{get_apk, ApkLocation};
|
|
use patcher::{
|
|
transform_method, ReflectionClassNewInstData, ReflectionCnstrNewInstData, ReflectionInvokeData,
|
|
};
|
|
|
|
use clap::Parser;
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[command(version, about, long_about = None, arg_required_else_help = true)]
|
|
struct Cli {
|
|
#[clap(flatten)]
|
|
apk: ApkLocation,
|
|
#[arg(short, long)]
|
|
out: PathBuf,
|
|
#[arg(short, long)]
|
|
keystore: PathBuf,
|
|
#[arg(short, long)]
|
|
zipalign: Option<PathBuf>,
|
|
#[arg(short, long)]
|
|
apksigner: Option<PathBuf>,
|
|
}
|
|
|
|
fn main() {
|
|
env_logger::init();
|
|
let cli = Cli::parse();
|
|
let mut apk = get_apk(&cli.apk);
|
|
//println!("{:#?}", apk.list_classes());
|
|
let class = apk
|
|
.get_class_mut(
|
|
&IdType::new("Lcom/example/theseus/reflection/MainActivity;".into()).unwrap(),
|
|
)
|
|
.unwrap();
|
|
//println!("{:#?}", class.direct_methods.keys());
|
|
//println!("{:#?}", class.virtual_methods.keys());
|
|
for m in [
|
|
"Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectCall()V",
|
|
"Lcom/example/theseus/reflection/MainActivity;->callConstructorVirtualMethodReflectConstr()V",
|
|
"Lcom/example/theseus/reflection/MainActivity;->callVirtualMethodReflectOldConst()V",
|
|
] {
|
|
let method = class
|
|
.virtual_methods
|
|
.get_mut(&IdMethod::from_smali(m).unwrap())
|
|
.unwrap();
|
|
transform_method(
|
|
method,
|
|
&ReflectionInvokeData {
|
|
method: IdMethod::from_smali(
|
|
"Lcom/example/theseus/reflection/Reflectee;->transfer(Ljava/lang/String;)Ljava/lang/String;",
|
|
)
|
|
.unwrap(),
|
|
},
|
|
&ReflectionClassNewInstData {
|
|
constructor: IdMethod::from_smali(
|
|
"Lcom/example/theseus/reflection/Reflectee;-><init>()V",
|
|
)
|
|
.unwrap(),
|
|
},
|
|
&ReflectionCnstrNewInstData{
|
|
constructor: IdMethod::from_smali(
|
|
"Lcom/example/theseus/reflection/Reflectee;-><init>(Ljava/lang/String;)V",
|
|
)
|
|
.unwrap(),
|
|
},
|
|
)
|
|
.unwrap();
|
|
}
|
|
let mut dex_files = vec![];
|
|
let mut files = apk.gen_raw_dex().unwrap();
|
|
let mut i = 0;
|
|
loop {
|
|
let name = if i == 0 {
|
|
"classes.dex".into()
|
|
} else {
|
|
format!("classes{}.dex", i + 1)
|
|
};
|
|
if let Some(file) = files.remove(&name) {
|
|
dex_files.push(Cursor::new(file))
|
|
} else {
|
|
break;
|
|
}
|
|
i += 1;
|
|
}
|
|
// TODO: aapt would be a lot more stable
|
|
apk_frauder::replace_dex(
|
|
cli.apk.path.unwrap(),
|
|
cli.out,
|
|
&mut dex_files,
|
|
cli.keystore,
|
|
cli.zipalign,
|
|
cli.apksigner,
|
|
None::<HashMap<_, Option<Cursor<&[u8]>>>>,
|
|
);
|
|
}
|