I read that JNI functions (the native C part) is very complex and must contain the java package name.
However, when reading Android webkit source. For example the nativeMoveGeneration functions in WebView.java
private native int nativeMoveGeneration();
It calls the JNI functions in WebView.cpp
static int nativeMoveGeneration(JNIEnv *env, jobject obj)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
if (!view)
return 0;
return view->moveGeneration();
}
Ihis JNI function does not follow naming rule. Why is it?
P/S: The function above is just for demonstration. I'm reading Android 4.0.3 source, so it may be different from the github source above
UPDATE
Thanks to #Alex Cohn and this JNI Tips, I know that we can use JNI_Onload or use complex name. But where should we put JNI_Onload ?
JNI defines special function, JNI_OnLoad. It is called before any JNI method is called, and it can populate the table of native methods using pointers to any C functions. See the official document
Related
We can write methods to get the key as below both Method 1 and Method 2 for the Android app
Are both Methods have the same security strength? or is there any security weakness in one of the below Methods while decompile/reverse engineering or other app cracking procedures?
Method 1
declare/assign key inside the method in the lib.cpp file
lib.cpp file
extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
std::string API_KEY = "YOUR_API_KEY";
return env->NewStringUTF(API_KEY.c_str());
}
Method 2
declare/assign keys in separate keys.h file in the same directory with lib.cpp and import to lib.cpp file
keys.h file
std::string API_KEY = "YOUR_API_KEY";
lib.cpp file
#include "keys.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
return env->NewStringUTF(API_KEY.c_str());
}
Your two snippets compile to nearly the exact same code. In both cases the API key is present in plain text in the compiled library. Even if you took pains to obfuscate the native code, an attacker can just attach a debugger and catch the return value of getKey.
You need to rethink your approach and decide if it is actually worth the effort on your part.
You can achieve a good result in another way:
you have to obfuscate JNI function name because "getKey()" is too much self-explained and easy to understand during reverse engineering
add unused parameters to "getKey()" to make it more complex when scrolling while viewing reversed code
getKey() haven't to return the Key but have to call a Java method or set a specific Java variable
About #3: I'm using a dedicated Thread on JNI to receive a "command" and a "callback" for its results:
Java calls JNI's "getKey(fakeArg1, fakeArg2, fn_callback, fakeArg3)"
getKey() sends a request to JNI dedicated Thread and pass even "fn_callback" as part of that request
the dedicated Thread process the request and then call Java Callback
In this way event during normal debugging it's very difficult to follow the Flow because debugging won't go inside dedicated Thread automatically using StepInto/Over key/button.
Update: callback is the first approach but create a link between caller and the result. To avoid this you could call a completly separated Java method from JNI to pass the variable to.
it's known that jni function usually named as follows (from Oracle docs):
Dynamic linkers resolve entries based on their names. A native method name is concatenated from the following components:
the prefix Java_
a mangled fully-qualified class name
an underscore (“_”) separator
a mangled method name
So method's name always should contain corresponding Java class name and cannot be called from outside of this class. In case u're call this method from other class Android studio inspector gives the warning like this:
Reports native method declarations in Java where no corresponding JNI function is found in the project.
And if u run that u will receive java.lang.UnsatisfiedLinkError: Native method not found exception.
And thus my question is: how to create shared library with native functions, which could be called from any Java class?
To be more concrete. I have Java class MyActivity. And i need to call some jni function from this class. As i understand according Oracle doc that function should be named smth like Java_xxx_yyy_zz_MyActivity_func1. Then imagine, that i also want to call this function from another android app. I copy my lib*.so to libs folder but i will not be able to call my func1, coz native function will not be found. For possibility of using that function in new app i need to create the same folders hierarchy that is xxx/yyy/zzz and class MyActivity there and after that i will be able to call func1 but only from that MyActivity class. But what should i do if i want to call that fron another class?
-- new answer, given question edits --
Thanks for the clarification. AFAIK, there is no automatic way to associate the same native method with multiple Java methods. However, there are a couple workarounds that you might find useful:
(1) Call a shared facade. Assuming you don't need to pass the Java instance object to the method, first declare a facade class as in my original answer, and implement it in C:
public class JniStuff {
public static native void method1(String s, int i);
}
JNIEXPORT void JNICALL Java_net_redpoint_scratch_JniStuff_method1
(JNIEnv *, jclass, jstring, jint);
then call it from any other class you want:
public class MyClass {
public static void method1(String s, int i) {
JniStuff.method1(s, i);
}
}
(2) Use the RegisterNatives call to associate the one C method with multiple java methods, as explained here. However, I doubt that you will find this to be convenient as the registration must be done from "C", so you would also need some startup method that is called first to do that.
--- old answer --
I'm not sure what you are after, exactly. If your problem is that you don't want to create an object containing the methods, just declare them static:
package net.redpoint.scratch;
public class JniStuff {
public static native void method1(String s, int i);
}
javah then generates this native method signature:
JNIEXPORT void JNICALL Java_net_redpoint_scratch_JniStuff_method1
(JNIEnv *, jclass, jstring, jint);
Your other Java code is free to call:
JniStuff.method1("something", 123);
without instantiating an object of type JniStuff
I'm trying to modify chromium on android for research purposes.
Chromium comes with a ContentViewCore.java class. This class calls a native function:
nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
This method is defined in the same class as follows:
private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
String script, JavaScriptCallback callback, boolean startRenderer);
The class has the following annotation:
#JNINamespace("content")
As I understand it, the JNI Generator links these methods to the correct native (c++) methods of the correct class.
My question: To which class is ContentViewCore.java linked? Where can I find the implementation of nativeEvaluateJavaScript? Where is it defined that a specific java class is linked to a specific c++ class?
The only thing I can find is content_view_core.h (src/content/public/browser/android), but that file doesn't get me any further. Googeling for 'nativeEvaluateJavaScript' revealed nothing. I've been searching for about 10 hours now and I'm not getting any closer.
The JNI generator will generate JNI binding file under "(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni/" during the build time.
For example, the corresponding JNI binding file for ContentViewCore.java is "out/Debug/gen/content/jni/ContentViewCore_jni.h". And you can see the native method of 'nativeEvaluateJavaScript':
static void EvaluateJavaScript(JNIEnv* env, jobject jcaller,...
I asked this question the other day, but wasn't too specific, so I want to re-clarify.
I am creating an Android Application which uses an existing library in C using the NDK. The problem I have run into is that the C code uses a lot of things java doesn't ( function pointers as parameters is the big problem ).
Anyway, I was wondering if I could write functions in my Java code that the C code calls. Now from what I can tell, you can do it, so I would appreciate it if no one just answered 'Yes you can, LINK." I have been looking into it but its very over my head as to what actually needs to be done.
Can anyone try to explain the process? I know it involves creating a JVM in the C code; any information that will help a newbie get on his feet will be greatly appreciated.
Thanks
EDIT :
So, I don't know what to do for these three steps.
To call a specific Java function from C, you need to do the following:
Obtain the class reference using the FindClass(,,) method.
Obtain the method IDs of the functions of the class that you want to call using the
GetStaticMethodID and GetMethodID function calls.
Call the functions using CallStaticVoidMethod, CallStaticIntMethod, and CallStaticObjectMethod.
This isn't explained too much and I have literally no experience in C. Is FindClass a C method?
Every C function that is callable from Java via JNI has a first parameter of type JNIEnv*. On the C end, this is a pointer to a pointer to a structure with a bunch of pointers to functions. Those functions are your interface to the Java world. FindClass, GetMethodID and the rest are among them.
So when you want to call FindClass from the C side, here's how you do it:
void Java_com_mypackage_MyClass_MyMethod(JNIEnv *jniEnv, jobject thiz)
{
jclass *clazz = (*(*jniEnv)->FindClass)(jniEnv, "com/mypackage/SomeClass");
jmethodID MethodID = (*(*jniEnv)->GetStaticMethodID)(jniEnv, clazz, "SomeMethod", "(I)I");
int result = (*(*jniEnv)->CallStaticIntMethod)(jniEnv, clazz, MethodID, 18);
And so forth. The line dereferences the jniEnv parameter, gets a function pointer and calls the function through it. Class and method names are completely bogus, naturally. How would I know yours.
Note: I'm talking of function pointers here, but not in the same sense as you do; those are function pointers to functions that JNI provides, not to your functions.
The verbosity of call syntax has to do with the limitations of C; in C++, you can write instead
jclass *cl = jniEnv->FindClass("com/mypackage/SomeClass");
as C++ supports function table pointers of this sort natively via virtual functions.
You can probably take some shortcuts along the way. If you're calling methods in the same class as your C point of entry, and it happens to be static, your second parameter already is a class object pointer. If you have a this pointer to the object you want to invoke a method on, you can use GetObjectClass.
This question has been asked and answered in many posts like this!
But how can I call from c++ directly ? For this how can I get JNIEnv* and jobject ?
Is this possible ?
To get JNIEnv you can write global JNI_OnLoad function that will get called during loading of shared library. This function will get JavaVM pointer as argument. Using it you can get JNIEnv for current thread (or create new one if there was no JNIEnv previously).
As to where get jobject - if that is new object you are instantiating, then you use JNIEnv::NewObject method. Otherwise you need to pass object on which you want to call method from java side to C/C++.
You need to read the Invocation section of the JNI Specification.