├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── maxwell │ │ └── nc │ │ └── nativestrencrypt │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── encryptlib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── maxwell │ │ └── nc │ │ └── encryptlib │ │ └── EncryptUtils.java │ ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── DecryptAPI.cpp │ ├── DecryptAPI.h │ ├── EncryptUtils.cpp │ ├── EncryptUtils.h │ ├── Tools.cpp │ └── Tools.h │ ├── libs │ ├── armeabi-v7a │ │ └── libmaxwell_encrypt.so │ ├── armeabi │ │ └── libmaxwell_encrypt.so │ └── x86 │ │ └── libmaxwell_encrypt.so │ └── res │ └── values │ └── strings.xml ├── gradle.properties ├── gradlew ├── gradlew.bat ├── preview ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg └── 5.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | /.idea 57 | /encryptlib/src/main/obj 58 | /gradle 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android字符串加密库 2 | An Android native library (*.so) which encrypt/decrypt string and proguard it to prevent decompile. 3 | 4 | ## 特点 Feature 5 | 6 | - 正版应用调用校验(防止二次打包等问题) 7 | - 函数名及内容混淆 8 | - 关键代码及字符串隐藏 9 | - 支持自定义加密解密扩展 10 | - 入口防止动态调试等等 11 | 12 | 13 | ## 预览 Preview 14 | 15 | 下面是正版应用调用展示: 16 | 17 | ![](preview/1.jpg) 18 | 19 | 20 | 下面是非法应用调用结果(包名或签名不一致): 21 | 22 | ![](preview/2.jpg) 23 | 24 | 下面是反编译后函数列表(混淆): 25 | 26 | ![](preview/3.jpg) 27 | 28 | 下面是搜索关键数据(如加密密钥、加密后的数据): 29 | 30 | ![](preview/4.jpg) 31 | 32 | 下面是关键代码片段反生成代码(加大反编译难度): 33 | 34 | ![](preview/5.jpg) 35 | 36 | 37 | ## 用法 Usage 38 | 39 | 注意:下面均忽略JNI调用的通用步骤 40 | 41 | 1.配置你的应用签名及包名 42 | 43 |   打开Tools.cpp,修改替换sign和validPackage内容,比如签名为:-498576263,包名为:com.github.maxwell.nc.nativestrencrypt,则可以修改为如下代码: 44 | ```c 45 | //正版签名hashcode,换签名请修改这个 46 | //忽略hashcode碰撞问题(另外有包名校验) 47 | //必须是使用tricks写法,直接int可以从so中静态反编译找到(容易被替换) 48 | char* sign = (char[]){'-','4','9','8','5','7','6','2','6','3'}; 49 | int vaildSignHash = atoi(sign); 50 | 51 | //正版包名 52 | //可以任意分割,见nstrcat 53 | const char* validPackage = nstrcat("com","co","m",".","gi","thub",".","max","we","ll", 54 | ".","nc",".","native","str","encrypt","com"); 55 | ``` 56 |   如果你不确定你的包名和签名,可以通过打开日志信息,观察日志中生成的hashcode和sign即为当前应用的签名hashcode及包名。 57 | 58 | 2.配置你的原生函数 59 | 60 |   由于是采用反射获取方法名称,需要通过配置regClazz(调用原生方法的包名)和gMethods(原生方法名、方法签名、函数指针),然后参考getSamplePass函数调用decryptStr方法进行解密: 61 | ```c 62 | __attribute__((section ("datas"))) 63 | JNICALL jstring getSamplePass(JNIEnv *env, jclass clazz, jobject object){ 64 | //这里的 616263898b8a 为加密后的字符串(可以任意分割) 65 | return decryptStr(env,object,"616","263","8","98","b8a",fakePass); 66 | } 67 | 68 | //要寻找的类:配置你的包名 69 | static char regClazz[] = "com/github/maxwell/nc/encryptlib/EncryptUtils"; 70 | 71 | //要寻找的方法:配置你的方法 72 | static JNINativeMethod gMethods[] = { 73 | { "getSamplePass", "(Ljava/lang/Object;)Ljava/lang/String;", (void*)getSamplePass }, 74 | }; 75 | ``` 76 | 77 | 78 | 3.调用原生方法 79 | ```java 80 | String samplePass = EncryptUtils.getSamplePass(this); 81 | ``` 82 | 如果错误则会返回预定义错误的字符串 83 | 84 | 4.特别注意!!! 85 | 86 | 源代码中加密解密方法随便写的,十分简单,不能用于实际应用。建议采用高强度加密解密算法(最好修改通用方法,加强安全) 87 | 88 | ## 进阶 Advance 89 | 90 | 打开日志信息 91 | 92 |   可以通过修改Tools.h中的宏定义: 93 | ```c 94 | #define DEBUG true 95 | ``` 96 | 97 | 修改预定义错误返回字符串 98 | 99 |   可以通过修改EncryptUtils.cpp中的decryptStr函数中的: 100 | ```c 101 | char* failStr = (char[]){'e','r','r','o','r','\0'}; 102 | ``` 103 | 104 | 其他事项 105 | 106 |   暂时没想到,以后有空再补充。 107 | 108 |   Sorry, I have no empty time to translate this readme file into English. 109 | 110 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /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.github.maxwell.nc.nativestrencrypt" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation project(':encryptlib') 24 | } 25 | -------------------------------------------------------------------------------- /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 E:\Development\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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/maxwell/nc/nativestrencrypt/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.maxwell.nc.nativestrencrypt; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.github.maxwell.nc.encryptlib.EncryptUtils; 9 | 10 | public class MainActivity extends Activity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | } 17 | 18 | /** 19 | * 按钮点击事件 20 | */ 21 | public void onButtonClick(View view) { 22 | getPassword(); 23 | } 24 | 25 | /** 26 | * so调用例子 27 | */ 28 | public void getPassword() { 29 | TextView tvPass = (TextView) findViewById(R.id.tv_pass); 30 | 31 | String samplePass = EncryptUtils.getSamplePass(this);//获取密码 32 | if (samplePass.equals("error")) { 33 | tvPass.setText("获取结果:非合法应用调用!"); 34 | } else { 35 | tvPass.setText(String.format("获取结果:%s", samplePass)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |