I can succesfully load native library with System.loadLibrary(""), but when I call native method from that library, I receive UnsatisfiedLinkError, no implementation found for that method.
But this code works in another application, somehow in mine not.
Did you change the packageName in the jni method, it should be Java_com_example_yourapp_methodname(JNIEnv * env, jobject thiz) where com_example_yourapp is the reference to your package of the class you call the method.
and after that, did you call ndk-build again?
The method Erik N is suggested fine, but it has some performance impact as the VM need to search a function call with the above signature. Instead you can map the functions with signatures and register them on JNI_OnLoad() function call.
http://docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html#wp5833
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.
Mentioned in the article:
http://androidcookbook.com/Recipe.seam?recipeId=77
Is:
"In the Activity class, outside any methods:
static {
System.loadLibrary("sqrt-demo");
}
// In a method of the Activity class where you need to use it:
double d = SqrtDemo.sqrtC(123456789.0);
"
If a designer wants to place all NDK actions (loading a library,defining a function) outside of the activity, can she/he?
I tried to solve this question by creating a new class and importing it into the activity. I placed the load library in the classes constructor, and I placed the method definition in the other class. The activity appears to load the library but will crash, with the error that It cannot find the function
Edit to add details:
I attempted this again but by placing the loadLibrary function back in the Activity. I get the same crash report:
java.lang.UnsatisfiedLinkError: Native method not found:
It appears I have found the issue, it was an overlook on my part.
You can load the library from the imported class, and you can place the method definition in the the imported class. YOU MUST however modify the function as so:
initial header: JNIEXPORT jobjectArray JNICALL Java_com_stackoverflow_MainAcitivty_helloWorld(){
to JNIEXPORT jobjectArray JNICALL Java_com_stackoverflow_newclass_helloWorld(){
I want to do some initialization job in library. Any clue would be great. thanks.
A constructor of a global/static C++ object might be a good place (but don't forget about extern "C"{} around JNI methods in the .cpp file). The constructor, however, doesn't get a JNIEnv pointer and can't do anything with the Java world.
Alternatively, introduce a static native method in the class that does the loadLibrary() call, and invoke this method right after the loadLibrary() call. This is probably simpler - no need to go C++.
I'm using JNI to get the music library from Android with Qt. I call upon the following Java method (which is already implemented),
public String getArtists(Context context)
...
I need to be able to get the Context of the application in order for it to work.
If it helps, when I was using Java, the following code provided the correct context.
MainActivity.this
Could anybody be of assistance in this problem?
Many thanks!
It will depend where you are making the call. Ideally you will cache the MainActivity pointer in C++.
One way to cache a pointer to use in a later JNI call is to add a native function in java such as native void onCreateNative() to you MainActivity class. In C++ you'll implement the method and cache the "thiz" pointer:
JNIEXPORT void JNICALL com_package_MainActivity_onCreateNative(JNIEnv *env, jobject thiz)
{
gCachedActivity = env->NewGlobalRef(thiz);
}
Now you can use gCachedActivity where you would have used MainActivity.this
env->CallObjectMethod(obj, s_getArtistsGetArtistsMethodID, gCachedActivity);
Of course replacing obj with the object you are calling the method on.
Lastly onCreateNative() should be called in the onCreate() method of MainActivity.
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.