Get app signature hash code in jni - android

i want to get app signature in native with these code: (source)
// For class Context
jclass native_clazz = (*env)->GetObjectClass(env, context);
// Get the getPackageManager method ID
jmethodID methodID_func = (*env)->GetMethodID(env, native_clazz,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
// Access manager application package
jobject package_manager = (*env)->CallObjectMethod(env, thiz, methodID_func);
// For class PackageManager
jclass pm_clazz = (*env)->GetObjectClass(env, package_manager);
// Get the getPackageInfo method ID
jmethodID methodID_pm = (*env)->GetMethodID(env, pm_clazz,
"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
// To obtain the application package information
jobject package_info = (*env)->CallObjectMethod(env, package_manager,
methodID_pm, (*env)->NewStringUTF(env, "com.example.hellojni"), 64);
but i got this:
error: 'context' undeclared (first use in this function)
how do i get context in native?
how do i return signature hashcode as string?

You can send the context to JNI in a parameter for example
jstring Java_packagename_stringFromJNI( JNIEnv* env, jobject thiz , jobject context)
And when you call the method in your activity:
public native String stringFromJNI(Context context);
...
Log.d(TAG, "Receive: " + stringFromJNI(this));

Related

Error when trying to access nativeLibraryDir

i'm trying to access getPackageManager.getApplicationInfo in jni.
const char* getNativeLibPath(JNIEnv* env, jobject thiz, const char* libraryName, const char* packageName) {
jclass contextClass = env->GetObjectClass(thiz);
jmethodID getPackageManager = env->GetMethodID(contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject instantiatePackageManager = env->CallObjectMethod(thiz, getPackageManager);
jclass packageManagerClass = env->GetObjectClass(instantiatePackageManager);
jmethodID getApplicationInfo = env->GetMethodID(packageManagerClass, "getApplicationInfo", "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;");
jobject instantiateApplicationInfo = env->CallObjectMethod(thiz, getApplicationInfo, packageName, 0);
jclass applicationInfoClass = env->GetObjectClass(instantiateApplicationInfo);
jfieldID nativeLibraryDir = env->GetFieldID(applicationInfoClass, "nativeLibraryDir", "Ljava/lang/String;");
auto string = (jstring) env->GetObjectField(instantiateApplicationInfo, nativeLibraryDir);
const char* returnValue = env->GetStringUTFChars(string, nullptr);
std::string appendedResult = std::string(returnValue) + std::string("/") + std::string(libraryName);
return appendedResult.c_str();
}
This is my code for it. However for some reason i'm getting this error: JNI ERROR (app bug): accessed stale WeakGlobal 0x74eecd21ff (index 1324143135 in a table of size 38) JNI DETECTED ERROR IN APPLICATION: use of deleted weak global reference 0x74eecd21ff
Any help is appreciated!
Your code has at least three problems:
You call getApplicationInfo with a const char * which expects a Java string:
jobject instantiateApplicationInfo = env->CallObjectMethod(instantiatePackageManager, getApplicationInfo, env->NewStringUTF(packageName), 0);
You need to call env->ReleaseStringUTF(returnValue) to release the string on the Java side
You cannot return a const char * like that. Either return the std::string directly, or allocate memory with new char[] and let the caller free it.

java lang class exception -Unable to cast the java vector<user defined java class> return from c++ jni object callback

I am not able to cast back the user self defined class return from C++ jni callback
code snippet as follow:
//Kotlin class
data class class_record(var id:String?,var class_name:String?,var class_type)
// com.example.MainActivity
public native Object Cls(String id);
Vector vec_ classrecord=new Vector();
vec_classrecord=(Vector)Cls("1234");
// c++ jni code
extern "C"
JNIEXPORT jobject JNICALL
Java_com_example_MainActivity_Cls(JNIEnv *env, jobject instance, jstring id,
) {
jclass java_vector_class;
jmethodID java_vector_method;
jobject java_vector_object ;
auto vec_record=// call c++ method that return vector for class record pointer
jstring jni_str;
jclass javaClassRef;
// jni for java.util.Vector
java_vector_class = env->FindClass("java/util/Vector");
java_vector_method_constructor = env->GetMethodID(java_vector_class, "<init>", "()V");
java_vector_object = env->NewObject(java_vector_class, java_vector_method_constructor, "");
for (auto record_it = vec_record.begin(); record_it < vec_record.end(); ++record_it) {
// jni for class_record
jclass java_class = env->FindClass("com/example/class_record");
javaClassRef = (jclass) env->NewGlobalRef(java_class);
jmethodID cls_constructor = env->GetMethodID(javaClassRef, "<init>", "()V");
jobject cls_object = env->NewObject(javaClassRef, cls_constructor, "");
// set id
javaMethodRef = env->GetMethodID(javaClassRef, "setId", "(Ljava/lang/String;)V");
std::string strval = record_it.id;
jni_str = env->NewStringUTF(strval.c_str());
env->CallVoidMethod(cls_object, javaMethodRef, jni_str);
// set class_name
javaMethodRef = env->GetMethodID(javaClassRef, "setClass_name","(Ljava/lang/String;)V");
std::string strval = record_it.class_name;
jni_str = env->NewStringUTF(strval.c_str());
env->CallVoidMethod(cls_object, javaMethodRef, jni_str);
//set class_type
javaMethodRef = env->GetMethodID(javaClassRef, "setClass_type","(Ljava/lang/String;)V");
std::string strval = record_it.class_type;
jni_str = env->NewStringUTF(strval.c_str());
env->CallVoidMethod(cls_object, javaMethodRef, jni_str);
jmethodID java_vector_add = env->GetMethodID(java_vector_class, "addElement","(Ljava/lang/Object;)V");
**env->CallVoidMethod(java_vector_object, java_vector_add, javaClassRef);**
}
return java_vector_object;
}
env->CallVoidMethod(java_vector_object, java_vector_add, cls_object);
Under Kotlin environment , it it much better to express jni c++ callback in ArrayList instead of vector which grow almost double the size with snippet as follow in situation where the returned arraylist is fixed size immuatable.
java_util_class = env->FindClass("java/util/ArrayList");
jmethodID java_add= env->GetMethodID(java_util_class, "add","(Ljava/lang/Object;)Z");
env->CallBooleanMethod(java_object, java_add, cls_object);
sample tutorial

PackageManager$NameNotFoundException fo JNI project

Getting PackageManager$NameNotFoundException for the signature capturing code in android studio
package com.example.u29692.helloandroidjni;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView) findViewById(R.id.jni_msgView)).setText(stringFromJNI(this));
}
// new code
static {
System.loadLibrary("hello-android-jni");
}
// public native String getMsgFromJni();
public native String stringFromJNI(Context context);
jni.c
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_u29692_helloandroidjni_MainActivity_stringFromJNI(JNIEnv *env, jobject instance,
jobject context) {
// TODO
// For class Context
jclass native_clazz = (*env)->GetObjectClass(env, context);
// Get the getPackageManager method ID
jmethodID methodID_func = (*env)->GetMethodID(env, native_clazz,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
// Access manager application package
jobject package_manager = (*env)->CallObjectMethod(env, context, methodID_func);
// For class PackageManager
jclass pm_clazz = (*env)->GetObjectClass(env, package_manager);
// Get the getPackageInfo method ID
jmethodID methodID_pm = (*env)->GetMethodID(env, pm_clazz,
"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
// To obtain the application package information
jobject package_info = (*env)->CallObjectMethod(env, package_manager,
methodID_pm, (*env)->NewStringUTF(env, "com.example.u29692.helloandroidjni"), 64);
return (*env)->NewStringUTF(env, package_info);
}
Application is crashing with the logs:
10-14 12:12:55.038: A/art(17135): sart/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI NewStringUTF called with pending exception 'android.content.pm.PackageManager$NameNotFoundException' thrown in unknown throw location
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
10-14 12:12:55.198: A/art(17135): sart/runtime/runtime.cc:292] Pending exception android.content.pm.PackageManager$NameNotFoundException thrown by 'unknown throw location'
0-14 12:12:55.198: A/art(17135): sart/runtime/runtime.cc:292] android.content.pm.PackageManager$NameNotFoundException: com.example.u29692.helloandroidjni
10-14 12:12:55.198: A/art(17135): sart/runtime/runtime.cc:292] at android.content.pm.PackageInfo android.app.ApplicationPackageManager.getPackageInfo(java.lang.String, int) (ApplicationPackageManager.java:167)
10-14 12:12:55.198: A/art(17135): sart/runtime/runtime.cc:292] at java.lang.String

