Android敏感数据泄露引发的思考

#include <jni.h>

#ifndef _Included_com_test_util_HttpKeyUtil

#define _Included_com_test_util_HttpKeyUtil

#ifdef __cplusplus

extern “C” {

#endif

JNIEXPORT jstring JNICALL Java_com_esky_common_component_util_HttpKeyUtil_getHttpSecretKey

(JNIEnv *, jclass, jint);

JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue

(JNIEnv *, jclass, jbyteArray);

#ifdef __cplusplus

}

#endif

#endif

3.编写相应的cpp文件:

在相应的Module中创建jni目录,将**com_test_util_HttpKeyUtil.h拷贝进来,然后再创建com_test_util_HttpKeyUtil.cpp**文件

jni

#include <jni.h>

#include

#include <malloc.h>

#include “com_test_util_HttpKeyUtil.h”

extern “C”

const char *KEY1 = “密钥1”;

const char *KEY2 = “密钥2”;

const char *KEY3 = “密钥3”;

const char *UNKNOWN = “unknown”;

jstring toMd5(JNIEnv *pEnv, jbyteArray pArray);

extern “C” JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey

(JNIEnv *env, jclass cls, jint index) {

if (随机数条件1) {

return env->NewStringUTF(KEY1);

} else if (随机数条件2) {

return env->NewStringUTF(KEY2);

} else if (随机数条件3) {

return env->NewStringUTF(KEY3);

} else {

return env->NewStringUTF(UNKNOWN);

}

}

extern “C” JNIEXPORT jstring JNICALL

Java_com_test_util_HttpKeyUtil_getSecretValue

(JNIEnv *env, jclass cls, jbyteArray jbyteArray1) {

//加密算法各有不同,这里我就用md5做个示范

return toMd5(env, jbyteArray1);

}

//md5

