From 91fd0137d8c663fcc0807ac3957e65173012498d Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Tue, 4 Mar 2025 17:38:35 +0100 Subject: [PATCH] improvement and add is_static data --- frida/README.md | 18 ++++++++++++++++ frida/consumer/StackConsumer.java | 2 +- frida/consumer/build.sh | 28 +++++++++++++++++-------- frida/theseus_frida/__init__.py | 35 ++++++++++++++----------------- frida/theseus_frida/hook.js | 4 +++- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/frida/README.md b/frida/README.md index 1dc9c5b..1d07d23 100644 --- a/frida/README.md +++ b/frida/README.md @@ -1,3 +1,21 @@ # Theseus Data Collector Collect runtime information about reflection operation done by en application to feed them to the patcher. + +The Frida hook uses a Java class to collect the stack information, before building/installing the python package, you need to build the class: + +```shell + +# If the default values do not match, set the variables: +# +# JAVAC: path to the java compiler +# ANDROID_SDK: path to the android sdk +# VERSION: Android SDK version to use +# D8: path to the d8 executable +# ANDROID_JAR: path to the android.jar file to link +# BUILD_F: build folder (will be delated if exist) +# OUT_FILE: the file where to put the b64 of the compiled dex + +bash consumer/build.sh +poetry build # / poetry install / pip install . +``` diff --git a/frida/consumer/StackConsumer.java b/frida/consumer/StackConsumer.java index 8fbae47..9ac5d2e 100644 --- a/frida/consumer/StackConsumer.java +++ b/frida/consumer/StackConsumer.java @@ -9,7 +9,7 @@ class StackConsumer implements Consumer { public ArrayList stack; public StackConsumer() { - this.stack = new ArrayList(); + this.stack = new ArrayList(); } @Override diff --git a/frida/consumer/build.sh b/frida/consumer/build.sh index 201516d..363e6c4 100644 --- a/frida/consumer/build.sh +++ b/frida/consumer/build.sh @@ -1,20 +1,30 @@ #!/usr/bin/env bash -JAVAC='/usr/lib/jvm/java-17-openjdk/bin/javac' -SDK_TOOLS="${HOME}/Android/Sdk/" -VERSION='34.0.0' -D8="${SDK_TOOLS}/build-tools/${VERSION}/d8" -VERSION_B=$(echo "${VERSION}" | sed 's/\..*//') -ANDROID_JAR="${SDK_TOOLS}/platforms/android-${VERSION_B}/android.jar" +JAVAC="${JAVAC:-/usr/lib/jvm/java-17-openjdk/bin/javac}" +ANDROID_SDK="${ANDROID_SDK:-${HOME}/Android/Sdk/}" +VERSION="${VERSION:-34.0.0}" +D8="${D8:-${ANDROID_SDK}/build-tools/${VERSION}/d8}" +VERSION_B="${VERSION_B:-$(echo "${VERSION}" | sed 's/\..*//')}" +ANDROID_JAR="${ANDROID_JAR:-${ANDROID_SDK}/platforms/android-${VERSION_B}/android.jar}" FOLDER=$(dirname "$(realpath $0)") -BUILD_F="${FOLDER}/build" -OUT_FILE="${FOLDER}/../theseus_frida/StackConsumer.dex.b64" +BUILD_F="${BUILD_F:-${FOLDER}/build}" +OUT_FILE="${OUT_FILE:-${FOLDER}/../theseus_frida/StackConsumer.dex.b64}" + +echo "JAVAC = ${JAVAC}" +echo "ANDROID_SDK = ${ANDROID_SDK}" +echo "VERSION = ${VERSION}" +echo "D8 = ${D8}" +# echo "VERSION_B = ${VERSION_B}" +echo "ANDROID_JAR = ${ANDROID_JAR}" +echo "BUILD_F = ${BUILD_F}" +echo "OUT_FILE = ${OUT_FILE}" + rm -r "${BUILD_F}" mkdir "${BUILD_F}" -"${JAVAC}" -d "${BUILD_F}" -classpath "${ANDROID_JAR}" "${FOLDER}/StackConsumer.java" +"${JAVAC}" -Xlint -d "${BUILD_F}" -classpath "${ANDROID_JAR}" "${FOLDER}/StackConsumer.java" mkdir "${BUILD_F}/classes" "${D8}" --classpath "${ANDROID_JAR}" "${BUILD_F}/theseus/android/StackConsumer.class" --output "${BUILD_F}/classes" diff --git a/frida/theseus_frida/__init__.py b/frida/theseus_frida/__init__.py index 6953104..271397a 100644 --- a/frida/theseus_frida/__init__.py +++ b/frida/theseus_frida/__init__.py @@ -7,6 +7,9 @@ from pathlib import Path import frida # type: ignore from androguard.core.apk import get_apkid # type: ignore +from loguru import logger # type: ignore + +logger.remove() # remove androguard logs FRIDA_SCRIPT = Path(__file__).parent / "hook.js" STACK_CONSUMER_B64 = Path(__file__).parent / "StackConsumer.dex.b64" @@ -35,32 +38,25 @@ def print_stack(stack, prefix: str): print(f"{prefix}{frame['method']}:{frame['bytecode_index']}{native}") -# def get_ty(java_name: str) -> str: -# """Return the android name from the java name of a class / type""" -# # TODO: array -# # TODO: scalar -# if java_name == "V": # tmp stub -# return "V" -# return f"L{java_name.replace('.', '/')};" - - -# def get_method_id(method_data) -> str: -# """Get a method descriptor from the different elements collected from the methods.""" -# name = method_data["name"] -# ret = get_ty(method_data["ret"]) -# cls = get_ty(method_data["class"]) -# args = "".join(map(get_ty, method_data["args"])) -# return f"{cls}->{name}({args}){ret}" - - def handle_invoke_data(data, data_storage: dict): method = data["method"] + # TODO: good idea? + if method in [ + "Landroid/view/View;->getTranslationZ()F", + "Landroid/view/View;->getElevation()F", + ]: + return if len(data["stack"]) == 0: return caller_method = data["stack"][0]["method"] addr = data["stack"][0]["bytecode_index"] + is_static = data["is_static"] + if is_static: + is_static_str = " (static)" + else: + is_static_str = "" print("Method.Invoke:") - print(f" called: {method}") + print(f" called: {method}{is_static_str}") print(f" by: {caller_method}") print(f" at: 0x{addr:08x}") # print(f" stack:") @@ -72,6 +68,7 @@ def handle_invoke_data(data, data_storage: dict): "method": method, "caller_method": caller_method, "addr": addr, + "is_static": is_static, } ) diff --git a/frida/theseus_frida/hook.js b/frida/theseus_frida/hook.js index f50dea1..612ce6a 100644 --- a/frida/theseus_frida/hook.js +++ b/frida/theseus_frida/hook.js @@ -67,6 +67,7 @@ Java.perform(() => { const Method = Java.use("java.lang.reflect.Method"); const Class = Java.use("java.lang.Class"); const Constructor = Java.use("java.lang.reflect.Constructor"); + const Modifier = Java.use("java.lang.reflect.Modifier"); Method.invoke.overload( "java.lang.Object", "[Ljava.lang.Object;" // the Frida type parser is so cursted... ).implementation = function (obj, args) { @@ -80,7 +81,8 @@ Java.perform(() => { "args": this.getParameterTypes().map((argty) => argty.getName() ), "ret": this.getReturnType().getName(), },*/ - "stack": get_stack() + "stack": get_stack(), + "is_static": Modifier.isStatic(this.getModifiers()), } }); return this.invoke(obj, args);