How to make native library which returns sha1 app key

I need library in native which calculates sha1 key and return it to application.
I also try: Protection Android of applications against breaking
But I can't compile to *so.
Maybe somebody have experience with native and will help me.
jstring find(JNIEnv *env, jobject thiz, jobject contexObject)
{
jclass contextTemp = env->FindClass("android/content/Context");
jclass contextClass = (jclass)env->NewGlobalRef(contextTemp);
jmethodID getPackageManager = env->GetMethodID(contextClass,
"getPackageManager",
"()Landroid/content/pm/PackageManager;");
jobject share = (jobject)env->CallObjectMethod(contexObject, getPackageManager);
jmethodID getPackageName = env->GetMethodID(contextClass, "getPackageName",
"()Ljava/lang/String;");
jstring packageName = (jstring)env->CallObjectMethod(contexObject, getPackageName);
jclass clazz = env->FindClass("android/content/pm/PackageManager");
jfieldID GET_SIGNATURESfid = env->GetStaticFieldID( clazz, "GET_SIGNATURES", "I");
jint GET_SIGNATURES = env->GetStaticIntField(clazz,GET_SIGNATURESfid);
//jclass temp = env->FindClass("android/content/pm/PackageManager");
jclass PackageManagerObj = (jclass)env->NewGlobalRef(clazz);
jmethodID getPackageInfoId = env->GetMethodID(PackageManagerObj, "getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jobject getPackageInfoObject = (jobject)env->CallObjectMethod(share, getPackageInfoId,
packageName,GET_SIGNATURES);
jclass packageInfoClass = env->FindClass("android/content/pm/PackageInfo");
jfieldID signatures = env->GetFieldID(packageInfoClass,"signatures","[Landroid/content/pm/Signature;");
jobjectArray rows = reinterpret_cast<jobjectArray>(
env->GetObjectField(getPackageInfoObject,signatures));
int size = env->GetArrayLength(rows);
jclass signaturesClass = env->FindClass("android/content/pm/Signature");
jclass mEssage = env->FindClass("java/security/MessageDigest");
jclass MessageDigestClass = (jclass)env->NewGlobalRef(mEssage);
jmethodID mGetInstance = env->GetStaticMethodID(MessageDigestClass,"getInstance","(Ljava/lang/String;)Ljava/security/MessageDigest;");
jmethodID updateMethod = env->GetMethodID(MessageDigestClass,"update","([B)V");
jmethodID toByteArrayMethod = env->GetMethodID(signaturesClass,"toByteArray","()[B");
jclass tempBase64 = env->FindClass("android/util/Base64");
jclass Base64Class = (jclass)env->NewGlobalRef(tempBase64);
jmethodID encodeToStringID = env->GetStaticMethodID(Base64Class,"encodeToString","([BI)Ljava/lang/String;");
jmethodID digest = env->GetMethodID(MessageDigestClass,"digest","()[B");
for(int i = 0 ;i<size;i++){
jobject messageDigest = env->CallStaticObjectMethod(MessageDigestClass,mGetInstance,env->NewStringUTF("SHA"));
jobject signature = env->GetObjectArrayElement(rows,i);
env->CallVoidMethod(messageDigest,updateMethod,(jbyteArray)env->CallObjectMethod(signature,toByteArrayMethod));
return (jstring)env->CallStaticObjectMethod(Base64Class,encodeToStringID,env->CallObjectMethod(messageDigest,digest),(jint)0);
}
return env->NewStringUTF("");
Very Crazy if you like ...
This NDK function reads the SHA signature of the signing certificate and converts it into a base64 string.

Sending an Intent from C++ via JNI

I am trying to make an explicit intent call (intent to a specific pkg and class) from C++ via JNI. Everything is fine until the last line where I am actually trying to send the intent:
env->CallVoidMethod(obj, startActivity, intentObject);
I dont get an android error, it is just a full dump/stack trace...which does not give me any helpful info.
Here is the C++ code making the call to start an intent:
JNIEXPORT void JNICALL Java_com_testpkg_test(JNIEnv *java_env, jobject obj) {
jvm->AttachCurrentThread(&java_env, 0);
jclass activityClass = java_env->GetObjectClass(obj);
jmethodID appGetContextId = java_env->GetMethodID(activityClass, "getApplicationContext", "()Landroid/content/Context;");
jobject appContext = java_env->CallObjectMethod(obj, appGetContextId);
//Get an instance of Intent
jclass intentClass = java_env->FindClass("android/content/Intent");
jmethodID newIntent = java_env->GetMethodID(intentClass, "<init>", "()V");
jobject intentObject = java_env->NewObject(intentClass, newIntent);
java_env->CallVoidMethod(intentObject, newIntent);
//Get an instance of the ComponentName class
jclass componentClass = java_env->FindClass("android/content/ComponentName");
jmethodID componentMID = java_env->GetMethodID(componentClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
jstring pkgName =java_env->NewStringUTF("com.testpkg");
jstring clsName =java_env->NewStringUTF("com.testpkg.test");
jobject componentObj = java_env->NewObject(componentClass, componentMID, pkgName, clsName);
java_env->CallVoidMethod(componentObj, componentMID, pkgName, clsName);
//Calling intent.setComponentName passing in pkg+class name
jmethodID setComponentName = java_env->GetMethodID(intentClass, "setComponent","(Landroid/content/ComponentName;)Landroid/content/Intent;");
java_env->CallObjectMethod(intentObject, setComponentName, componentObj);
//Call getapplicationcontext().startActivity(intent)
jmethodID startActivity = java_env->GetMethodID(activityClass, "startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod(obj, startActivity, intentObject);
}
The comments I posted still apply, but here's a problem- don't call java_env->CallVoidMethod(intentObject, newIntent). The NewObject call does it for you. You do this twice, its likely to be screwing up Java's memory management.

Categories

Resources