directly define StackConsumer in frida
This commit is contained in:
parent
a0cb49fd77
commit
28f5ac772c
5 changed files with 54 additions and 84 deletions
|
|
@ -2,20 +2,3 @@
|
||||||
|
|
||||||
Collect runtime information about reflection operation done by en application to feed them to the patcher.
|
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 .
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package theseus.android;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.lang.StackWalker.StackFrame;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
class StackConsumer implements Consumer<StackFrame> {
|
|
||||||
|
|
||||||
public ArrayList<StackFrame> stack;
|
|
||||||
|
|
||||||
public StackConsumer() {
|
|
||||||
this.stack = new ArrayList<StackFrame>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(StackFrame frame) {
|
|
||||||
stack.add(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StackFrame[] getStack() {
|
|
||||||
return this.stack.toArray(new StackFrame[] {});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Function<? super Stream<StackWalker.StackFrame>, StackFrame[]> walkNFrame(int n) {
|
|
||||||
return s -> { s.limit(n).forEach(this); return this.getStack(); };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
|
|
||||||
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="${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}" -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"
|
|
||||||
|
|
||||||
base64 "${BUILD_F}/classes/classes.dex" > "${OUT_FILE}"
|
|
||||||
|
|
@ -330,11 +330,6 @@ def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: Tex
|
||||||
|
|
||||||
with FRIDA_SCRIPT.open("r") as file:
|
with FRIDA_SCRIPT.open("r") as file:
|
||||||
jsscript = file.read()
|
jsscript = file.read()
|
||||||
with STACK_CONSUMER_B64.open("r") as file:
|
|
||||||
jsscript = jsscript.replace(
|
|
||||||
"<PYTHON REPLACE StackConsumer.dex.b64>",
|
|
||||||
file.read().replace("\n", "").strip(),
|
|
||||||
)
|
|
||||||
|
|
||||||
pid = device.spawn([app])
|
pid = device.spawn([app])
|
||||||
session = device.attach(pid)
|
session = device.attach(pid)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,57 @@ function dump_classloaders() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerStackConsumer() {
|
||||||
|
const Consumer = Java.use('java.util.function.Consumer');
|
||||||
|
const Method = Java.use('java.lang.reflect.Method');
|
||||||
|
const ArrayList = Java.use('java.util.ArrayList');
|
||||||
|
const StackFrame = Java.use('java.lang.StackWalker$StackFrame');
|
||||||
|
|
||||||
|
// Finding r8 optimized method for the Consumer interface
|
||||||
|
let requiredMethods = Consumer.class.getDeclaredMethods();
|
||||||
|
var lambdamethod = '';
|
||||||
|
requiredMethods.forEach(m => {
|
||||||
|
var meth = Java.cast(m, Method);
|
||||||
|
let methodname = meth.getName();
|
||||||
|
if (methodname.startsWith("$r8$lambda$")) {
|
||||||
|
lambdamethod = methodname;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return Java.registerClass({
|
||||||
|
name: "theseus.android.StackConsumer",
|
||||||
|
implements: [Consumer],
|
||||||
|
fields: {
|
||||||
|
stack: 'java.util.ArrayList',
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
'<init>': [{
|
||||||
|
returnType: 'void',
|
||||||
|
argumentTypes: [],
|
||||||
|
implementation: function () {
|
||||||
|
this.stack.value = ArrayList.$new();
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
accept(frame) {
|
||||||
|
var castedFrame = Java.cast(frame, StackFrame);
|
||||||
|
this.stack.value.add(castedFrame);
|
||||||
|
},
|
||||||
|
getStack: [{
|
||||||
|
returnType: '[Ljava.lang.StackWalker$StackFrame;',
|
||||||
|
argumentTypes: [],
|
||||||
|
implementation: function () {
|
||||||
|
return this.stack.value.toArray(Java.array('java.lang.StackWalker$StackFrame', []));
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
andThen(cons) {
|
||||||
|
return this.$super.andThen(cons);
|
||||||
|
},
|
||||||
|
lambda$andThen$0(consumer, obj) {},
|
||||||
|
['_' + lambdamethod]: function (cons1, cons2, obj) {}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// recv('dump-class-loaders', function onMessage(msg) {dump_classloaders()});
|
// recv('dump-class-loaders', function onMessage(msg) {dump_classloaders()});
|
||||||
|
|
||||||
Java.perform(() => {
|
Java.perform(() => {
|
||||||
|
|
@ -44,12 +95,14 @@ Java.perform(() => {
|
||||||
const System = Java.use('java.lang.System');
|
const System = Java.use('java.lang.System');
|
||||||
const Arrays = Java.use('java.util.Arrays');
|
const Arrays = Java.use('java.util.Arrays');
|
||||||
|
|
||||||
|
/*
|
||||||
const myClassLoader = InMemoryDexClassLoader.$new(
|
const myClassLoader = InMemoryDexClassLoader.$new(
|
||||||
ByteBuffer.wrap(Base64.decode("<PYTHON REPLACE StackConsumer.dex.b64>", Base64.DEFAULT.value)),
|
ByteBuffer.wrap(Base64.decode("<PYTHON REPLACE StackConsumer.dex.b64>", Base64.DEFAULT.value)),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const StackConsumer = Java.ClassFactory.get(myClassLoader).use("theseus.android.StackConsumer");
|
const StackConsumer = Java.ClassFactory.get(myClassLoader).use("theseus.android.StackConsumer");
|
||||||
|
*/
|
||||||
|
const StackConsumer = registerStackConsumer();
|
||||||
|
|
||||||
const get_stack = function () {
|
const get_stack = function () {
|
||||||
// console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
|
// console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue