Android本地关键代码安全处理
创始人
2025-05-31 08:11:24

一、背景

最近在做代码安全方面的工作,发现一些关键信息如:密钥、加密策略等直接写死在项目代码中,存在代码安全隐患。本文档提供一种示例:把关键信息,保存在native层;并对安装包关联信息进行校验,防止反编译、重签名导致信息泄露的可能。

二、处理方式

  • 关键信息、算法、逻辑下沉;利用C/C++编写,利用JNI方式引用。so库+核心java类,导出aar文件。
  • 导入aar,加载so库过程中对其关联的APP签名进行校验。如果校验通过,才能获取库内部信息。
  • 对C/C++编写的so库进行安全加固,二次防编译。
    在这里插入图片描述

三、关键逻辑

1. 签名校验

1.1 java代码获取签名

 private String getSign1() {try {//通过PackageManager获取PackageManager pm = getPackageManager();PackageInfo pi = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);Signature[] signatures = pi.signatures;Signature signature0 = signatures[0];return signature0.toCharsString();} catch (Exception e) {e.printStackTrace();return "";}}private String getSign2() {try {// 下面几行代码展示如何任意获取Context对象,在jni中也可以使用这种方式Class activityThreadClz = Class.forName("android.app.ActivityThread");Method currentApplication = activityThreadClz.getMethod("currentApplication");Application application = (Application) currentApplication.invoke(null);PackageManager pm = application.getPackageManager();PackageInfo pi = pm.getPackageInfo(application.getPackageName(), PackageManager.GET_SIGNATURES);Signature[] signatures = pi.signatures;Signature signature0 = signatures[0];return signature0.toCharsString();} catch (Exception e) {e.printStackTrace();return "";}}

1.2 C获取签名

static int verifySign(JNIEnv *env) {// Application objectjobject application = getApplication(env);if (application == NULL) {return JNI_ERR;}// Context(ContextWrapper) classjclass context_clz = env->GetObjectClass(application);// getPackageManager()jmethodID getPackageManager = env->GetMethodID(context_clz, "getPackageManager","()Landroid/content/pm/PackageManager;");// android.content.pm.PackageManager objectjobject package_manager = env->CallObjectMethod(application, getPackageManager);// PackageManager classjclass package_manager_clz = env->GetObjectClass(package_manager);// getPackageInfo()jmethodID getPackageInfo = env->GetMethodID(package_manager_clz, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");// context.getPackageName()jmethodID getPackageName = env->GetMethodID(context_clz, "getPackageName","()Ljava/lang/String;");// call getPackageName() and cast from jobject to jstringjstring package_name = (jstring) (env->CallObjectMethod(application, getPackageName));// PackageInfo objectjobject package_info = env->CallObjectMethod(package_manager, getPackageInfo, package_name, 64);// class PackageInfojclass package_info_clz = env->GetObjectClass(package_info);// field signaturesjfieldID signatures_field = env->GetFieldID(package_info_clz, "signatures","[Landroid/content/pm/Signature;");jobject signatures = env->GetObjectField(package_info, signatures_field);jobjectArray signatures_array = (jobjectArray) signatures;jobject signature0 = env->GetObjectArrayElement(signatures_array, 0);jclass signature_clz = env->GetObjectClass(signature0);jmethodID toCharsString = env->GetMethodID(signature_clz, "toCharsString","()Ljava/lang/String;");// call toCharsString()jstring signature_str = (jstring) (env->CallObjectMethod(signature0, toCharsString));// releaseenv->DeleteLocalRef(application);env->DeleteLocalRef(context_clz);env->DeleteLocalRef(package_manager);env->DeleteLocalRef(package_manager_clz);env->DeleteLocalRef(package_name);env->DeleteLocalRef(package_info);env->DeleteLocalRef(package_info_clz);env->DeleteLocalRef(signatures);env->DeleteLocalRef(signature0);env->DeleteLocalRef(signature_clz);//获取到安装的APK对应的签名const char *sign = env->GetStringUTFChars(signature_str, NULL);if (sign == NULL) {LOGE("分配内存失败");return JNI_ERR;}//    LOGI("应用中读取到的签名为:%s", sign);int result_debug = strcmp(sign, SIGN_Debug);int result_release = strcmp(sign, SIGN_Release);// 使用之后要释放这段内存env->ReleaseStringUTFChars(signature_str, sign);env->DeleteLocalRef(signature_str);if (result_debug == 0 || result_release == 0) { // 签名一致return JNI_OK;}return JNI_ERR;
}

1.3 是否打开APP签名校验

void Java_com_ankerwork_ctool_Security_setCheckSign(JNIEnv *env, jclass clazz, jboolean is_check) {unsigned char b = is_check;LOGI("/n is_check: %lu  ", b);if (b) {isCheck = true;} else {isCheck = false;}
}

2. 打包AAR

找到Module对应的Task,执行 执行assembleRelease
如:
在这里插入图片描述

3. 调用

3.1 引入AAR

  1. 将aar拷贝至该Module的libs目录中
  2. 在该Module的build.gradle中补上下面的代码
repositories {flatDir {dirs 'libs'}
}
dependencies {compile(name:'XXX', ext:'aar')
}

3.2 Java代码获取签名

参考1.1方法

3.3 c代码中填写签名内容

定义变量如:

static const char *sign = "1111"

3.4 设置是否校验签名

public class Security {static {System.loadLibrary("selfsecurity");}public static native String getIjmSecret();public static native void setCheckSign(boolean isCheck);
}Security.setCheckSign(true);//设置校验签名

3.5 获取关键Key

Security.getIjmSecret()

四、参考代码

完整代码链接:https://download.csdn.net/download/fepengwang/87594007

相关内容

热门资讯

韩国首个商业运载火箭发射失败 韩国首尔时间23日10时13分许,韩国民间运载火箭企业INNOSPACE的首枚商业运载火箭“韩光-纳...
金钛股份业绩下滑,研发占比低,... 文:权衡财经iqhcj研究员 李力编:许辉朝阳金达钛业股份有限公司(简称:金钛股份)拟在北交所上市,...
“新城二代”布局潮玩,打出资本... 斑马消费 陈碧婷继2019年王晓松火线就任,对新城控股力挽狂澜后,如今,他26岁的妹妹王凯莉,正在通...
【开盘】A股三大股指集体小幅高... 12月23日,A股三大股指集体小幅高开。其中,沪指涨0.04%报3919.11点,深成指涨0.05%...
LMArena最新排名:文心大... 12月23日,LMArena 大模型竞技场发布最新排名,文心新模型 ERNIE-5.0-Previe...