android jni签名验证(一)

时间:2022-10-13 23:43:03

jni获取签名一般要传入一个context到jni中,然后通过jni进行签名的相关操作,这种方法有一个缺点,通过重写

PackageManager类 进行签名重写,欺骗从而破解签名的目的

下面给出cpp文件,不传入context获取签名的一种方式:代码中有详细注释

#include <jni.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
/*
author:xiaobaiyey
date:2015年11月7日15:24:02
email:xiaobaiyey@outlook.com
*/
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "xiaobai", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "xiaobai", __VA_ARGS__))

void verifySign(JNIEnv *env, jobject obj);
jstring getentyString();
//jstring转char*
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode =env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID( clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)env->CallObjectMethod( jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements( barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
jobject getApplication(JNIEnv *env) {
jclass localClass = env->FindClass("android/app/ActivityThread");
if (localClass!=NULL)
{
LOGI("class have find");
jmethodID getapplication = env->GetStaticMethodID(localClass, "currentApplication", "()Landroid/app/Application;");
if (getapplication!=NULL)
{
jobject application = env->CallStaticObjectMethod(localClass, getapplication);
return application;
}
return NULL;
}
return NULL;
}
//注册native方法
static JNINativeMethod gMethods[] = {
{ "verifySign", "()V", (void *)verifySign },//对应java中的public native void verifySign();
{ "getentyString", "(I)Ljava/lang/String;", (jstring *)getentyString },

};
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods,
int numMethods) {
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
//注册类
static int registerNatives(JNIEnv *env) {
const char *kClassName = "com/xiaobai/xposedtool/MainActivity";//指定要注册的类 即nativie方法所在的类
return registerNativeMethods(env,kClassName,gMethods,sizeof(gMethods) / sizeof(gMethods[0]));

}
void verifySign(JNIEnv *env, jobject obj) {
jobject context= getApplication(env);
jclass activity = env->GetObjectClass(context);
// 得到 getPackageManager 方法的 ID
jmethodID methodID_func = env->GetMethodID(activity, "getPackageManager", "()Landroid/content/pm/PackageManager;");
// 获得PackageManager对象
jobject packageManager = env->CallObjectMethod(context,methodID_func);
jclass packageManagerclass = env->GetObjectClass(packageManager);
//得到 getPackageName 方法的 ID
jmethodID methodID_pack = env->GetMethodID(activity,"getPackageName", "()Ljava/lang/String;");
//获取包名
jstring name_str = static_cast<jstring>(env->CallObjectMethod(context, methodID_pack));
// 得到 getPackageInfo 方法的 ID
jmethodID methodID_pm = env->GetMethodID(packageManagerclass,"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
// 获得应用包的信息
jobject package_info = env->CallObjectMethod(packageManager, methodID_pm, name_str, 64);
// 获得 PackageInfo 类
jclass package_infoclass = env->GetObjectClass(package_info);
// 获得签名数组属性的 ID
jfieldID fieldID_signatures = env->GetFieldID(package_infoclass,"signatures", "[Landroid/content/pm/Signature;");
// 得到签名数组,待修改
jobject signatur = env->GetObjectField(package_info, fieldID_signatures);
jobjectArray signatures = reinterpret_cast<jobjectArray>(signatur);
// 得到签名
jobject signature = env->GetObjectArrayElement(signatures, 0);
// 获得 Signature 类,待修改
jclass signature_clazz = env->GetObjectClass(signature);
//获取sign
jmethodID toCharString = env->GetMethodID(signature_clazz, "toCharsString", "()Ljava/lang/String;");
//获取签名字符;或者其他进行验证操作
jstring signstr = static_cast<jstring>(env->CallObjectMethod(signature, toCharString));
char* ch = jstringTostring(env, signstr);
//输入签名字符串,这里可以进行相关验证
LOGI("the signtures is :%s", ch);
}
//返回字符
jstring getentyString() {


return NULL;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
jint result = -1;

LOGI("in jni onload");
if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
LOGI("register natives");
if (!registerNatives(env)) {//注册
LOGI("register failed");
return -1;
}
//成功
result = JNI_VERSION_1_4;
LOGI("register success");
return result;
}
  1. 通过动态注册类和native方法。此方法可以一定程度上增加逆向难度。

  2. 通过ActivityThread中currentApplication方法动态获取Application对象,在通过此对象获取签名相关信息。可以防止重写PackageManager对签名的伪造。