frida / frida-java-bridge

Java runtime interop from Frida
318 stars 118 forks source link

Support arrays of array #314

Closed histausse closed 2 months ago

histausse commented 2 months ago

Add test for #313 and implement a fix.

histausse commented 2 months ago

(I did not manage to get frida to use a different version of the bridge, so the only tests I did are the one run by make check)

nezza commented 2 months ago

I tested this patch and can confirm it fixes issues with nested arrays. Thanks a lot!

@histausse For me the instructions here worked well: https://github.com/frida/frida-tools/blob/main/README.md#loading-your-custom-frida-java-bridge As long as your frida-version is compatible with the frida-tools tag you checked out it should work well. Which issue did you run into?

histausse commented 2 months ago

I tested this patch and can confirm it fixes issues with nested arrays. Thanks a lot!

@histausse For me the instructions here worked well: https://github.com/frida/frida-tools/blob/main/README.md#loading-your-custom-frida-java-bridge As long as your frida-version is compatible with the frida-tools tag you checked out it should work well. Which issue did you run into?

The bridge used is just not the modified one. Here is how a tried to add an "hello world" in Java.use:

$ git clone https://github.com/frida/frida-tools.git
$ cd frida-tools/
$ git checkout 12.3.0
$ python -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$(pwd)
$ echo $PYTHONPATH
/tmp/tmp.9HAJacCmdN/frida-tools
$ cd agents/tracer/
$ npm link frida-java-bridge
$ # edit agents/tracer/agent.ts and agents/tracer/node_modules/frida-java-bridge/index.js and run npm run watch in another term
$ cd -
$ head -n 3 agents/tracer/agent.ts
Object.defineProperty(global, 'Java', { value: require('frida-java-bridge') });;

class Agent {
$ grep -A 2 -B 2 Hello agents/tracer/node_modules/frida-java-bridge/index.js

