jni验证application

This commit is contained in:
mahongyin
2021-03-25 12:20:44 +08:00
parent ba6eb721e1
commit 0df3d14e28
9 changed files with 131 additions and 42 deletions

View File

@@ -46,8 +46,13 @@ public class APISecurity {
* @param str * @param str
*/ */
public static native String sign(String str); public static native String sign(String str);
public static native String getRelayPackName();
public static native String getRealyAppName();
public static native void verifyApp(Application applicationByReflect); public static native void verifyApp(Application applicationByReflect);
public static native boolean verifyApplication();
public static native boolean init(Context context); public static native boolean init(Context context);
/** /**
@@ -62,7 +67,7 @@ public class APISecurity {
// Log.e("mhyLog", "hash:" + AppSigning.getSignatureHash(context)); // Log.e("mhyLog", "hash:" + AppSigning.getSignatureHash(context));
// Log.e("mhyLog", "sha1:" + getSignSha1(context)); // Log.e("mhyLog", "sha1:" + getSignSha1(context));
//runCommand(); //runCommand();
// Log.e("mhyLog包文件", "签名:"+getApkSignatures(context, context.getPackageName())); // Log.e("mhyLog包文件", "签名:"+getApkSignatures(context, context.getPackageName()));
//Log.e("mhyLog已安装", "签名:"+getInstalledAPKSignature(context, context.getPackageName())); //Log.e("mhyLog已安装", "签名:"+getInstalledAPKSignature(context, context.getPackageName()));
//通过获取其他应用的签名 如果一样那么被hook了 //通过获取其他应用的签名 如果一样那么被hook了
} }
@@ -79,7 +84,7 @@ public class APISecurity {
if (appInfo == null || appInfo.signingInfo == null) if (appInfo == null || appInfo.signingInfo == null)
return ""; return "";
return AppSigning.getSignatureString(appInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1); return AppSigning.getSignatureString(appInfo.signingInfo.getApkContentsSigners(), AppSigning.SHA1);
}else { } else {
PackageInfo appInfo = pm.getPackageInfo(packageName.trim(), PackageManager.GET_SIGNATURES); PackageInfo appInfo = pm.getPackageInfo(packageName.trim(), PackageManager.GET_SIGNATURES);
if (appInfo == null || appInfo.signatures == null) if (appInfo == null || appInfo.signatures == null)
return ""; return "";
@@ -105,19 +110,19 @@ public class APISecurity {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
//TODO 这里获取的signingInfo 为空 猜想是flag不对 但看源码好像 目前只能使【GET_SIGNATURES 对应signatures】 //TODO 这里获取的signingInfo 为空 猜想是flag不对 但看源码好像 目前只能使【GET_SIGNATURES 对应signatures】
PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNING_CERTIFICATES); PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNING_CERTIFICATES);
if (packageInfo != null&&packageInfo.signingInfo!=null) { if (packageInfo != null && packageInfo.signingInfo != null) {
Signature[] signatures = packageInfo.signingInfo.getApkContentsSigners(); Signature[] signatures = packageInfo.signingInfo.getApkContentsSigners();
return AppSigning.getSignatureString(signatures, AppSigning.SHA1); return AppSigning.getSignatureString(signatures, AppSigning.SHA1);
}else { } else {
return AppSigning.getAPKSignatures(path); return AppSigning.getAPKSignatures(path);
} }
//如果获取失败就用下面方法喽 //如果获取失败就用下面方法喽
}else { } else {
PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNATURES); PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_SIGNATURES);
if (packageInfo != null) { if (packageInfo != null) {
Signature[] signatures = packageInfo.signatures; Signature[] signatures = packageInfo.signatures;
return AppSigning.getSignatureString(signatures, AppSigning.SHA1); return AppSigning.getSignatureString(signatures, AppSigning.SHA1);
}else { } else {
return AppSigning.showUninstallAPKSignatures(path); return AppSigning.showUninstallAPKSignatures(path);
} }
} }

View File

@@ -80,7 +80,6 @@ public class AppSigning {
IllegalAccessException, IllegalAccessException,
NoSuchFieldException, NoSuchFieldException,
NullPointerException { NullPointerException {
// 反射获取 ActivityThread 的 currentActivityThread 获取 mainThread // 反射获取 ActivityThread 的 currentActivityThread 获取 mainThread
Class activityThreadClass = Class.forName("android.app.ActivityThread"); Class activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = Method currentActivityThreadMethod =
@@ -115,12 +114,12 @@ public class AppSigning {
/** /**
* 校验 application * 校验 application
*/ */
public static boolean checkApplication(){ public static boolean sameApplication(){
//在这里使用反射 获取比较靠谱 如果 被替换换 就查出来了 //在这里使用反射 获取比较靠谱 如果 被替换换 就查出来了
Application nowApplication = getApplicationByReflect(); Application nowApplication = getApplicationByReflect();
APISecurity.verifyApp(nowApplication); String trueApplicationName = APISecurity.getRealyAppName();
String trueApplicationName = "cn.android.sample.MyApplication";//getSimpleName()自己的Application类名 防止替换 //getSimpleName()自己的Application类名 防止替换
String nowApplicationName = nowApplication.getClass().getName(); String nowApplicationName = nowApplication.getClass().getName();//当前app类全名
Log.e("mhyLogAppName", "反射获取:"+nowApplicationName); Log.e("mhyLogAppName", "反射获取:"+nowApplicationName);
return trueApplicationName.equals(nowApplicationName); return trueApplicationName.equals(nowApplicationName);
} }
@@ -326,7 +325,6 @@ public class AppSigning {
return getSignatureString(info,AppSigning.SHA1); return getSignatureString(info,AppSigning.SHA1);
} }
} else { } else {
pkgParserCt = pkgParserCls.getConstructor(typeArgs); pkgParserCt = pkgParserCls.getConstructor(typeArgs);
pkgParser = pkgParserCt.newInstance(apkPath); pkgParser = pkgParserCt.newInstance(apkPath);

View File

@@ -12,15 +12,12 @@
package cn.android.security; package cn.android.security;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -39,9 +36,9 @@ public class InitProvider extends ContentProvider {
} }
Log.e("mhyLog", "initContentProvider:"); Log.e("mhyLog", "initContentProvider:");
chekSignature(application); chekSignature(application);
Log.e("mhyLog验证APP", String.valueOf(AppSigning.sameApplication())+";apkmd5="+ AppSigning.apkMD5(application));
Log.e("mhyLog检测Provider_APP", String.valueOf(AppSigning.checkApplication())); APISecurity.verifyApp(AppSigning.getApplicationByReflect());
APISecurity.verifyApplication();
return true; return true;
} }