jstring toMd5(JNIEnv *env, jbyteArray source) {

// MessageDigest

jclass classMessageDigest = env->FindClass(“java/security/MessageDigest”);

// MessageDigest.getInstance()

jmethodID midGetInstance = env->GetStaticMethodID(classMessageDigest, “getInstance”,

“(Ljava/lang/String;)Ljava/security/MessageDigest;”);

// MessageDigest object

jobject objMessageDigest = env->CallStaticObjectMethod(classMessageDigest, midGetInstance,

env->NewStringUTF(“md5”));

jmethodID midUpdate = env->GetMethodID(classMessageDigest, “update”, “([B)V”);

env->CallVoidMethod(objMessageDigest, midUpdate, source);

// Digest

jmethodID midDigest = env->GetMethodID(classMessageDigest, “digest”, “()[B”);

jbyteArray objArraySign = (jbyteArray) env->CallObjectMethod(objMessageDigest, midDigest);

jsize intArrayLength = env->GetArrayLength(objArraySign);

jbyte *byte_array_elements = env->GetByteArrayElements(objArraySign, NULL);

size_t length = (size_t) intArrayLength * 2 + 1;

char *char_result = (char *) malloc(length);

memset(char_result, 0, length);

toHexStr((const char *) byte_array_elements, char_result, intArrayLength);

// 在末尾补\0

*(char_result + intArrayLength * 2) = ‘\0’;

jstring stringResult = env->NewStringUTF(char_result);

// release

env->ReleaseByteArrayElements(objArraySign, byte_array_elements, JNI_ABORT);

// 指针

free(char_result);

return stringResult;

}

//转换为16进制字符串

void toHexStr(const char *source, char *dest, int sourceLen) {

short i;

char highByte, lowByte;

for (i = 0; i < sourceLen; i++) {

highByte = source[i] >> 4;

lowByte = (char) (source[i] & 0x0f);

highByte += 0x30;

if (highByte > 0x39) {

dest[i * 2] = (char) (highByte + 0x07);

} else {

dest[i * 2] = highByte;

}

lowByte += 0x30;

if (lowByte > 0x39) {

dest[i * 2 + 1] = (char) (lowByte + 0x07);

} else {

dest[i * 2 + 1] = lowByte;

}

}

}

4.事件就此结束?

到这里就此结束了?too yuang too simple!!!虽然将密钥和加密算法写在了c++中,貌似好像是比较安全了。但是但是万一别人反编译后,拿到c++代码最终生成的so库,然后直接调用so库里的方法去获取密钥并调用加密方法怎么破?看来我们还是要加一步身份校验才行:即在native层对应用的包名、签名进行鉴权校验,校验通过才返回正确结果。下面就是获取apk包名和签名校验的代码:

const char *PACKAGE_NAME = “你的ApplicationId”;

//(签名的md5值自己可以写方法获取,或者用签名工具直接获取,一般对接微信sdk的时候也会要应用签名的MD5值)

const char *SIGN_MD5 = “你的应用签名的MD5值注意是大写”;

//获取Application实例

jobject getApplication(JNIEnv *env) {

jobject application = NULL;

//这里是你的Application的类路径,混淆时注意不要混淆该类和该类获取实例的方法比如getInstance

jclass baseapplication_clz = env->FindClass(“com/test/component/BaseApplication”);

if (baseapplication_clz != NULL) {

jmethodID currentApplication = env->GetStaticMethodID(

baseapplication_clz, “getInstance”,

“()Lcom/test/component/BaseApplication;”);

if (currentApplication != NULL) {

application = env->CallStaticObjectMethod(baseapplication_clz, currentApplication);

}

env->DeleteLocalRef(baseapplication_clz);

}

return application;

}

bool isRight = false;

//获取应用签名的MD5值并判断是否与本应用的一致

jboolean getSignature(JNIEnv *env) {

LOGD(“getSignature isRight: %d”, isRight ? 1 : 0);

if (!isRight) {//避免每次都进行校验浪费资源,只要第一次校验通过后,后边就不在进行校验

jobject context = getApplication(env);

// 获得Context类

jclass cls = env->FindClass(“android/content/Context”);

// 得到getPackageManager方法的ID

jmethodID mid = env->GetMethodID(cls, “getPackageManager”,

“()Landroid/content/pm/PackageManager;”);

// 获得应用包的管理器

jobject pm = env->CallObjectMethod(context, mid);

// 得到getPackageName方法的ID

mid = env->GetMethodID(cls, “getPackageName”, “()Ljava/lang/String;”);

// 获得当前应用包名

jstring packageName = (jstring) env->CallObjectMethod(context, mid);

const char *c_pack_name = env->GetStringUTFChars(packageName, NULL);

// 比较包名,若不一致,直接return包名

if (strcmp(c_pack_name, PACKAGE_NAME) != 0) {

return false;

}

// 获得PackageManager类

cls = env->GetObjectClass(pm);

// 得到getPackageInfo方法的ID

mid = env->GetMethodID(cls, “getPackageInfo”,

“(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;”);

// 获得应用包的信息

jobject packageInfo = env->CallObjectMethod(pm, mid, packageName,

0x40); //GET_SIGNATURES = 64;

// 获得PackageInfo 类

cls = env->GetObjectClass(packageInfo);

// 获得签名数组属性的ID

jfieldID fid = env->GetFieldID(cls, “signatures”, “[Landroid/content/pm/Signature;”);

// 得到签名数组

jobjectArray signatures = (jobjectArray) env->GetObjectField(packageInfo, fid);

// 得到签名

jobject signature = env->GetObjectArrayElement(signatures, 0);

// 获得Signature类

cls = env->GetObjectClass(signature);

mid = env->GetMethodID(cls, “toByteArray”, “()[B”);

// 当前应用签名信息

jbyteArray signatureByteArray = (jbyteArray) env->CallObjectMethod(signature, mid);

//转成jstring

jstring str = toMd5(env, signatureByteArray);

char *c_msg = (char *) env->GetStringUTFChars(str, 0);

LOGD(“getSignature release sign md5: %s”, c_msg);

isRight = strcmp(c_msg, SIGN_MD5) == 0;

return isRight;

}

return isRight;

}

//有了校验的方法,所以我们要对第3步中,获取密钥和加密方法的进行修改,添加校验的逻辑

extern “C” JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey

(JNIEnv *env, jclass cls, jint index) {

if (getSignature(env)){//校验通过

if (随机数条件1) {

return env->NewStringUTF(KEY1);

} else if (随机数条件2) {

return env->NewStringUTF(KEY2);

} else if (随机数条件3) {

return env->NewStringUTF(KEY3);

} else {

return env->NewStringUTF(UNKNOWN);

}

}else {

return env->NewStringUTF(UNKNOWN);

}

}

extern “C” JNIEXPORT jstring JNICALL

Java_com_test_util_HttpKeyUtil_getSecretValue

(JNIEnv *env, jclass cls, jbyteArray jbyteArray1) {

//加密算法各有不同,这里我就用md5做个示范

if (getSignature(env)){//校验通过

return toMd5(env, jbyteArray1);

}else {

return env->NewStringUTF(UNKNOWN);

}

}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值