using jlongArray in JNI with Android NDK - android

I have those two pieces of code, the first is:
JNIEXPORT jlongArray* JNICALL Java_com_home_overlay_activity_MainActivity_ProcessPointer(JNIEnv* env, jobject) {
jlongArray blobs_arr;
return &blobs_arr;
}
and the second is:
JNIEXPORT jlongArray JNICALL Java_com_home_overlay_activity_MainActivity_Process(JNIEnv* env, jobject) {
jlongArray blobs_arr;
return blobs_arr;
}
all I want is to return long array to the java code.
The first runs okay while the second not, is there any issue here with returning a long array this way ??

There are no pointers in Java, so I think that if the first snippet of code actually works, it will not produce what you want at all. It probably returns the memory address of the C jlongArray.
As for the second piece of code, I can't see any problem with it except that it returns an uninitialized object, maybe NULL, maybe some random memory garbage, which probably causes unexpected behavior on the Java side. Maybe you should try initializing it to NULL in the C part, or try making your code snippet more realistic by actually filing the array so you can test the code behavior in real conditions.

My application was not reading the jni.h but working .. which is weird, after I set the NDKROOT variable it all worked correctly

Related

Use NDK/JNI to keep secret keys in Android with high security

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.

The proper way to create a global map to hold multiple C++ objects in JNI

I am using TextureView and Vulkan to draw 3D models. I get the surface from the TextureView and pass it to the native side to render.
I need to support multiple TextureView to render different 3D models simultaneously, but I find out that my native .so library is only loaded once per process, suitable for memory saving.
So I think I need a global std::map in jni to hold different c++ objects. Every TextureView has an id and could use its id to find its c++ objects.
I was planning to code like this.
#include <jni.h>
#include <string>
#include <map>
#include <android/native_window_jni.h>
#include <android/asset_manager_jni.h>
std::unique_ptr<std::map<jint, MiuiVkWidgetApp*>> mVkWidgetAppMapUniquePtr;
extern "C" JNIEXPORT jboolean JNICALL
Java_com_miui_vkwidget_MiuiVkTextureView_nativeInitVkWidgetApp(JNIEnv* env, jobject /* this */, jint id) {
...
if (!mVkWidgetAppMapUniquePtr) {
mVkWidgetAppMapUniquePtr.reset(new std::map<jint, MiuiVkWidgetApp*>());
}
...
return true;
}
extern "C" JNIEXPORT void JNICALL
Java_com_miui_vkwidget_MiuiVkTextureView_nativeDestroyVkWidgetApp(JNIEnv* /* env */,
jobject /* this */, jint id) {
mVkWidgetAppMapUniquePtr.reset(nullptr);
...
}
But in https://developer.android.com/training/articles/perf-jni#local-and-global-references "Local and global reference," it says that "The only way to get non-local references is via the functions NewGlobalRef and NewWeakGlobalRef." But NewGlobalRef seems only to support java objects.
I assume how I create the global map may have some potential risks, such as memory leak(I call DestroyVkWidgetApp when TextureView is onDestroy)? I am curious on how to create a proper global map in jni to hold multiple c++ objects? Thanks!
JNI GlobalRefs refers to Java VM objects: those objects will persists in memory until a "destroy" method is called and Java could refers to them (if needed) in that period. Without GlobalRefs that object's memory could be freed early (by JVM GarbageCollector) and Java will FC due to memory issue.
It's seems that your JVM spawns multiple Processes, so if second process is spawn from the first one, yes you could use a "Mapped Memory File" starting from JavaVersion.VERSION_1_4 (JNI part could be copied from here: https://www.codeproject.com/Articles/2460/Using-Memory-Mapped-Files-and-JNI-to-communicate-b even if you don't need the Java one).
If processes are spawned from different Apps, I'm not sure but I think my solution will work.
(A "global map" is GLOBAL inside the same JVM (one Process per JVM), so even if you use a "global map" it will not be "seen" from the second Process but this last one will create its own "global map")

SIGABRT when trying to access array values in JNI

im currently trying to integrate a c library to my android project.
The extern function accepts a Array<Double> for example
val doubleArray= arrayOf(0.0)
MyClass().myFunction(doubleArray)
in the native part of the application, im trying to access it like this:
Java_com_mypackage_MyClass_myFunction(JNIEnv *env, jobject thiz,jdoubleArray myArray) {
jdouble *body_ = (*env)->GetDoubleArrayElements(env, myArray, 0);
}
This is the way, how the documentation tells me to access my array values. But when im doing this, i'm getting a SIGABRT.
What am i missing here? Would appreciate when you can point me the direction :)
An Array<Double> is a java.lang.Double[] in JVM terms, ie an array of objects.
You meant to create a DoubleArray, which is a double[] (the primitive).

Two java objects, same native address?

I have native method like this.
public native int NativeMethod(Object object);
JNIEXPORT jint JNICALL NativeMethod(
JNIEnv *,
jobject,
jobject object) {
printf("%d", (int)object);
}
I call the method two times with different Java objects.
In Java I output their hashCode() and toString() info and they have different values.
But in native C, they have same output value.
It is just observed on Android 5.x devices and working well on devices below 5.0.
Also it works first time(different value in C) and doesn't work after that(some operations, not specific).
Really I don't how to fix it.
Anyone can help? Please.

JNI: How to substring? How to get caller's package name? Call C code from Java on Android

I could call a very simple JNI method below from Java on Android somehow. However I have no idea what should I do next.
JNIEXPORT jstring JNICALL Java_com_test_ndktest_MyActivity_HelloJNI
(JNIEnv *env, jobject obj)
{
(*env)->NewStringUTF(env, "Hello from JNI");
}
What I want to do are two things...
What is compatible Java's substring method.
String str1 = new String("Hello World!");
String new_str1 = str1.substring(2, 5);
System.out.println(new_str1); // llo
I want to have a limitation to call
I may be able to get caller's package name. I want to avoid calling by unexpecting callers.
I am very grateful if you can share any hints or advices.
Thanks
Why don't you do that in Java? As for me the better way is to do this things in java. Sorry if i din't understand something.
As you know you can use C/C++. Did you see this:
Elegant way to copy substring from char* to std::string or http://www.cplusplus.com/reference/string/string/string/?

Categories

Resources