BIN
app/androidkey.keystore Normal file

Binary file not shown.

View File

@@ -26,6 +26,12 @@ android {
storeFile file("test.keystore") storeFile file("test.keystore")
storePassword '123456' storePassword '123456'
} }
debug {//非目标签名 用于验证
keyAlias 'androidkey'
keyPassword 'android'
storeFile file("androidkey.keystore")
storePassword 'android'
}
} }
@@ -39,7 +45,7 @@ android {
} }
debug{ debug{
debuggable true debuggable true
signingConfig signingConfigs.release signingConfig signingConfigs.debug
} }
} }

BIN
app/libs/x86/libold.so Normal file

Binary file not shown.

BIN
app/libs/x86_64/libold.so Normal file

Binary file not shown.

View File

@@ -24,22 +24,24 @@
//#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写 55 //#define SHA1 "04c1411b0662acd9e4aa300559677e5f106a5255"//区分da小写 55
//此处改为你的APP包名 //此处改为你的APP包名
#define APP_PKG "cn.android.sample" #define APP_PKG "cn.android.sample"
//此处改为你的application全名 没有就是android.app.Application
//#define APPLICATION_NAME "android.app.Application"
#define APPLICATION_NAME "cn.android.sample.MyApplication" #define APPLICATION_NAME "cn.android.sample.MyApplication"
//此处填写API盐值 //此处填写API盐值 MD5加盐
#define API_SECRET "ABC1234567"//设置api 密钥 MD5加盐 #define API_SECRET "ABC1234567"
static bool isInit = false; static bool isInit = false;
static char *secret; static char *secret;
//当动态库被加载时这个函数被系统调用 //当动态库被加载时这个函数被系统调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGI("JNI_OnLoad"); LOGI("JNI_OnLoad");
return JNI_VERSION_1_4; return JNI_VERSION_1_4;
} }
//当动态库被卸载时这个函数被系统调用 //当动态库被卸载时这个函数被系统调用
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
LOGI("JNI_OnUnload"); LOGI("JNI_OnUnload");
} }
jint version() { jint version() {
// 1. 获取 SDK 版本号 , 存储于 C 字符串 sdk_verison_str 中 // 1. 获取 SDK 版本号 , 存储于 C 字符串 sdk_verison_str 中
char sdk[128] = "0"; char sdk[128] = "0";
@@ -47,6 +49,7 @@ jint version() {
__system_property_get("ro.build.version.sdk", sdk); __system_property_get("ro.build.version.sdk", sdk);
//将版本号转为 int 值 //将版本号转为 int 值
int sdk_verison = atoi(sdk); int sdk_verison = atoi(sdk);
return sdk_verison; return sdk_verison;
} }
@@ -124,7 +127,7 @@ jobject getPackageInfo(JNIEnv *env, jobject package_manager, jstring package_nam
0x08000000);//安卓9 0x08000000 0x08000000);//安卓9 0x08000000
} else { } else {
package_info = env->CallObjectMethod(package_manager, methodId, package_name, package_info = env->CallObjectMethod(package_manager, methodId, package_name,
0x00000040);//安卓9 0x08000000 0x00000040);
} }
return package_info; return package_info;
} }
@@ -219,7 +222,7 @@ jobject getSignature28(JNIEnv *env, jobject package_info) {
jobjectArray signature_object_array = (jobjectArray) env->CallObjectMethod(signingInfo_object, jobjectArray signature_object_array = (jobjectArray) env->CallObjectMethod(signingInfo_object,
methodId); methodId);
LOGE("%s", "methodId:getApkContentsSigners"); LOGE("%s", "methodId:getApkContentsSigners");
if (signature_object_array == nullptr){ if (signature_object_array == nullptr) {
LOGE("signature_object_array空"); LOGE("signature_object_array空");
return nullptr; return nullptr;
} }
@@ -334,7 +337,7 @@ Java_cn_android_security_APISecurity_init(
//获取PackageInfo对象 //获取PackageInfo对象
jobject package_info = getPackageInfo(env, package_manager, package_name); jobject package_info = getPackageInfo(env, package_manager, package_name);
if (package_info == nullptr){ if (package_info == nullptr) {
LOGE("package_info空"); LOGE("package_info空");
return JNI_FALSE; return JNI_FALSE;
} }
@@ -346,7 +349,7 @@ Java_cn_android_security_APISecurity_init(
} else { } else {
signature_object = getSignature(env, package_info); signature_object = getSignature(env, package_info);
} }
if (signature_object == nullptr){ if (signature_object == nullptr) {
LOGE("signature_object空"); LOGE("signature_object空");
return JNI_FALSE; return JNI_FALSE;
} }
@@ -367,7 +370,7 @@ Java_cn_android_security_APISecurity_init(
LOGE("非法调用2Package: %s", pkgName); LOGE("非法调用2Package: %s", pkgName);
return JNI_FALSE; return JNI_FALSE;
} }
/*********接着调用Java方法验证 安装目录apk文件de签名**/ /*********接着调用Java方法验证 安装目录apk文件签名**/
jclass cls_util = env->FindClass( jclass cls_util = env->FindClass(
"cn/android/security/APISecurity"); "cn/android/security/APISecurity");
//注意,这里的使用的斜杠而不是点 //注意,这里的使用的斜杠而不是点
@@ -516,13 +519,13 @@ void checkTaskCount() {
} }
/** /**
* Application.getClass().getName(); 验证application是否被替换 * Application.getClass().getName(); 验证application是否被替换 【前提是不能用360加固那些 否则二次jiagu后无法察觉】
*/ */
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_cn_android_security_APISecurity_verifyApp(JNIEnv *env, jclass clazz, Java_cn_android_security_APISecurity_verifyApp(JNIEnv *env, jclass clazz,
jobject application_by_reflect) { jobject application_by_reflect) {
// jclass application_clazz=env->GetObjectClass(application_by_reflect); // jclass application_clazz=env->GetObjectClass(application_by_reflect);
jclass object_clazz = env->FindClass("java/lang/Object"); jclass object_clazz = env->FindClass("java/lang/Object");
jmethodID getClass = env->GetMethodID(object_clazz, "getClass", "()Ljava/lang/Class;"); jmethodID getClass = env->GetMethodID(object_clazz, "getClass", "()Ljava/lang/Class;");
jobject clazz_object = env->CallObjectMethod(application_by_reflect, getClass); jobject clazz_object = env->CallObjectMethod(application_by_reflect, getClass);
@@ -530,12 +533,53 @@ Java_cn_android_security_APISecurity_verifyApp(JNIEnv *env, jclass clazz,
jmethodID getNameId = env->GetMethodID(mClazz, "getName", "()Ljava/lang/String;"); jmethodID getNameId = env->GetMethodID(mClazz, "getName", "()Ljava/lang/String;");
jstring appname = (jstring) env->CallObjectMethod(clazz_object, getNameId); jstring appname = (jstring) env->CallObjectMethod(clazz_object, getNameId);
const char *ss = env->GetStringUTFChars(appname, nullptr); const char *ss = env->GetStringUTFChars(appname, nullptr);
LOGE("调用5NAME: %s", ss);
if (strcmp(ss, APPLICATION_NAME) != 0) { if (strcmp(ss, APPLICATION_NAME) != 0) {
LOGE("非法调用5SHA1: %s", ss); LOGE("非法调用5NAME: %s", ss);
isInit = false; isInit = false;
} }
}extern "C" }
extern "C"
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
Java_cn_android_security_APISecurity_getRelayPackName(JNIEnv *env, jclass clazz) { Java_cn_android_security_APISecurity_getRealyAppName(JNIEnv *env, jclass clazz) {
// TODO: implement getRelayPackName() return env->NewStringUTF(APPLICATION_NAME);
}
/**
* 在这里反射获取 application 对比applicationa是否被篡改 前提是不能用360加固那些 否则二次jiagu后无法察觉
*/
extern "C"
JNIEXPORT jboolean JNICALL
Java_cn_android_security_APISecurity_verifyApplication(JNIEnv *env, jclass clazz) {
jclass activityThread_clazz = env->FindClass("android/app/ActivityThread");
if (activityThread_clazz== nullptr){
return JNI_FALSE;
}
//activityThread_clazz = static_cast<jclass>(env->NewGlobalRef(activityThread_clazz));//全局引用(自己来提升)
jmethodID threadId = env->GetStaticMethodID(activityThread_clazz, "currentActivityThread",
"()Landroid/app/ActivityThread;");
jobject activityThread = env->CallStaticObjectMethod(activityThread_clazz, threadId);
jmethodID getApplication = env->GetMethodID(activityThread_clazz, "getApplication",
"()Landroid/app/Application;");
env->DeleteLocalRef(activityThread_clazz);//删除引用
jobject application = env->CallObjectMethod(activityThread, getApplication);
if (application== nullptr){
return JNI_FALSE;
}
jclass object_clazz = env->FindClass("java/lang/Object");
jmethodID getClass = env->GetMethodID(object_clazz, "getClass", "()Ljava/lang/Class;");
env->DeleteLocalRef(object_clazz);//删除引用
jobject clazz_object = env->CallObjectMethod(application, getClass);
jclass mClazz = env->FindClass("java/lang/Class");
jmethodID getNameId = env->GetMethodID(mClazz, "getName", "()Ljava/lang/String;");
env->DeleteLocalRef(mClazz);//删除引用
jstring appname = (jstring) env->CallObjectMethod(clazz_object, getNameId);
const char *ss = env->GetStringUTFChars(appname, nullptr);
LOGE("调用6NAME: %s", ss);
// env->DeleteGlobalRef(activityThread_clazz);//对应手动释放全局引用
if (strcmp(ss, APPLICATION_NAME) != 0) {
LOGE("非法调用6NAME: %s", ss);
isInit = false;
return JNI_FALSE;
}
return JNI_TRUE;
} }

View File

@@ -9,6 +9,7 @@ package cn.android.sample;
*/ */
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@@ -16,6 +17,7 @@ import android.content.pm.PackageManager;
import android.content.pm.Signature; import android.content.pm.Signature;
import android.content.pm.SigningInfo; import android.content.pm.SigningInfo;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
@@ -68,12 +70,51 @@ public class MyApplication extends Application implements InvocationHandler {
//在签名校验被hook 之后重置PackageManager //在签名校验被hook 之后重置PackageManager
/*在这里 重置PackageManager 只要在验证前重置即可*/ /*在这里 重置PackageManager 只要在验证前重置即可*/
AppSigning.resetPackageManager(getBaseContext()); AppSigning.resetPackageManager(getBaseContext());
lifeCallback();
}
private void lifeCallback() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
} }
/** /**
* 全局hook 签名校验 * 全局hook 签名校验
*
* @param context
*/ */
@SuppressLint("PrivateApi") @SuppressLint("PrivateApi")
private void hook(Context context) { private void hook(Context context) {
@@ -191,6 +232,4 @@ public class MyApplication extends Application implements InvocationHandler {
// IPackageManager接口中无getPackageArchiveInfo 方法无法代理 // IPackageManager接口中无getPackageArchiveInfo 方法无法代理
return method.invoke(this.base, objArr); return method.invoke(this.base, objArr);
} }
} }