wip
This commit is contained in:
parent
2d7c69cb05
commit
e34415857d
9 changed files with 116 additions and 18 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use androscalpel::{Apk, IdType};
|
use androscalpel::{Apk, IdType};
|
||||||
|
|
@ -38,13 +38,16 @@ fn insert_code_naive(apk: &mut Apk, data: &RuntimeData) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_code_model_class_loaders(apk: &mut Apk, data: &RuntimeData) -> Result<()> {
|
fn insert_code_model_class_loaders(apk: &mut Apk, data: &RuntimeData) -> Result<()> {
|
||||||
|
let mut class_defined = apk.list_classes();
|
||||||
let mut class_loaders = HashMap::new();
|
let mut class_loaders = HashMap::new();
|
||||||
class_loaders.insert(
|
class_loaders.insert(
|
||||||
"MAIN".to_string(),
|
"MAIN".to_string(),
|
||||||
ClassLoader {
|
ClassLoader {
|
||||||
|
id: "MAIN".to_string(),
|
||||||
parent: None,
|
parent: None,
|
||||||
class: IdType::from_smali("Ljava/lang/Boolean;").unwrap(),
|
class: IdType::from_smali("Ljava/lang/Boolean;").unwrap(),
|
||||||
apk: ApkOrRef::Ref(apk),
|
apk: ApkOrRef::Ref(apk),
|
||||||
|
renamed_classes: HashSet::new(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
for dyn_data in &data.dyn_code_load {
|
for dyn_data in &data.dyn_code_load {
|
||||||
|
|
@ -54,17 +57,25 @@ fn insert_code_model_class_loaders(apk: &mut Apk, data: &RuntimeData) -> Result<
|
||||||
let file = File::open(file)?;
|
let file = File::open(file)?;
|
||||||
apk.add_code(file, crate::labeling, false)?;
|
apk.add_code(file, crate::labeling, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(!class_loaders.contains_key(&dyn_data.classloader));
|
assert!(!class_loaders.contains_key(&dyn_data.classloader));
|
||||||
class_loaders.insert(
|
|
||||||
dyn_data.classloader.clone(),
|
let classes = apk.list_classes();
|
||||||
ClassLoader {
|
let mut class_loader = ClassLoader {
|
||||||
parent: None,
|
id: dyn_data.classloader.clone(),
|
||||||
class,
|
parent: None,
|
||||||
apk: ApkOrRef::Owned(apk),
|
class,
|
||||||
},
|
apk: ApkOrRef::Owned(apk),
|
||||||
);
|
renamed_classes: HashSet::new(),
|
||||||
|
};
|
||||||
|
let collisions = class_defined.intersection(&classes);
|
||||||
|
for cls in collisions {
|
||||||
|
class_loader.rename_classdef(cls);
|
||||||
|
}
|
||||||
|
class_defined.extend(classes);
|
||||||
|
|
||||||
|
class_loaders.insert(dyn_data.classloader.clone(), class_loader);
|
||||||
}
|
}
|
||||||
// TODO: list colliding classes
|
|
||||||
// TODO: rename colliding classes according to class laoder
|
// TODO: rename colliding classes according to class laoder
|
||||||
// TODO: get the ClassLoader::parent values...
|
// TODO: get the ClassLoader::parent values...
|
||||||
// TODO: model the delegation behavior and rename ref to class accordingly
|
// TODO: model the delegation behavior and rename ref to class accordingly
|
||||||
|
|
@ -75,9 +86,11 @@ fn insert_code_model_class_loaders(apk: &mut Apk, data: &RuntimeData) -> Result<
|
||||||
/// Structure modelizing a class loader.
|
/// Structure modelizing a class loader.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
struct ClassLoader<'a> {
|
struct ClassLoader<'a> {
|
||||||
|
pub id: String,
|
||||||
pub parent: Option<String>,
|
pub parent: Option<String>,
|
||||||
pub class: IdType,
|
pub class: IdType,
|
||||||
pub apk: ApkOrRef<'a>,
|
pub apk: ApkOrRef<'a>,
|
||||||
|
pub renamed_classes: HashSet<IdType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassLoader<'_> {
|
impl ClassLoader<'_> {
|
||||||
|
|
@ -87,6 +100,16 @@ impl ClassLoader<'_> {
|
||||||
ApkOrRef::Ref(ref mut apk) => apk,
|
ApkOrRef::Ref(ref mut apk) => apk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rename_classdef(&mut self, cls: &IdType) {
|
||||||
|
use androscalpel::SmaliName;
|
||||||
|
println!(
|
||||||
|
"TODO: rename {} -> {}_{}",
|
||||||
|
cls.try_to_smali().unwrap(),
|
||||||
|
cls.try_to_smali().unwrap(),
|
||||||
|
self.id
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
|
|
||||||
1
patcher/tst.sh
Normal file
1
patcher/tst.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
cargo run --bin patcher -- --code-loading-patch-strategy model-class-loaders --runtime-data ./tst/runtime.json --path ../test_apks/dynloading/build/test_dynloading.apk --out /tmp/patched_dynloading.apk -k ../test_apks/dynloading/ToyKey.keystore -z $(which zipalign) -a $(which apksigner)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
71
patcher/tst/runtime.json
Normal file
71
patcher/tst/runtime.json
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
"invoke_data": [
|
||||||
|
{
|
||||||
|
"method": "Lcom/example/theseus/dynloading/AMain;->getColliderId()Ljava/lang/String;",
|
||||||
|
"caller_method": "Lcom/example/theseus/dynloading/MainActivity;->indirectWithoutParent()V",
|
||||||
|
"addr": 33,
|
||||||
|
"is_static": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "Lcom/example/theseus/dynloading/AMain;->getColliderId()Ljava/lang/String;",
|
||||||
|
"caller_method": "Lcom/example/theseus/dynloading/MainActivity;->indirectWithParent()V",
|
||||||
|
"addr": 39,
|
||||||
|
"is_static": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "Lcom/example/theseus/dynloading/Collider;->getColliderId()Ljava/lang/String;",
|
||||||
|
"caller_method": "Lcom/example/theseus/dynloading/MainActivity;->directWithoutParent()V",
|
||||||
|
"addr": 33,
|
||||||
|
"is_static": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "Lcom/example/theseus/dynloading/Collider;->getColliderId()Ljava/lang/String;",
|
||||||
|
"caller_method": "Lcom/example/theseus/dynloading/MainActivity;->directWithParent()V",
|
||||||
|
"addr": 39,
|
||||||
|
"is_static": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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/dynloading/MainActivity;-><init>()V",
|
||||||
|
"caller_method": "Landroid/app/AppComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;",
|
||||||
|
"addr": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cnstr_new_inst_data": [],
|
||||||
|
"dyn_code_load": [
|
||||||
|
{
|
||||||
|
"classloader_class": "Ldalvik/system/PathClassLoader;",
|
||||||
|
"classloader": "0dfe1ce0",
|
||||||
|
"files": [
|
||||||
|
"./tst/dex/PathClassLoader_0dfe1ce0_09d17bb5de42d5d9.bytecode"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"classloader_class": "Ldalvik/system/PathClassLoader;",
|
||||||
|
"classloader": "0b4ac535",
|
||||||
|
"files": [
|
||||||
|
"./tst/dex/PathClassLoader_0b4ac535_09d17bb5de42d5d9.bytecode"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"classloader_class": "Ldalvik/system/PathClassLoader;",
|
||||||
|
"classloader": "0ceee91e",
|
||||||
|
"files": [
|
||||||
|
"./tst/dex/PathClassLoader_0ceee91e_09d17bb5de42d5d9.bytecode"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"classloader_class": "Ldalvik/system/PathClassLoader;",
|
||||||
|
"classloader": "0545b1a9",
|
||||||
|
"files": [
|
||||||
|
"./tst/dex/PathClassLoader_0545b1a9_09d17bb5de42d5d9.bytecode"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
5
theseus_autopatcher/.gitignore
vendored
5
theseus_autopatcher/.gitignore
vendored
|
|
@ -1,3 +1,2 @@
|
||||||
dist
|
# Created by venv; see https://docs.python.org/3/library/venv.html
|
||||||
__pycache__
|
*
|
||||||
src/theseus_autopatcher/patcher_86_64_musl
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from theseus_frida import collect_runtime
|
||||||
|
|
||||||
def get_android_sdk_path() -> Path | None:
|
def get_android_sdk_path() -> Path | None:
|
||||||
if "ANDROID_HOME" in os.environ:
|
if "ANDROID_HOME" in os.environ:
|
||||||
return os.environ["ANDROID_HOME"]
|
return Path(os.environ["ANDROID_HOME"])
|
||||||
default = Path.home() / "Android" / "Sdk"
|
default = Path.home() / "Android" / "Sdk"
|
||||||
if default.exists():
|
if default.exists():
|
||||||
return default
|
return default
|
||||||
|
|
@ -29,10 +29,10 @@ def get_build_tools_path(toolname: str) -> Path | None:
|
||||||
|
|
||||||
path = which(toolname)
|
path = which(toolname)
|
||||||
if path is not None:
|
if path is not None:
|
||||||
return path
|
return Path(path)
|
||||||
path = which(toolname + ".exe")
|
path = which(toolname + ".exe")
|
||||||
if path is not None:
|
if path is not None:
|
||||||
return path
|
return Path(path)
|
||||||
|
|
||||||
sdk = get_android_sdk_path()
|
sdk = get_android_sdk_path()
|
||||||
if sdk is None:
|
if sdk is None:
|
||||||
|
|
@ -54,8 +54,12 @@ def get_build_tools_path(toolname: str) -> Path | None:
|
||||||
def get_keytool_path() -> Path | None:
|
def get_keytool_path() -> Path | None:
|
||||||
path = which("keytool")
|
path = which("keytool")
|
||||||
if path is not None:
|
if path is not None:
|
||||||
return path
|
return Path(path)
|
||||||
return which("keytool.exe")
|
path = which("keytool.exe")
|
||||||
|
if path is not None:
|
||||||
|
return Path(path)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def gen_keystore(keytool: Path, storepath: Path):
|
def gen_keystore(keytool: Path, storepath: Path):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue