android_of_theseus/patcher/src/main.rs

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]>>>>,
);
}