├── .gitignore ├── README.md ├── app ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── aizuzi │ │ └── verificationdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── native-lib.cpp │ │ └── valid.cpp │ ├── java │ │ └── com │ │ │ └── aizuzi │ │ │ └── verificationdemo │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── aizuzi │ └── verificationdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle └── wrapper │ └── gradle-wrapper.jar └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SignatureVerificationDemo 2 | Android 使用jni校验应用签名sha1值,防止so文件逆向盗用 3 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | 14 | add_library( # Sets the name of the library. 15 | native-lib 16 | 17 | # Sets the library as a shared library. 18 | SHARED 19 | 20 | # Provides a relative path to your source file(s). 21 | src/main/cpp/native-lib.cpp) 22 | 23 | # Searches for a specified prebuilt library and stores the path as a 24 | # variable. Because CMake includes system libraries in the search path by 25 | # default, you only need to specify the name of the public NDK library 26 | # you want to add. CMake verifies that the library exists before 27 | # completing its build. 28 | 29 | find_library( # Sets the name of the path variable. 30 | log-lib 31 | 32 | # Specifies the name of the NDK library that 33 | # you want CMake to locate. 34 | log ) 35 | 36 | # Specifies libraries CMake should link to your target library. You 37 | # can link multiple libraries, such as libraries you define in this 38 | # build script, prebuilt third-party libraries, or system libraries. 39 | 40 | target_link_libraries( # Specifies the target library. 41 | native-lib 42 | 43 | # Links the target library to the log library 44 | # included in the NDK. 45 | ${log-lib} ) -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.aizuzi.verificationdemo" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | externalNativeBuild { 14 | cmake { 15 | cppFlags "" 16 | } 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | externalNativeBuild { 26 | cmake { 27 | path "CMakeLists.txt" 28 | } 29 | } 30 | } 31 | 32 | dependencies { 33 | compile fileTree(dir: 'libs', include: ['*.jar']) 34 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 35 | exclude group: 'com.android.support', module: 'support-annotations' 36 | }) 37 | compile 'com.android.support:appcompat-v7:25.3.1' 38 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 39 | testCompile 'junit:junit:4.12' 40 | } 41 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aizuzi/verificationdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.aizuzi.verificationdemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.aizuzi.verificationdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/cpp/native-lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"valid.cpp" 4 | 5 | extern "C" 6 | JNIEXPORT jstring JNICALL 7 | Java_com_aizuzi_verificationdemo_MainActivity_getSignaturesSha1( 8 | JNIEnv *env, 9 | jobject, 10 | jobject contextObject) { 11 | 12 | return env->NewStringUTF(app_sha1); 13 | } 14 | extern "C" 15 | JNIEXPORT jboolean JNICALL 16 | Java_com_aizuzi_verificationdemo_MainActivity_checkSha1( 17 | JNIEnv *env, 18 | jobject, 19 | jobject contextObject) { 20 | 21 | char *sha1 = getSha1(env,contextObject); 22 | 23 | jboolean result = checkValidity(env,sha1); 24 | 25 | return result; 26 | } 27 | extern "C" 28 | JNIEXPORT jstring JNICALL 29 | Java_com_aizuzi_verificationdemo_MainActivity_getToken( 30 | JNIEnv *env, 31 | jobject, 32 | jobject contextObject, 33 | jstring userId) { 34 | char *sha1 = getSha1(env,contextObject); 35 | jboolean result = checkValidity(env,sha1); 36 | 37 | if(result){ 38 | return env->NewStringUTF("获取Token成功"); 39 | }else{ 40 | return env->NewStringUTF("获取失败,请检查valid.cpp文件配置的sha1值"); 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/cpp/valid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define TAG "jni-log" 7 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) 8 | 9 | //签名信息 10 | const char *app_sha1="81BA0CF9134C6415F34C3BCC854913A53C71415E"; 11 | const char hexcode[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 12 | 13 | char* getSha1(JNIEnv *env, jobject context_object){ 14 | //上下文对象 15 | jclass context_class = env->GetObjectClass(context_object); 16 | 17 | //反射获取PackageManager 18 | jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;"); 19 | jobject package_manager = env->CallObjectMethod(context_object, methodId); 20 | if (package_manager == NULL) { 21 | LOGD("package_manager is NULL!!!"); 22 | return NULL; 23 | } 24 | 25 | //反射获取包名 26 | methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;"); 27 | jstring package_name = (jstring)env->CallObjectMethod(context_object, methodId); 28 | if (package_name == NULL) { 29 | LOGD("package_name is NULL!!!"); 30 | return NULL; 31 | } 32 | env->DeleteLocalRef(context_class); 33 | 34 | //获取PackageInfo对象 35 | jclass pack_manager_class = env->GetObjectClass(package_manager); 36 | methodId = env->GetMethodID(pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 37 | env->DeleteLocalRef(pack_manager_class); 38 | jobject package_info = env->CallObjectMethod(package_manager, methodId, package_name, 0x40); 39 | if (package_info == NULL) { 40 | LOGD("getPackageInfo() is NULL!!!"); 41 | return NULL; 42 | } 43 | env->DeleteLocalRef(package_manager); 44 | 45 | //获取签名信息 46 | jclass package_info_class = env->GetObjectClass(package_info); 47 | jfieldID fieldId = env->GetFieldID(package_info_class, "signatures", "[Landroid/content/pm/Signature;"); 48 | env->DeleteLocalRef(package_info_class); 49 | jobjectArray signature_object_array = (jobjectArray)env->GetObjectField(package_info, fieldId); 50 | if (signature_object_array == NULL) { 51 | LOGD("signature is NULL!!!"); 52 | return NULL; 53 | } 54 | jobject signature_object = env->GetObjectArrayElement(signature_object_array, 0); 55 | env->DeleteLocalRef(package_info); 56 | 57 | //签名信息转换成sha1值 58 | jclass signature_class = env->GetObjectClass(signature_object); 59 | methodId = env->GetMethodID(signature_class, "toByteArray", "()[B"); 60 | env->DeleteLocalRef(signature_class); 61 | jbyteArray signature_byte = (jbyteArray) env->CallObjectMethod(signature_object, methodId); 62 | jclass byte_array_input_class=env->FindClass("java/io/ByteArrayInputStream"); 63 | methodId=env->GetMethodID(byte_array_input_class,"","([B)V"); 64 | jobject byte_array_input=env->NewObject(byte_array_input_class,methodId,signature_byte); 65 | jclass certificate_factory_class=env->FindClass("java/security/cert/CertificateFactory"); 66 | methodId=env->GetStaticMethodID(certificate_factory_class,"getInstance","(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;"); 67 | jstring x_509_jstring=env->NewStringUTF("X.509"); 68 | jobject cert_factory=env->CallStaticObjectMethod(certificate_factory_class,methodId,x_509_jstring); 69 | methodId=env->GetMethodID(certificate_factory_class,"generateCertificate",("(Ljava/io/InputStream;)Ljava/security/cert/Certificate;")); 70 | jobject x509_cert=env->CallObjectMethod(cert_factory,methodId,byte_array_input); 71 | env->DeleteLocalRef(certificate_factory_class); 72 | jclass x509_cert_class=env->GetObjectClass(x509_cert); 73 | methodId=env->GetMethodID(x509_cert_class,"getEncoded","()[B"); 74 | jbyteArray cert_byte=(jbyteArray)env->CallObjectMethod(x509_cert,methodId); 75 | env->DeleteLocalRef(x509_cert_class); 76 | jclass message_digest_class=env->FindClass("java/security/MessageDigest"); 77 | methodId=env->GetStaticMethodID(message_digest_class,"getInstance","(Ljava/lang/String;)Ljava/security/MessageDigest;"); 78 | jstring sha1_jstring=env->NewStringUTF("SHA1"); 79 | jobject sha1_digest=env->CallStaticObjectMethod(message_digest_class,methodId,sha1_jstring); 80 | methodId=env->GetMethodID(message_digest_class,"digest","([B)[B"); 81 | jbyteArray sha1_byte=(jbyteArray)env->CallObjectMethod(sha1_digest,methodId,cert_byte); 82 | env->DeleteLocalRef(message_digest_class); 83 | 84 | //转换成char 85 | jsize array_size=env->GetArrayLength(sha1_byte); 86 | jbyte* sha1 =env->GetByteArrayElements(sha1_byte,NULL); 87 | char *hex_sha=new char[array_size*2+1]; 88 | for (int i = 0; i 2 | 11 | 12 | 16 | 17 | 21 | 22 | 26 | 27 | 28 | 33 | 34 | 38 | 39 | 43 | 44 | 45 |