近来闲的无聊,看了看Android 应用安全防护和逆向分析,里面有个使用apk签名防止反编译的篇章。
实践了一下。
有两种方式,
1. 可在java层判定
获取签名的java代码
public static String getSignature(){ Context context = mContext; try{ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); Signature[]signatures = packageInfo.signatures; StringBuilder stringBuilder = new StringBuilder(); for(Signature signature : signatures){ stringBuilder.append(signature.toCharsString()); } return stringBuilder.toString(); } catch (PackageManager.NameNotFoundException e){ e.printStackTrace(); } return ""; }
然后简单判定一下:
private boolean isOwnApp(){ if (APP_SIGN.equalsIgnoreCase(getSignature())){ return true; } return false; }
这种方式比较简单,但也很容易被破解。
2. 在jni层判断,编译一个so
调用上面定义的获取签名函数和app_sig对比
const char *app_sig = "xxx"; JNIEXPORT jboolean JNICALL Java_com_example_signatureprotect_SignatureJni_isEqual (JNIEnv *env, jclass jcla, jstring sig) { char *className = "com/example/signatureprotect/MainActivity"; jclass clazz = (env)->FindClass(className); if (clazz == NULL) { LOGI("do not find class '%s'", className); return false; } LOGI("find class '%s'", className); jmethodID method = (env)->GetStaticMethodID( clazz, "getSignature", "()Ljava/lang/String;"); if (method == NULL) { LOGI("do not find method"); return false; } LOGI("find method"); jstring obj = (jstring)(env)->CallStaticObjectMethod( clazz, method); if (obj == NULL){ LOGI("invoke error: %p", obj); return false; } LOGI("invoke method"); const char *str = (env)->GetStringUTFChars(obj, 0); LOGI("str %s", str); int cmpval = strcmp(str, app_sig); LOGI("strcmp pass"); if (cmpval == 0) { LOGI("equal return true"); return true; } (env)->ReleaseStringUTFChars(obj,str); LOGI("equal return false"); return false; }
可以在java层调用,但是这样调用跟上面的第一种方法区别不大,可在java层破解。
private boolean isOwnApp2(){ if (SignatureJni.isEqual("")){ return true; } return false; }
可以在加载so的时候判断,重写JNI_OnLoad函数即可
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; LOGI("JNI_OnLoad"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGI("ERROR: GetEnv failed "); goto bail; } if(env == NULL) return result; /* success -- return valid version number */ result = JNI_VERSION_1_4; if (!Java_com_example_signatureprotect_SignatureJni_isEqual(env, NULL, NULL)) { char *className = "com/example/signatureprotect/MainActivity"; jclass clazz = (env)->FindClass(className); if (clazz == NULL) { LOGI("do not find class '%s'", className); return false; } jmethodID method = (env)->GetStaticMethodID( clazz, "killMyself", "()V"); if (method == NULL) { LOGI("do not find method"); return result; } LOGI("find method"); (env)->CallStaticVoidMethod( clazz, method); }
这样相对会好一些
源码地址:https://github.com/george-cw/AppAddShellDemo
这个源码有三个模块,APP模块是签名保护的demo,但是里面的定义的签名字符串不是APP的签名(是加壳app的签名,详细描述见下一篇文章),如果需要单独使用请替换~
签名的字符串