JNI C call Java function - android

I've been turning in circle for hours on this one... Im porting an old android app to 11 and try to open a URL from C. Previously I was opening URL using:
if( fork() == 0 )
{ execvp( "/system/bin/am", cmd ); }
But now it seems we cannot run commands using execvp directly anymore, so the idea is to call from C a Java function to open a browser and launch the URL. So now I got the following:
[Utils.java]
package com.android.MyApp;
public class Utils {
public static void open_url(String url) {
// Test it out...
System.out.println(url);
}
}
[main.c]
void test( void ) {
jclass cls = (*g_env)->FindClass( g_env, "com/android/MyApp/Utils" );
jmethodID open_url = (*g_env)->GetStaticMethodID( g_env, cls, "open_url", "(Ljava/lang/String;)V");
(*g_env)->CallStaticVoidMethod( g_env, cls, open_url, (jstring)"https://stackoverflow.com/" );
}
Everything compile but Android Studio report on the CallStaticVoidMethod line: JVM object referenced by 'cls' is of type 'Class<MyApp.Utils>' and it does not have access to static method 'open_url(String)' declared in class 'Utils'.
And of course calling CallStaticVoidMethod even if g_env and cls got an address crash... How can I fix this problem?

Related

Using frida and java script to hook protected APK encountered attach( ) error

I used the following java script to learn hooking in frida (windows 7).
Java.perform(function () {
console.log("prepare hook...");
var application = Java.use("android.app.Application");
console.log("get application...");
application.attach.overload("android.app.Context").implementation = function(Context){
console.log("get context...");
var classloader = Context.getClassLoader();
Java.classFactory.loader = classloader;
console.log("get classloader");
}
});
What I wanted to do in this exercise is to get the class loader of a protected APK. In frida -R -f com.xxxx.xxx -l myjs1.js, attach( ) argument type error popped up:
What's wrong with my javascript and how to fix it? Thank you very much.
You are trying to hook a non-existing method.
What you try to hook:
android.app.Application.attach(android.app.Context)
The only attach method in this class has the signature
android.app.Application.attach(android.content.Context)
See source code: https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/app/Application.java#L350
If you are trying to get access with Context, here is alternative on make it works
Java.perform(function () {
var context = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
console.log("get context...");
var classloader = context.getClassLoader();
Java.classFactory.loader = classloader;
console.log("get classloader");
});
Just remove the application implementation.

Calling simple java static method via JNI does not work, though c++ compiles and run it

Considering this Java class with the static method:
public class TestClass{
public string str;
public TestClass() {
str = "Test From Java";
}
public static String staticMethod() {
return "Test From Java";
}
}
I have written these lines of code in c++ file:
QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod(
"org/.../TestClass"
,"staticMethod"
,"(V)Ljava/lang/String;");
It seems everything is working but I don't know how can I use the str Object. I tried to convert it to a QString object using str.tostring() method but it always returns an empty string.
Why it does not work as expected? I've also tested ()Ljava/lang/String; for method signature but no success!
Thanks in advance.
You should specify the returned JNI type in <...> when calling the method :
QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod<jstring>(
"org/.../TestClass"
,"staticMethod");
QString string = str.toString();
Here there is no need to define the signature since your function has no argument.

Qt Android Extras Call Class

Say I have a Java class,
public static String helloWorld() {
return "hello world!";
}
How, in Qt, do I get what this function returned? The example for notifications has the following:
QAndroidJniObject javaNotification = QAndroidJniObject::fromString(m_notification);
QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
"notify",
"(Ljava/lang/String;)V",
javaNotification.object<jstring>());
Should by method descriptor be ()Ljava/lang/String;? What should be in the chevrons after callStaticMethod?
Edit. Fixed and I don't know how. I didn't have the chevrons, and the descriptor was correct.
QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod<jstring>("com/your/project/YourClass", "helloWorld");
Is equivalent to:
QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod("com/your/project/YourClass", "helloWorld", "()Ljava/lang/String;");
For trivial signatures, that is, signatures that takes no arguments and returns one of the know jni types, you can write the short version by supplying the template type.

Calling static jar function from Unity3D

I made and compiled a Android Library, containing a simple class and a simple static function:
package moo;
public class MyTestClass {
public static String Foo(){
return "Foo from Moo";
}
}
I placed the .jar in my Assets/Plugins/Android Folder. Then In Unity:
void OnGUI () {
string somestring = "foooooooooooOOooo";
AndroidJavaClass testClass = new AndroidJavaClass("moo.MyTestClass");
somestring = testClass.CallStatic<string>("Foo");
GUI.Label (new Rect (20, 20, 100, 20), somestring);
}
And I get an error:
JNI: Unable to find method id for 'Foo' (static)
UnityEngine.AndroidJavaObject:CallStatic(String, Object[])
Am I missing something to call my static method?
Thanks!
there are 2 problem as far as I can see:
you have to put your jar package to Assets/Plugins/Android/bin;
you will always get this error on your windows/mac editor, you have to run this on your android device;

How does dalvik findlibrary?

first, in System.java, it calls Runtime to loadLibrary.
public static void loadLibrary(String libName) {
SecurityManager smngr = System.getSecurityManager();
if (smngr != null) {
smngr.checkLink(libName);
}
Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
}
second, it calles VMStack.getCallingClassLoader() to findLibrary.
void loadLibrary(String libraryName, ClassLoader loader) {
if (loader != null) {
String filename = loader.findLibrary(libraryName);
if (filename == null) {
throw new UnsatisfiedLinkError("Couldn't load " + libraryName + ": " +
"findLibrary returned null");
}
//....
}
}
So, i think VMStack.getCallingClassLoader() is the most meaningful.
But in its jni file dalvik_system_VMStack.cpp, the Dalvik_dalvik_system_VMStack_getCallingClassLoader function is hard to learn. And at last, how dalvik findLibrary?
static void Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4* args,
JValue* pResult){
ClassObject* clazz =
dvmGetCaller2Class(dvmThreadSelf()->interpSave.curFrame);
UNUSED_PARAMETER(args);
if (clazz == NULL)
RETURN_PTR(NULL);
RETURN_PTR(clazz->classLoader);
}
VMStack.getCallingClassLoader() returns the class loader of the class that declared the method that called the current method. In other words, if my function foo() called Runtime.loadLibrary(), it would return foo's class loader.
The point of all that is to make sure the library is loaded in the context of whoever called findLibrary, rather than in the context of java.lang.Runtime.
There's a good chance findLibrary() is implemented by BaseDexClassLoader, which calls into DexPathList.findLibrary(), which does the actual work. The interesting bit there is the walk through nativeLibraryDirectories, which is initialized from the libraryPath argument to the BaseDexClassLoader constructor (which gets it from PathClassLoader or DexClassLoader).
For Android apps, take a look at android.app.ApplicationLoaders, which uses a PathClassLoader. If you trace that back far enough you'll see the directory being retrieved from ApplicationInfo.nativeLibraryDir.
EDIT: going deeper to address comment...
/system/lib comes from the java.library.path property, which the core libraries extract from the LD_LIBRARY_PATH environment variable. The app-specific library dir is configured by the framework.
The PackageManagerService constructor sets the lib path in mAppLibInstallDir, and setInternalAppNativeLibraryPath() configures nativeLibraryDir.
DexPathList.splitLibraryPath() combines the java.library.path path with the APK-specific path. See the comments there for notes on ordering.

Categories

Resources