  use (className, options) {
    console.log("Hello World!");
    return this.classFactory.use(className, options);
  }
$ pip install .
$ frida -U TestClassLoader
     ____
    / _  |   Frida 16.2.1 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to Android Emulator 5554 (id=emulator-5554)

[Android Emulator 5554::TestClassLoader ]-> Java.use("java.lang.Class")
"<class: java.lang.Class>"
[Android Emulator 5554::TestClassLoader ]->

I'm verry unfamilliar with javascript dependencies management (and javascript in general) so it's probably on me, do you see any obvious mistake in my process?

nezza commented 2 months ago

Hmmm I did pretty much the same, only difference is that I have the modification in agent.ts on the bottom of the file - have you checked whether your PYTHONPATH is respected? I.e. is the correct frida-tools loaded? Do you see npm watch doing something when you modify the file? (Not a JS dependency expert at all either.)

histausse commented 2 months ago

I tried again with Object.defineProperty at the end of the file, but same issue. Frida is not installed system-wide so I'm pretty sure the one used is the one in the venv, starting frida from python confirmed it (inspect.getfile returned /tmp/tmp.VE2pOmrdVm/frida-tools/frida_tools/repl.py, and the script in /tmp/tmp.VE2pOmrdVm/frida-tools/frida_tools/tracer_agent.js is the one generated by npm run watch and contains modification made to frida-java-bridge, but they are not reflected in the REPL:

$ grep PLOP /tmp/tmp.VE2pOmrdVm/frida-tools/frida_tools/tracer_agent.js
    this.PLOP = "PLOP";
$ grep -A 3 myfun /tmp/tmp.VE2pOmrdVm/frida-tools/frida_tools/tracer_agent.js
  myfunc() {
    return "plopliplop";
  }
$ python
Python 3.12.3 (main, Apr 23 2024, 09:16:07) [GCC 13.2.1 20240417] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from frida_tools.repl import main
>>> import inspect
>>> inspect.getfile(main)
'/tmp/tmp.VE2pOmrdVm/frida-tools/frida_tools/repl.py'
>>> import sys
>>> sys.argv = ["frida", "-U", "TestClassLoader"]
>>> main()
     ____
    / _  |   Frida 16.2.1 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://frida.re/docs/home/
   . . . .
   . . . .   Connected to Android Emulator 5554 (id=emulator-5554)

[Android Emulator 5554::TestClassLoader ]-> Java.myfunc()
TypeError: not a function
    at <eval> (<input>:1)
[Android Emulator 5554::TestClassLoader ]-> Java
{
    "ACC_ABSTRACT": 1024,
    "ACC_BRIDGE": 64,
    "ACC_FINAL": 16,
    "ACC_NATIVE": 256,
    "ACC_PRIVATE": 2,
    "ACC_PROTECTED": 4,
    "ACC_PUBLIC": 1,
    "ACC_STATIC": 8,
    "ACC_STRICT": 2048,
    "ACC_SYNCHRONIZED": 32,
    "ACC_SYNTHETIC": 4096,
    "ACC_VARARGS": 128,
    "_apiError": null,
    "_cachedIsAppProcess": null,
    "_initialized": true,
    "_pendingMainOps": [],
    "_pendingVmOps": [],
    "_pollListener": null,
    "_wakeupHandler": null,
    "api": {
        "$delete": "0x77bb7f859910",
        "$new": "0x77bb7f859840",
        "JNI_GetCreatedJavaVMs": "0x77b8ea71f290",
        "addLocalReference": null,
        "art::ArtMethod::PrettyMethod": "0x77b8ea501c10",
        "art::ClassLinker::VisitClassLoaders": "0x77b8ea528350",
        "art::ClassLinker::VisitClasses": "0x77b8ea5283d0",
        "art::Dbg::SetJdwpAllowed": "0x77b8ea57af80",
        "art::Instrumentation::Deoptimize": "0x77b8ea680f40",
        "art::Instrumentation::DeoptimizeEverything": "0x77b8ea681fb0",
        "art::Instrumentation::EnableDeoptimization": "0x77b8ea681650",
        "art::JavaVMExt::AddGlobalRef": "0x77b8ea719980",
        "art::Monitor::TranslateLocation": "0x77b8ea83ab30",
        "art::ReaderWriterMutex::ExclusiveLock": "0x77b8ea507dd0",
        "art::ReaderWriterMutex::ExclusiveUnlock": "0x77b8ea508100",
        "art::Runtime::DeoptimizeBootImage": "0x77b8ea93a140",
        "art::StackVisitor::DescribeLocation": "0x77b8ea95c310",
        "art::StackVisitor::GetMethod": "0x77b8ea954a40",
        "art::StackVisitor::StackVisitor": "0x77b8ea955a20",
        "art::StackVisitor::WalkStack": "0x77b8ea953860",
        "art::Thread::CurrentFromGdb": "0x77b8ea999700",
        "art::Thread::DecodeJObject": "0x77b8ea992ea0",
        "art::Thread::GetLongJumpContext": "0x77b8ea999ff0",
        "art::ThreadList::ResumeAll": "0x77b8ea9a8b30",
        "art::ThreadList::SuspendAll": "0x77b8ea9a8210",
        "art::interpreter::GetNterpEntryPoint": "0x77b8eaa94ad0",
        "art::jni::JniIdManager::DecodeMethodId": "0x77b8ea723d10",
        "art::mirror::Class::GetDescriptor": "0x77b8ea814820",
        "art::mirror::Class::GetLocation": "0x77b8ea81ca50",
        "artClassLinker": {
            "address": "0x77b9baadb050",
            "quickGenericJniTrampoline": "0x706c5030",
            "quickImtConflictTrampoline": "0x706c5040",
            "quickResolutionTrampoline": "0x706c5050",
            "quickToInterpreterBridgeTrampoline": "0x706c5060"
        },
        "artHeap": "0x77b9faad1360",
        "artInstrumentation": "0x77b9faad1c70",
        "artNterpEntryPoint": "0x77b8ea45db08",
        "artQuickGenericJniTrampoline": "0x77b8ea479ff0",
        "artQuickResolutionTrampoline": "0x77b8ea479e90",
        "artQuickToInterpreterBridge": "0x77b8ea47a1c0",
        "artRuntime": "0x77b9faad19d0",
        "artThreadList": "0x77ba6aae2430",
        "flavor": "art",
        "kAccCompileDontBother": 33554432,
        "module": {
            "base": "0x77b8ea2f6000",
            "name": "libart.so",
            "path": "/apex/com.android.art/lib64/libart.so",
            "size": 8138752
        },
        "vm": "0x77b9baad8650"
    },
    "classFactory": {
        "_classHandles": {
            "capacity": 10,
            "items": {}
        },
        "_classes": {},
        "_loader": null,
        "_patchedMethods": {},
        "_types": [
            {},
            {}
        ],
        "cacheDir": "/data/local/tmp",
        "codeCacheDir": "/data/local/tmp/dalvik-cache",
        "tempFileNaming": {
            "prefix": "frida",
            "suffix": ""
        }
    },
    "vm": {
        "handle": "0x77b9baad8650"
    }
}
[Android Emulator 5554::TestClassLoader ]->
oleavr commented 2 months ago

Whoa, nice! 💥 Thanks for doing this, and apologies for the delay -- just finished a painful restructuring of the build system and reviving CI across the Frida project's main repos.

I've pushed some style adjustments and minor simplifications, but haven't gotten a chance to test them yet. Today is a bank holiday here in Norway so I might not get around to it until tomorrow. But if any of you are able to take it for a spin in the meantime, please do let me know. (I'll try to take a stab at reviving the frida-java-bridge CI soon.)