Java.perform(() => { /* //const StackFrameInfo = Java.use('java.lang.StackFrameInfo'); const Consumer = Java.use('java.util.function.Consumer'); const System = Java.use('java.lang.System'); */ const StackWalker = Java.use('java.lang.StackWalker'); const StackWalkerOptions = Java.use('java.lang.StackWalker$Option'); const StackWalkerOptionsShowHidden = StackWalkerOptions.valueOf("SHOW_HIDDEN_FRAMES"); const StackWalkerOptionsShowReflect = StackWalkerOptions.valueOf("SHOW_REFLECT_FRAMES"); const StackWalkerOptionsRetainClassReference = StackWalkerOptions.valueOf("RETAIN_CLASS_REFERENCE"); const StackFrame = Java.use('java.lang.StackWalker$StackFrame'); const Base64 = Java.use("android.util.Base64"); const InMemoryDexClassLoader = Java.use("dalvik.system.InMemoryDexClassLoader"); const ByteBuffer = Java.use("java.nio.ByteBuffer"); const myClassLoader = InMemoryDexClassLoader.$new( ByteBuffer.wrap(Base64.decode("", Base64.DEFAULT.value)), null ); const StackConsumer = Java.ClassFactory.get(myClassLoader).use("theseus.android.StackConsumer"); const get_stack = function () { var stackConsumer = StackConsumer.$new(); var walker = StackWalker.getInstance(StackWalkerOptionsRetainClassReference); walker.forEach(stackConsumer); //send({"type": "stack", "data": stackConsumer.getStack()}); return stackConsumer.getStack().map((frame) => { return { "bytecode_index": frame.getByteCodeIndex(), "is_native": frame.isNativeMethod(), "method": frame.getDeclaringClass().descriptorString() + "->" + frame.getMethodName() + frame.getDescriptor(), //{ //"descriptor": frame.getDescriptor(), //"name": frame.getMethodName(), //"class": frame.getDeclaringClass().descriptorString(), // Broken for some reason //"args": frame.getMethodType().parameterArray().map((argty) => argty.getName()), //"ret": frame.getMethodType().returnType().getName(), //} }; }); }; const get_method_dsc = function (mth) { // TODO: find a way to use MethodType (https://developer.android.com/reference/java/lang/invoke/MethodType) // MethodType.descriptorString() return mth.getDeclaringClass().descriptorString() + "->" + mth.getName() + "(" + mth.getParameterTypes().map((argty) => argty.descriptorString()).join('') + ")" + mth.getReturnType().descriptorString(); }; const get_constr_dsc = function (cnstr) { // TODO: find a way to use MethodType (https://developer.android.com/reference/java/lang/invoke/MethodType) // MethodType.descriptorString() return cnstr.getDeclaringClass().descriptorString() + "->" + "" + "(" + cnstr.getParameterTypes().map((argty) => argty.descriptorString()).join('') + ")V"; }; const Method = Java.use("java.lang.reflect.Method"); const Class = Java.use("java.lang.Class"); const Constructor = Java.use("java.lang.reflect.Constructor"); Method.invoke.overload( "java.lang.Object", "[Ljava.lang.Object;" // the Frida type parser is so cursted... ).implementation = function (obj, args) { send({ "type": "invoke", "data": { "method": get_method_dsc(this), /*{ "name": this.getName(), "class": this.getDeclaringClass().getName(), "args": this.getParameterTypes().map((argty) => argty.getName() ), "ret": this.getReturnType().getName(), },*/ "stack": get_stack() } }); return this.invoke(obj, args); }; Class.newInstance.overload( ).implementation = function () { send({ "type": "class-new-inst", "data": { "constructor": this.descriptorString() + "->()V", /*{ "name": "", "class": this.getName(), "args": [], "ret": "V", },*/ "caller_method": "?", "addr": 0, "stack": get_stack() } }); return this.newInstance(); }; Constructor.newInstance.overload( "[Ljava.lang.Object;" ).implementation = function (args) { send({ "type": "cnstr-new-isnt", "data": { "constructor": get_constr_dsc(this), /* { "name": "", "class": this.getDeclaringClass().getName(), "args": this.getParameterTypes().map((argty) => argty.getName()), "ret": "V", }, */ "caller_method": "?", "addr": 0, "stack": get_stack() } }); return this.newInstance(args); }; });