Android Apk 安全之校验签名
校验签名
一般绝大多数的 app 在上线前都会做一层安全防护,比如代码混淆、加固等。
今天就来讲讲其中的一项:校验签名。
校验签名可以有效的防止二次打包,避免你的 app 被植入广告甚至破解等。而今天就从两个角度来讲签名的具体校验:
- Java 层
- C/C++ 层
那么就先开始讲 java 层好了。
Java 层
1 | private static boolean validateAppSignature(Context context, String apkSignature) { |
Java 层的签名校验核心代码就这些,传入的两个参数 :
- Context context : 一般都是 Application
- String apkSignature : 你的 apk 的正式签名
Java 层的签名校验比较容易被攻破,因为别人可以反编译一下,然后在 smali 中把 validateAppSignature 方法的返回值改成 true 就大功告成了。
也正因为如此,所以需要在 C/C++ 层中也加入签名校验。
C/C++ 层
在 so 文件加载的时候,会去调用 JNI_OnLoad 函数,所以我们可以在这里做签名校验。
1 | JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { |
签名校验的代码主要在 checkAppSignature 函数中:
1 | static jboolean checkAppSignature(JNIEnv *env) { |
可以看出来,checkAppSignature 主要是通过 C 的代码反射来获取 Context 。
对应的 Java 层代码如下,一般来说, Security.setContext(application)
会在 Application.onCreate 方法中调用 :
1 | public class Security { |
获取到 Context 之后,就可以来比较签名了 :
1 | const char* APP_SIGNATURE = "input your signature of apk"; |
这里的 APP_SIGNATURE 就是正式版的签名字符串,而 loadSignature 函数需要反射安卓系统的 API 才能获得。
1 | static jstring loadSignature(JNIEnv *env, jobject context) { |
loadSignature 函数可以说就是用 C 语言把上面 Java 的那段代码实现了一遍,并没有什么差别。