Android App 签名保护demo

近来闲的无聊,看了看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的签名,详细描述见下一篇文章),如果需要单独使用请替换~

签名的字符串

原文地址:https://www.cnblogs.com/george-cw/p/10299951.html