Android App 簽名保護demo

近來閒的無聊,看了看Android 應用安全防禦和逆向分析,裏面有個使用apk簽名防止反編譯的篇章。java

實踐了一下。git

有兩種方式,github

1. 可在java層斷定安全

獲取簽名的java代碼app

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;
    }

這種方式比較簡單,但也很容易被破解。ui

2. 在jni層判斷,編譯一個sospa

調用上面定義的獲取簽名函數和app_sig對比code

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層破解。blog

 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\n");
          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的簽名,詳細描述見下一篇文章),若是須要單獨使用請替換~

簽名的字符串

相關文章
相關標籤/搜索