├── AndroidShell ├── .gitignore ├── .idea │ ├── caches │ │ └── build_file_checksums.ser │ ├── codeStyles │ │ └── Project.xml │ ├── gradle.xml │ ├── misc.xml │ └── runConfigurations.xml ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── missile │ │ │ └── demo │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── missile │ │ │ │ └── demo │ │ │ │ ├── GlideUtil.java │ │ │ │ ├── ImageActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── NetStateReceiver.java │ │ │ │ └── app │ │ │ │ └── DemoApplication.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ ├── activity_image.xml │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.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 │ │ └── missile │ │ └── demo │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── secure-jni │ ├── .gitignore │ ├── CMakeLists.txt │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── missile │ │ │ └── secure │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── cpp │ │ │ ├── com_missile_secure_ProxyApplication.h │ │ │ └── secure.cpp │ │ ├── java │ │ │ └── com │ │ │ │ └── missile │ │ │ │ └── secure │ │ │ │ ├── MainActivity.java │ │ │ │ └── ProxyApplication.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ ├── activity_image.xml │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.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 │ │ └── missile │ │ └── secure │ │ └── ExampleUnitTest.java ├── secure │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── missile │ │ │ └── secure │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── missile │ │ │ │ └── secure │ │ │ │ ├── MainActivity.java │ │ │ │ ├── ProxyApplication.java │ │ │ │ └── RefInvoke.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ ├── activity_image.xml │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.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 │ │ └── missile │ │ └── secure │ │ └── ExampleUnitTest.java └── settings.gradle ├── AndroidShellTools ├── .gitignore ├── .idea │ ├── compiler.xml │ ├── description.html │ ├── encodings.xml │ ├── misc.xml │ ├── uiDesigner.xml │ └── vcs.xml ├── force │ ├── classes.dex │ ├── demo.apk │ └── shell.dex └── src │ └── DexShellTool.java ├── README.md └── Tools ├── README.txt ├── payload-release.apk ├── payload.apk ├── secure.jks └── sign.bat /AndroidShell/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /AndroidShell/.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /AndroidShell/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /AndroidShell/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /AndroidShell/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /AndroidShell/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidShell/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AndroidShell/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.missile.demo" 7 | minSdkVersion 19 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 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(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:28.0.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 28 | 29 | implementation 'com.github.bumptech.glide:glide:3.6.1' 30 | } 31 | -------------------------------------------------------------------------------- /AndroidShell/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /AndroidShell/app/src/androidTest/java/com/missile/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 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 | * Instrumented 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() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.missile.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/java/com/missile/demo/GlideUtil.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 2 | 3 | import android.content.Context; 4 | import android.widget.ImageView; 5 | 6 | import com.bumptech.glide.Glide; 7 | 8 | 9 | public class GlideUtil { 10 | 11 | public static void setImage(Context context, String url, ImageView img) { 12 | Glide.with(context).load(url).dontAnimate().fitCenter().placeholder(R.mipmap.ic_launcher_round).into(img); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/java/com/missile/demo/ImageActivity.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 2 | 3 | import android.content.IntentFilter; 4 | import android.net.ConnectivityManager; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.widget.ImageView; 8 | 9 | 10 | public class ImageActivity extends AppCompatActivity { 11 | 12 | 13 | private NetStateReceiver receiver = new NetStateReceiver(); 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_image); 19 | 20 | IntentFilter filter = new IntentFilter(); 21 | filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 22 | registerReceiver(receiver, filter); 23 | receiver.onReceive(this, null); 24 | 25 | ImageView image = (ImageView) findViewById(R.id.image); 26 | GlideUtil.setImage(this, "http://pic.sc.chinaz.com/files/pic/pic9/201508/apic14052.jpg", image); 27 | } 28 | 29 | @Override 30 | protected void onDestroy() { 31 | super.onDestroy(); 32 | this.unregisterReceiver(receiver); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/java/com/missile/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.AppCompatButton; 7 | import android.view.View; 8 | import android.widget.TextView; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | 17 | TextView textView = findViewById(R.id.text); 18 | textView.setText("包名: " + getAppInfo()); 19 | 20 | AppCompatButton button = findViewById(R.id.button); 21 | button.setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(View view) { 24 | startActivity(new Intent(MainActivity.this, ImageActivity.class)); 25 | } 26 | }); 27 | 28 | } 29 | 30 | private String getAppInfo() { 31 | try { 32 | String pkName = this.getPackageName(); 33 | return pkName; 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/java/com/missile/demo/NetStateReceiver.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.ConnectivityManager; 8 | import android.net.NetworkInfo; 9 | 10 | public class NetStateReceiver extends BroadcastReceiver { 11 | 12 | @Override 13 | public void onReceive(final Context context, Intent arg) { 14 | ConnectivityManager manager = (ConnectivityManager) context. 15 | getSystemService(Context.CONNECTIVITY_SERVICE); 16 | if (manager != null) { 17 | NetworkInfo gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); 18 | NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 19 | if (!gprs.isConnected() && !wifi.isConnected()) { 20 | AlertDialog.Builder ab = new AlertDialog.Builder(context); 21 | ab.setTitle("网络不可用"); 22 | ab.setMessage("请检查网络状态!"); 23 | ab.create().show(); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /AndroidShell/app/src/main/java/com/missile/demo/app/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo.app; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | 7 | public class DemoApplication extends Application { 8 | 9 | private static final String TAG = "DemoApplication"; 10 | 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | Log.e(TAG, "====== apk onCreate ======" + this); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/layout/activity_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AndroidShell 3 | 4 | -------------------------------------------------------------------------------- /AndroidShell/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidShell/app/src/test/java/com/missile/demo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.demo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /AndroidShell/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.2' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /AndroidShell/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /AndroidShell/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /AndroidShell/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Nov 13 10:12:21 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /AndroidShell/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /AndroidShell/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Sets the minimum version of CMake required to build the native 2 | # library. You should either keep the default value or only pass a 3 | # value of 3.4.0 or lower. 4 | 5 | cmake_minimum_required(VERSION 3.4.1) 6 | 7 | # Creates and names a library, sets it as either STATIC 8 | # or SHARED, and provides the relative paths to its source code. 9 | # You can define multiple libraries, and CMake builds it for you. 10 | # Gradle automatically packages shared libraries with your APK. 11 | 12 | add_library( # Sets the name of the library. 13 | secure 14 | 15 | # Sets the library as a shared library. 16 | SHARED 17 | 18 | # Provides a relative path to your source file(s). 19 | # Associated headers in the same location as their source 20 | # file are automatically included. 21 | src/main/cpp/secure.cpp ) 22 | 23 | # Searches for a specified prebuilt library and stores the path as a 24 | # variable. Because system libraries are included 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 the 38 | # build script, prebuilt third-party libraries, or system libraries. 39 | 40 | target_link_libraries( # Specifies the target library. 41 | secure 42 | 43 | # Links the target library to the log library 44 | # included in the NDK. 45 | ${log-lib} ) 46 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | 7 | 8 | defaultConfig { 9 | applicationId "com.missile.secure" 10 | minSdkVersion 19 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | externalNativeBuild { 17 | cmake { 18 | cppFlags "" 19 | } 20 | } 21 | ndk { 22 | // Specifies the ABI configurations of your native 23 | // libraries Gradle should build and package with your APK. 24 | abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 25 | 'arm64-v8a' 26 | } 27 | } 28 | 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | } 34 | } 35 | externalNativeBuild { 36 | cmake { 37 | path 'CMakeLists.txt' 38 | } 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | 45 | implementation 'com.android.support:appcompat-v7:28.0.0' 46 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 47 | testImplementation 'junit:junit:4.12' 48 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 49 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 50 | } 51 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/androidTest/java/com/missile/secure/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 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 | * Instrumented 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() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.missile.secure", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/cpp/com_missile_secure_ProxyApplication.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_missile_secure_ProxyApplication */ 4 | 5 | #ifndef _Included_com_missile_secure_ProxyApplication 6 | #define _Included_com_missile_secure_ProxyApplication 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_missile_secure_ProxyApplication 12 | * Method: decrypt 13 | * Signature: ([B)[B 14 | */ 15 | JNIEXPORT jbyteArray JNICALL Java_com_missile_secure_ProxyApplication_decrypt___3B 16 | (JNIEnv *, jobject, jbyteArray); 17 | 18 | /* 19 | * Class: com_missile_secure_ProxyApplication 20 | * Method: decrypt 21 | * Signature: ([BLjava/lang/String;)[B 22 | */ 23 | JNIEXPORT jbyteArray JNICALL Java_com_missile_secure_ProxyApplication_decrypt___3BLjava_lang_String_2 24 | (JNIEnv *, jobject, jbyteArray, jstring); 25 | 26 | /* 27 | * Class: com_missile_secure_ProxyApplication 28 | * Method: replaceDefaultClassLoader 29 | * Signature: (Ljava/lang/String;I)V 30 | */ 31 | JNIEXPORT void JNICALL Java_com_missile_secure_ProxyApplication_replaceDefaultClassLoader 32 | (JNIEnv *, jobject, jstring, jint); 33 | 34 | /* 35 | * Class: com_missile_secure_ProxyApplication 36 | * Method: originalAppCreate 37 | * Signature: (I)V 38 | */ 39 | JNIEXPORT void JNICALL Java_com_missile_secure_ProxyApplication_originalAppCreate 40 | (JNIEnv *, jobject, jint); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif 46 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/cpp/secure.cpp: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | #include 4 | #include 5 | 6 | #define LOG_TAG "missile_secure_native" 7 | #define LOGOPEN 1 8 | #if(LOGOPEN == 1) 9 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) 10 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 11 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 12 | #else 13 | #define LOGD(...) NULL 14 | #define LOGE(...) NULL 15 | #define LOGI(...) NULL 16 | #endif 17 | 18 | const jbyte DEFAULT_KEY[32] = "8A1ED465A5942AD6"; 19 | 20 | /* Header for class com_missile_secure_ProxyApplication */ 21 | 22 | #ifndef _Included_com_missile_secure_ProxyApplication 23 | #define _Included_com_missile_secure_ProxyApplication 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* 29 | * Class: com_missile_secure_ProxyApplication 30 | * Method: originalAppCreate 31 | * Signature: (I)V 32 | */ 33 | JNIEXPORT void JNICALL Java_com_missile_secure_ProxyApplication_originalAppCreate 34 | (JNIEnv *env, jobject obj, jint sdkVersion) { 35 | 36 | jclass ProxyApplicationClass = env->GetObjectClass(obj); 37 | jmethodID getPackageManagerMethodId = env->GetMethodID(ProxyApplicationClass, 38 | "getPackageManager", 39 | "()Landroid/content/pm/PackageManager;"); 40 | jobject packageManager = env->CallObjectMethod(obj, getPackageManagerMethodId); 41 | jmethodID pmGetApplicationInfoMethodId = env->GetMethodID(env->GetObjectClass(packageManager), 42 | "getApplicationInfo", 43 | "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;"); 44 | jmethodID getPackageNameMethodId = env->GetMethodID(ProxyApplicationClass, "getPackageName", 45 | "()Ljava/lang/String;"); 46 | jobject pmAppInfo = env->CallObjectMethod(packageManager, pmGetApplicationInfoMethodId, 47 | env->CallObjectMethod(obj, getPackageNameMethodId), 48 | 128); 49 | 50 | 51 | jclass PackageItemInfoClass = env->FindClass("android/content/pm/PackageItemInfo"); 52 | jfieldID metaDataField = env->GetFieldID(PackageItemInfoClass, "metaData", 53 | "Landroid/os/Bundle;"); 54 | jobject metaData = env->GetObjectField(pmAppInfo, metaDataField); 55 | 56 | if (metaData == NULL) { 57 | LOGE("未找到Bundle"); 58 | return; 59 | } 60 | 61 | jmethodID bundleGetStringMethodId = env->GetMethodID(env->GetObjectClass(metaData), "getString", 62 | "(Ljava/lang/String;)Ljava/lang/String;"); 63 | 64 | jstring originApplicationName = (jstring) env->CallObjectMethod(metaData, 65 | bundleGetStringMethodId, 66 | env->NewStringUTF( 67 | "APPLICATION_CLASS_NAME")); 68 | if (originApplicationName == NULL) { 69 | LOGE("未找到原始Application Name"); 70 | return; 71 | } 72 | LOGE("原始Application Name : %s", env->GetStringUTFChars(originApplicationName, false)); 73 | 74 | 75 | jclass ActivityThreadClass = env->FindClass("android/app/ActivityThread"); 76 | jmethodID currentActivityThreadMethodId = env->GetStaticMethodID(ActivityThreadClass, 77 | "currentActivityThread", 78 | "()Landroid/app/ActivityThread;"); 79 | jobject activityThread = env->CallStaticObjectMethod(ActivityThreadClass, 80 | currentActivityThreadMethodId); 81 | 82 | 83 | jfieldID mBoundApplicationField = env->GetFieldID(ActivityThreadClass, "mBoundApplication", 84 | "Landroid/app/ActivityThread$AppBindData;"); 85 | jobject mBoundApplication = env->GetObjectField(activityThread, mBoundApplicationField); 86 | 87 | 88 | jfieldID infoField = env->GetFieldID(env->GetObjectClass(mBoundApplication), "info", 89 | "Landroid/app/LoadedApk;"); 90 | jobject info = env->GetObjectField(mBoundApplication, infoField); 91 | 92 | jfieldID mApplicationField = env->GetFieldID(env->GetObjectClass(info), "mApplication", 93 | "Landroid/app/Application;"); 94 | env->SetObjectField(info, mApplicationField, NULL); 95 | 96 | jfieldID mInitialApplicationField = env->GetFieldID(ActivityThreadClass, "mInitialApplication", 97 | "Landroid/app/Application;"); 98 | jobject mInitialApplication = env->GetObjectField(activityThread, mInitialApplicationField); 99 | 100 | 101 | jfieldID mAllApplicationsField = env->GetFieldID(ActivityThreadClass, "mAllApplications", 102 | "Ljava/util/ArrayList;"); 103 | jobject mAllApplications = env->GetObjectField(activityThread, mAllApplicationsField); 104 | jmethodID removeMethodId = env->GetMethodID(env->GetObjectClass(mAllApplications), "remove", 105 | "(Ljava/lang/Object;)Z"); 106 | env->CallBooleanMethod(mAllApplications, removeMethodId, mInitialApplication); 107 | 108 | jfieldID appInfoField = env->GetFieldID(env->GetObjectClass(mBoundApplication), "appInfo", 109 | "Landroid/content/pm/ApplicationInfo;"); 110 | jobject appInfo = env->GetObjectField(mBoundApplication, appInfoField); 111 | 112 | jfieldID mApplicationInfoField = env->GetFieldID(env->GetObjectClass(info), "mApplicationInfo", 113 | "Landroid/content/pm/ApplicationInfo;"); 114 | jobject mApplicationInfo = env->GetObjectField(info, mApplicationInfoField); 115 | 116 | 117 | jfieldID classNameField = env->GetFieldID(env->GetObjectClass(appInfo), "className", 118 | "Ljava/lang/String;"); 119 | env->SetObjectField(appInfo, classNameField, originApplicationName); 120 | env->SetObjectField(mApplicationInfo, classNameField, originApplicationName); 121 | 122 | jmethodID makeApplication = env->GetMethodID(env->GetObjectClass(info), "makeApplication", 123 | "(ZLandroid/app/Instrumentation;)Landroid/app/Application;"); 124 | jobject originalApp = env->CallObjectMethod(info, makeApplication, false, NULL); 125 | env->SetObjectField(activityThread, mInitialApplicationField, originalApp); 126 | 127 | 128 | jfieldID mProviderMapField; 129 | if (sdkVersion < 19) { 130 | mProviderMapField = env->GetFieldID(ActivityThreadClass, "mProviderMap", 131 | "Ljava/util/HashMap;"); 132 | } else { 133 | mProviderMapField = env->GetFieldID(ActivityThreadClass, "mProviderMap", 134 | "Landroid/util/ArrayMap;"); 135 | } 136 | 137 | if (mProviderMapField == NULL) { 138 | LOGE("未找到mProviderMapField"); 139 | return; 140 | } 141 | 142 | jobject mProviderMap = env->GetObjectField(activityThread, mProviderMapField); 143 | jmethodID valuesMethodId = env->GetMethodID(env->GetObjectClass(mProviderMap), "values", 144 | "()Ljava/util/Collection;"); 145 | jobject collections = env->CallObjectMethod(mProviderMap, valuesMethodId); 146 | 147 | jmethodID iterator = env->GetMethodID(env->GetObjectClass(collections), "iterator", 148 | "()Ljava/util/Iterator;"); 149 | 150 | jobject mIterator = env->CallObjectMethod(collections, iterator); 151 | jmethodID hasNext = env->GetMethodID(env->GetObjectClass(mIterator), "hasNext", "()Z"); 152 | jmethodID next = env->GetMethodID(env->GetObjectClass(mIterator), "next", 153 | "()Ljava/lang/Object;"); 154 | while (env->CallBooleanMethod(mIterator, hasNext)) { 155 | jobject providerClientRecord = env->CallObjectMethod(mIterator, next); 156 | if (providerClientRecord == NULL) { 157 | LOGE("providerClientRecord = NULL"); 158 | continue; 159 | } 160 | jclass ProviderClientRecordClass = env->FindClass( 161 | "android/app/ActivityThread$ProviderClientRecord"); 162 | jfieldID mLocalProviderField = env->GetFieldID(ProviderClientRecordClass, "mLocalProvider", 163 | "Landroid/content/ContentProvider;"); 164 | if (mLocalProviderField == NULL) { 165 | LOGE("mLocalProviderField not found"); 166 | continue; 167 | } 168 | jobject mLocalProvider = env->GetObjectField(providerClientRecord, mLocalProviderField); 169 | if (mLocalProvider == NULL) { 170 | LOGE("mLocalProvider is NULL"); 171 | continue; 172 | } 173 | 174 | jfieldID mContextField = env->GetFieldID(env->GetObjectClass(mLocalProvider), "mContext", 175 | "Landroid/content/Context;"); 176 | if (mContextField == NULL) { 177 | LOGE("mContextField not found"); 178 | continue; 179 | } 180 | env->SetObjectField(mLocalProvider, mContextField, originalApp); 181 | } 182 | LOGE("已完成脱壳"); 183 | jmethodID onCreate = env->GetMethodID(env->GetObjectClass(originalApp), "onCreate", "()V"); 184 | env->CallVoidMethod(originalApp, onCreate); 185 | LOGE("壳Application执行完毕"); 186 | } 187 | 188 | 189 | /* 190 | * Class: com_missile_secure_ProxyApplication 191 | * Method: decrypt 192 | * Signature: ()V 193 | */ 194 | JNIEXPORT jbyteArray JNICALL Java_com_missile_secure_ProxyApplication_decrypt 195 | (JNIEnv *env, jobject obj, jbyteArray data) { 196 | /* 197 | int len = env->GetArrayLength(data); 198 | signed char buff[len]; 199 | env->GetByteArrayRegion(data, 0, len, buff); 200 | for (int i = 0; i < len; i++) { 201 | buff[i] = 0xFF ^ buff[i]; 202 | } 203 | jbyteArray result = env->NewByteArray(len); 204 | env->SetByteArrayRegion(result, 0, len, buff); 205 | return result; 206 | */ 207 | 208 | jbyteArray key = env->NewByteArray(32); 209 | env->SetByteArrayRegion(key, 0, 32, DEFAULT_KEY); 210 | 211 | jclass SecureRandom = env->FindClass("java/security/SecureRandom"); 212 | jmethodID secureRandomMethodId = env->GetMethodID(SecureRandom, "", "()V"); 213 | jobject random = env->NewObject(SecureRandom, secureRandomMethodId); 214 | 215 | jclass DESKeySpecClass = env->FindClass("javax/crypto/spec/DESKeySpec"); 216 | jmethodID initDESKeySpecId = env->GetMethodID(DESKeySpecClass, "", "([B)V"); 217 | 218 | jobject desKeySpec = env->NewObject(DESKeySpecClass, initDESKeySpecId, key); 219 | 220 | 221 | jclass SecretKeyFactoryClass = env->FindClass("javax/crypto/SecretKeyFactory"); 222 | jmethodID getFactoryInstanceId = env->GetStaticMethodID(SecretKeyFactoryClass, "getInstance", 223 | "(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;"); 224 | 225 | jobject secretKeyFactory = env->CallStaticObjectMethod(SecretKeyFactoryClass, 226 | getFactoryInstanceId, 227 | env->NewStringUTF("DES")); 228 | 229 | jmethodID generateSecretId = env->GetMethodID(SecretKeyFactoryClass, "generateSecret", 230 | "(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;"); 231 | jobject secretKey = env->CallObjectMethod(secretKeyFactory, generateSecretId, desKeySpec); 232 | 233 | jclass CipherClass = env->FindClass("javax/crypto/Cipher"); 234 | jmethodID getInstanceId = env->GetStaticMethodID(CipherClass, "getInstance", 235 | "(Ljava/lang/String;)Ljavax/crypto/Cipher;"); 236 | jobject cipher = env->CallStaticObjectMethod(CipherClass, getInstanceId, 237 | env->NewStringUTF("DES")); 238 | jmethodID initId = env->GetMethodID(CipherClass, "init", "(ILjava/security/Key;)V"); 239 | env->CallVoidMethod(cipher, initId, 2, secretKey, random); 240 | 241 | jmethodID doFinalId = env->GetMethodID(CipherClass, "doFinal", "([B)[B"); 242 | 243 | if (env->ExceptionCheck()) { 244 | env->ExceptionDescribe(); 245 | env->ExceptionClear(); 246 | env->ThrowNew(env->FindClass("java/lang/Exception"), "DECRYPT ERROR !"); 247 | } 248 | return (jbyteArray) env->CallObjectMethod(cipher, doFinalId, data); 249 | 250 | } 251 | 252 | /* 253 | * Class: com_missile_secure_ProxyApplication 254 | * Method: replaceDefaultClassLoader 255 | * Signature: (Ljava/lang/String;I)V 256 | */ 257 | JNIEXPORT void JNICALL Java_com_missile_secure_ProxyApplication_replaceDefaultClassLoader 258 | (JNIEnv *env, jobject obj, jstring dexPath, jint sdkVersion) { 259 | jclass ActivityThreadClass = env->FindClass("android/app/ActivityThread"); 260 | 261 | jmethodID currentActivityThreadMethodId = env->GetStaticMethodID(ActivityThreadClass, 262 | "currentActivityThread", 263 | "()Landroid/app/ActivityThread;"); 264 | 265 | jobject activityThread = env->CallStaticObjectMethod(ActivityThreadClass, 266 | currentActivityThreadMethodId); 267 | 268 | jmethodID getPackageName = env->GetMethodID(env->GetObjectClass(obj), "getPackageName", 269 | "()Ljava/lang/String;"); 270 | jstring packageName = (jstring) env->CallObjectMethod(obj, getPackageName); 271 | 272 | jfieldID mPackagesField; 273 | if (sdkVersion < 19) { 274 | mPackagesField = env->GetFieldID(ActivityThreadClass, "mPackages", "Ljava/util/HashMap;"); 275 | } else { 276 | mPackagesField = env->GetFieldID(ActivityThreadClass, "mPackages", 277 | "Landroid/util/ArrayMap;"); 278 | } 279 | 280 | jobject mPackages = env->GetObjectField(activityThread, mPackagesField); 281 | 282 | jmethodID arrayMapGet = env->GetMethodID(env->GetObjectClass(mPackages), "get", 283 | "(Ljava/lang/Object;)Ljava/lang/Object;"); 284 | jobject wr = env->CallObjectMethod(mPackages, arrayMapGet, packageName); 285 | 286 | 287 | jmethodID getDir = env->GetMethodID(env->GetObjectClass(obj), "getDir", 288 | "(Ljava/lang/String;I)Ljava/io/File;"); 289 | jstring optimizedDirName = env->NewStringUTF("optimizedDirectory"); 290 | jobject optimizedDirFolder = env->CallObjectMethod(obj, getDir, optimizedDirName, 0); 291 | jmethodID getAbsolutePath = env->GetMethodID(env->GetObjectClass(optimizedDirFolder), 292 | "getAbsolutePath", "()Ljava/lang/String;"); 293 | jstring optimizedDirFolderPath = (jstring) env->CallObjectMethod(optimizedDirFolder, 294 | getAbsolutePath); 295 | 296 | jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(obj), 297 | "getApplicationInfo", 298 | "()Landroid/content/pm/ApplicationInfo;"); 299 | jobject appInfo = env->CallObjectMethod(obj, getApplicationInfo); 300 | jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(appInfo), 301 | "nativeLibraryDir", "Ljava/lang/String;"); 302 | jstring nativeLibraryDir = (jstring) env->GetObjectField(appInfo, nativeLibraryDirField); 303 | 304 | 305 | jmethodID weakReferenceGet = env->GetMethodID(env->GetObjectClass(wr), "get", 306 | "()Ljava/lang/Object;"); 307 | jobject loadedApk = env->CallObjectMethod(wr, weakReferenceGet); 308 | jfieldID mClassLoaderField = env->GetFieldID(env->GetObjectClass(loadedApk), "mClassLoader", 309 | "Ljava/lang/ClassLoader;"); 310 | jobject mClassLoader = env->GetObjectField(loadedApk, mClassLoaderField); 311 | 312 | jclass DexClassLoaderClass = env->FindClass("dalvik/system/DexClassLoader"); 313 | jmethodID initDexClassLoader = env->GetMethodID(DexClassLoaderClass, "", 314 | "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V"); 315 | 316 | jobject dexClassLoader = env->NewObject(DexClassLoaderClass, initDexClassLoader, dexPath, 317 | optimizedDirFolderPath, nativeLibraryDir, mClassLoader); 318 | 319 | env->SetObjectField(loadedApk, mClassLoaderField, dexClassLoader); 320 | } 321 | 322 | 323 | #ifdef __cplusplus 324 | } 325 | #endif 326 | #endif -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/java/com/missile/secure/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_main); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/java/com/missile/secure/ProxyApplication.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.util.ArrayMap; 7 | 8 | import java.io.BufferedInputStream; 9 | import java.io.ByteArrayInputStream; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.DataInputStream; 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.lang.ref.WeakReference; 17 | import java.util.zip.ZipEntry; 18 | import java.util.zip.ZipInputStream; 19 | 20 | import dalvik.system.DexClassLoader; 21 | 22 | 23 | public class ProxyApplication extends Application { 24 | 25 | static { 26 | System.loadLibrary("secure"); 27 | } 28 | 29 | private static final String appkey = "APPLICATION_CLASS_NAME"; 30 | private String apkFileName; 31 | private String odexPath; 32 | private String libPath; 33 | 34 | @Override 35 | protected void attachBaseContext(Context base) { 36 | super.attachBaseContext(base); 37 | try { 38 | File odex = this.getDir("payload_odex", MODE_PRIVATE); 39 | File libs = this.getDir("payload_lib", MODE_PRIVATE); 40 | odexPath = odex.getAbsolutePath(); 41 | libPath = libs.getAbsolutePath(); 42 | 43 | apkFileName = odex.getAbsolutePath() + "/payload.apk"; 44 | File dexFile = new File(apkFileName); 45 | 46 | if (!dexFile.exists()) { 47 | dexFile.createNewFile(); //在payload_odex文件夹内,创建payload.apk 48 | // 读取程序classes.dex文件 49 | byte[] dexdata = readDexFileFromApk(); 50 | 51 | // 分离出解壳后的apk文件已用于动态加载 52 | splitPayLoadFromDex(dexdata); 53 | } 54 | 55 | 56 | replaceDefaultClassLoader(apkFileName, Build.VERSION.SDK_INT); 57 | 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | 64 | @Override 65 | public void onCreate() { 66 | originalAppCreate(Build.VERSION.SDK_INT); 67 | } 68 | 69 | /** 70 | * 从apk包里面获取dex文件内容(byte) 71 | * 72 | * @return 73 | * @throws IOException 74 | */ 75 | private byte[] readDexFileFromApk() throws IOException { 76 | ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream(); 77 | ZipInputStream localZipInputStream = new ZipInputStream( 78 | new BufferedInputStream(new FileInputStream( 79 | this.getApplicationInfo().sourceDir))); 80 | while (true) { 81 | ZipEntry localZipEntry = localZipInputStream.getNextEntry(); 82 | if (localZipEntry == null) { 83 | localZipInputStream.close(); 84 | break; 85 | } 86 | if (localZipEntry.getName().equals("classes.dex")) { 87 | byte[] arrayOfByte = new byte[1024]; 88 | while (true) { 89 | int i = localZipInputStream.read(arrayOfByte); 90 | if (i == -1) 91 | break; 92 | dexByteArrayOutputStream.write(arrayOfByte, 0, i); 93 | } 94 | } 95 | localZipInputStream.closeEntry(); 96 | } 97 | localZipInputStream.close(); 98 | return dexByteArrayOutputStream.toByteArray(); 99 | } 100 | 101 | /** 102 | * 释放被加壳的apk文件,so文件 103 | * 104 | * @param 105 | * @throws IOException 106 | */ 107 | private void splitPayLoadFromDex(byte[] apkdata) throws IOException { 108 | int ablen = apkdata.length; 109 | //取被加壳apk的长度 这里的长度取值,对应加壳时长度的赋值都可以做些简化 110 | byte[] dexlen = new byte[4]; 111 | System.arraycopy(apkdata, ablen - 4, dexlen, 0, 4); 112 | ByteArrayInputStream bais = new ByteArrayInputStream(dexlen); 113 | DataInputStream in = new DataInputStream(bais); 114 | int readInt = in.readInt(); 115 | System.out.println(Integer.toHexString(readInt)); 116 | byte[] newdex = new byte[readInt]; 117 | //把被加壳apk内容拷贝到newdex中 118 | System.arraycopy(apkdata, ablen - 4 - readInt, newdex, 0, readInt); 119 | 120 | //对源程序Apk进行解密 121 | newdex = decrypt(newdex); 122 | 123 | //写入apk文件 124 | File file = new File(apkFileName); 125 | try { 126 | FileOutputStream localFileOutputStream = new FileOutputStream(file); 127 | localFileOutputStream.write(newdex); 128 | localFileOutputStream.close(); 129 | } catch (IOException localIOException) { 130 | throw new RuntimeException(localIOException); 131 | } 132 | 133 | //分析被加壳的apk文件 134 | ZipInputStream localZipInputStream = new ZipInputStream( 135 | new BufferedInputStream(new FileInputStream(file))); 136 | while (true) { 137 | ZipEntry localZipEntry = localZipInputStream.getNextEntry();//不了解这个是否也遍历子目录,看样子应该是遍历的 138 | if (localZipEntry == null) { 139 | localZipInputStream.close(); 140 | break; 141 | } 142 | //取出被加壳apk用到的so文件,放到 libPath中(data/data/包名/payload_lib) 143 | String name = localZipEntry.getName(); 144 | if (name.startsWith("lib/") && name.endsWith(".so")) { 145 | File storeFile = new File(libPath + "/" 146 | + name.substring(name.lastIndexOf('/'))); 147 | storeFile.createNewFile(); 148 | FileOutputStream fos = new FileOutputStream(storeFile); 149 | byte[] arrayOfByte = new byte[1024]; 150 | while (true) { 151 | int i = localZipInputStream.read(arrayOfByte); 152 | if (i == -1) 153 | break; 154 | fos.write(arrayOfByte, 0, i); 155 | } 156 | fos.flush(); 157 | fos.close(); 158 | } 159 | localZipInputStream.closeEntry(); 160 | } 161 | localZipInputStream.close(); 162 | 163 | 164 | } 165 | 166 | private native byte[] decrypt(byte[] data); 167 | 168 | private native void replaceDefaultClassLoader(String dexPath, int sdkVersion); 169 | 170 | private native void originalAppCreate(int sdkVersion); 171 | 172 | } 173 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/layout/activity_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure-jni/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AndroidShell 3 | 4 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidShell/secure-jni/src/test/java/com/missile/secure/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /AndroidShell/secure/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AndroidShell/secure/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | 7 | 8 | defaultConfig { 9 | applicationId "com.missile.secure" 10 | minSdkVersion 19 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | 31 | implementation 'com.android.support:appcompat-v7:28.0.0' 32 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 33 | testImplementation 'junit:junit:4.12' 34 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 35 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 36 | } 37 | -------------------------------------------------------------------------------- /AndroidShell/secure/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/androidTest/java/com/missile/secure/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 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 | * Instrumented 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() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.missile.secure", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/java/com/missile/secure/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_main); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/java/com/missile/secure/ProxyApplication.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import android.app.Application; 4 | import android.app.Instrumentation; 5 | import android.content.Context; 6 | import android.content.pm.ApplicationInfo; 7 | import android.content.pm.PackageManager; 8 | import android.os.Bundle; 9 | import android.util.ArrayMap; 10 | import android.util.Log; 11 | 12 | import java.io.BufferedInputStream; 13 | import java.io.ByteArrayInputStream; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.DataInputStream; 16 | import java.io.File; 17 | import java.io.FileInputStream; 18 | import java.io.FileOutputStream; 19 | import java.io.IOException; 20 | import java.lang.ref.WeakReference; 21 | import java.security.SecureRandom; 22 | import java.sql.Ref; 23 | import java.util.ArrayList; 24 | import java.util.Iterator; 25 | import java.util.zip.ZipEntry; 26 | import java.util.zip.ZipInputStream; 27 | 28 | import javax.crypto.Cipher; 29 | import javax.crypto.SecretKey; 30 | import javax.crypto.SecretKeyFactory; 31 | import javax.crypto.spec.DESKeySpec; 32 | 33 | import dalvik.system.DexClassLoader; 34 | 35 | 36 | public class ProxyApplication extends Application { 37 | 38 | private static final String appkey = "APPLICATION_CLASS_NAME"; 39 | private String apkFileName; 40 | private String odexPath; 41 | private String libPath; 42 | 43 | 44 | /** 45 | * 思路:可以将我们使用的DexClassLoader加载器绑定到系统加载Activity的类加载器上,替换LoadedApk中的mClassLoader 46 | * 如何获取LoadedApk? 需要从ActivityThread入手,在ActivityThread中有一个ArrayMap存放Apk包名和LoadedApk映射关系的数据结构, 47 | * 就从这里入手,使用反射获取LoadedApk中的mClassLoader,然后将它替换成源apk使用的DexClassLoader加载器 48 | * 49 | * @param base 50 | */ 51 | @Override 52 | protected void attachBaseContext(Context base) { 53 | super.attachBaseContext(base); 54 | try { 55 | File odex = this.getDir("payload_odex", MODE_PRIVATE); 56 | File libs = this.getDir("payload_lib", MODE_PRIVATE); 57 | odexPath = odex.getAbsolutePath(); 58 | libPath = libs.getAbsolutePath(); 59 | 60 | apkFileName = odex.getAbsolutePath() + "/payload.apk"; 61 | File dexFile = new File(apkFileName); 62 | 63 | if (!dexFile.exists()) { 64 | dexFile.createNewFile(); //在payload_odex文件夹内,创建payload.apk 65 | // 读取程序classes.dex文件 66 | byte[] dexdata = readDexFileFromApk(); 67 | 68 | // 分离出解壳后的apk文件已用于动态加载 69 | splitPayLoadFromDex(dexdata); 70 | } 71 | 72 | Object currentActivityThread = RefInvoke.invokeStaticMethod( 73 | "android.app.ActivityThread", "currentActivityThread", 74 | new Class[]{}, new Object[]{}); 75 | 76 | String packageName = getPackageName(); 77 | 78 | ArrayMap mPackages = (ArrayMap) RefInvoke.getFieldObject( 79 | "android.app.ActivityThread", currentActivityThread, 80 | "mPackages"); 81 | WeakReference wr = (WeakReference) mPackages.get(packageName); //获取当前的LoadedApk 82 | 83 | //这里,需要注意的是,DexClassLoader的最后一个参数,是DexClassLoader的parent,这里需要设置成PathClassLoader类, 84 | // 因为我们上面虽然说是替换PathClassLoader为DexClassLoader, 85 | // 但是PathClassLoader是系统本身默认的类加载器(也就是mClassLoader变量的值,我们如果单独的将DexClassLoader设置为mClassLoader的值的话,就会出错的), 86 | // 所以一定要讲DexClassLoader的父加载器设置成PathClassLoader,因为类加载器是符合双亲委派机制的。 87 | 88 | 89 | DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath, libPath,/*getClassLoader()*/ 90 | (ClassLoader) RefInvoke.getFieldObject("android.app.LoadedApk", wr.get(), "mClassLoader")); 91 | 92 | //替换ClassLoader 93 | RefInvoke.setFieldObject("android.app.LoadedApk", "mClassLoader", wr.get(), dLoader); 94 | 95 | } catch (Exception e) { 96 | e.printStackTrace(); 97 | } 98 | 99 | } 100 | 101 | 102 | @Override 103 | public void onCreate() { 104 | 105 | String appClassName = null; 106 | 107 | try { 108 | ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); 109 | 110 | Bundle bundle = ai.metaData; 111 | 112 | if (bundle != null && bundle.containsKey(appkey)) { 113 | appClassName = bundle.getString(appkey); 114 | } else { 115 | return; 116 | } 117 | } catch (PackageManager.NameNotFoundException e) { 118 | e.printStackTrace(); 119 | } 120 | 121 | Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", 122 | new Class[]{}, new Object[]{}); 123 | 124 | Object mBoundApplication = RefInvoke.getFieldObject("android.app.ActivityThread", currentActivityThread, 125 | "mBoundApplication"); 126 | 127 | Object loadedApkInfo = RefInvoke.getFieldObject("android.app.ActivityThread$AppBindData", mBoundApplication, 128 | "info"); 129 | //把当前进程的mApplication 设置成了null 130 | RefInvoke.setFieldObject("android.app.LoadedApk", "mApplication", loadedApkInfo, null); 131 | Object oldApplication = RefInvoke.getFieldObject( 132 | "android.app.ActivityThread", currentActivityThread, 133 | "mInitialApplication"); 134 | 135 | ArrayList mAllApplications = (ArrayList) RefInvoke 136 | .getFieldObject("android.app.ActivityThread", 137 | currentActivityThread, "mAllApplications"); 138 | mAllApplications.remove(oldApplication);//删除oldApplication 139 | 140 | ApplicationInfo appinfo_In_LoadedApk = (ApplicationInfo) RefInvoke 141 | .getFieldObject("android.app.LoadedApk", loadedApkInfo, 142 | "mApplicationInfo"); 143 | ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo) RefInvoke 144 | .getFieldObject("android.app.ActivityThread$AppBindData", 145 | mBoundApplication, "appInfo"); 146 | appinfo_In_LoadedApk.className = appClassName; 147 | appinfo_In_AppBindData.className = appClassName; 148 | Application app = (Application) RefInvoke.invokeMethod( 149 | "android.app.LoadedApk", "makeApplication", loadedApkInfo, 150 | new Class[]{boolean.class, Instrumentation.class}, 151 | new Object[]{false, null});//执行 makeApplication(false,null) 152 | RefInvoke.setFieldObject("android.app.ActivityThread", 153 | "mInitialApplication", currentActivityThread, app); 154 | 155 | 156 | ArrayMap mProviderMap = (ArrayMap) RefInvoke.getFieldObject( 157 | "android.app.ActivityThread", currentActivityThread, 158 | "mProviderMap"); 159 | Iterator it = mProviderMap.values().iterator(); 160 | while (it.hasNext()) { 161 | Object providerClientRecord = it.next(); 162 | Object localProvider = RefInvoke.getFieldObject( 163 | "android.app.ActivityThread$ProviderClientRecord", 164 | providerClientRecord, "mLocalProvider"); 165 | RefInvoke.setFieldObject("android.content.ContentProvider", 166 | "mContext", localProvider, app); 167 | } 168 | 169 | app.onCreate(); 170 | 171 | } 172 | 173 | /** 174 | * 从apk包里面获取dex文件内容(byte) 175 | * 176 | * @return 177 | * @throws IOException 178 | */ 179 | private byte[] readDexFileFromApk() throws IOException { 180 | ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream(); 181 | ZipInputStream localZipInputStream = new ZipInputStream( 182 | new BufferedInputStream(new FileInputStream( 183 | this.getApplicationInfo().sourceDir))); 184 | while (true) { 185 | ZipEntry localZipEntry = localZipInputStream.getNextEntry(); 186 | if (localZipEntry == null) { 187 | localZipInputStream.close(); 188 | break; 189 | } 190 | if (localZipEntry.getName().equals("classes.dex")) { 191 | byte[] arrayOfByte = new byte[1024]; 192 | while (true) { 193 | int i = localZipInputStream.read(arrayOfByte); 194 | if (i == -1) 195 | break; 196 | dexByteArrayOutputStream.write(arrayOfByte, 0, i); 197 | } 198 | } 199 | localZipInputStream.closeEntry(); 200 | } 201 | localZipInputStream.close(); 202 | return dexByteArrayOutputStream.toByteArray(); 203 | } 204 | 205 | /** 206 | * 释放被加壳的apk文件,so文件 207 | * 208 | * @param 209 | * @throws IOException 210 | */ 211 | private void splitPayLoadFromDex(byte[] apkdata) throws IOException { 212 | int ablen = apkdata.length; 213 | //取被加壳apk的长度 这里的长度取值,对应加壳时长度的赋值都可以做些简化 214 | byte[] dexlen = new byte[4]; 215 | System.arraycopy(apkdata, ablen - 4, dexlen, 0, 4); 216 | ByteArrayInputStream bais = new ByteArrayInputStream(dexlen); 217 | DataInputStream in = new DataInputStream(bais); 218 | int readInt = in.readInt(); 219 | System.out.println(Integer.toHexString(readInt)); 220 | byte[] newdex = new byte[readInt]; 221 | //把被加壳apk内容拷贝到newdex中 222 | System.arraycopy(apkdata, ablen - 4 - readInt, newdex, 0, readInt); 223 | //这里应该加上对于apk的解密操作,若加壳是加密处理的话 224 | //? 225 | 226 | //对源程序Apk进行解密 227 | newdex = decrypt(newdex); 228 | 229 | //写入apk文件 230 | File file = new File(apkFileName); 231 | try { 232 | FileOutputStream localFileOutputStream = new FileOutputStream(file); 233 | localFileOutputStream.write(newdex); 234 | localFileOutputStream.close(); 235 | } catch (IOException localIOException) { 236 | throw new RuntimeException(localIOException); 237 | } 238 | 239 | //分析被加壳的apk文件 240 | ZipInputStream localZipInputStream = new ZipInputStream( 241 | new BufferedInputStream(new FileInputStream(file))); 242 | while (true) { 243 | ZipEntry localZipEntry = localZipInputStream.getNextEntry();//不了解这个是否也遍历子目录,看样子应该是遍历的 244 | if (localZipEntry == null) { 245 | localZipInputStream.close(); 246 | break; 247 | } 248 | //取出被加壳apk用到的so文件,放到 libPath中(data/data/包名/payload_lib) 249 | String name = localZipEntry.getName(); 250 | if (name.startsWith("lib/") && name.endsWith(".so")) { 251 | File storeFile = new File(libPath + "/" 252 | + name.substring(name.lastIndexOf('/'))); 253 | storeFile.createNewFile(); 254 | FileOutputStream fos = new FileOutputStream(storeFile); 255 | byte[] arrayOfByte = new byte[1024]; 256 | while (true) { 257 | int i = localZipInputStream.read(arrayOfByte); 258 | if (i == -1) 259 | break; 260 | fos.write(arrayOfByte, 0, i); 261 | } 262 | fos.flush(); 263 | fos.close(); 264 | } 265 | localZipInputStream.closeEntry(); 266 | } 267 | localZipInputStream.close(); 268 | 269 | 270 | } 271 | 272 | /* private byte[] decrypt(byte[] srcdata) { 273 | for (int i = 0; i < srcdata.length; i++) { 274 | srcdata[i] = (byte) (0xFF ^ srcdata[i]); 275 | } 276 | return srcdata; 277 | }*/ 278 | 279 | 280 | private static byte[] decrypt(byte[] src) { 281 | try { 282 | String key = "8A1ED465A5942AD6"; 283 | // DES算法要求有一个可信任的随机数源 284 | SecureRandom random = new SecureRandom(); 285 | // 创建一个DESKeySpec对象 286 | DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); 287 | // 创建一个密匙工厂 288 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 289 | // 将DESKeySpec对象转换成SecretKey对象 290 | SecretKey secretkey = keyFactory.generateSecret(desKeySpec); 291 | // Cipher对象实际完成解密操作 292 | Cipher cipher = Cipher.getInstance("DES"); 293 | // 用密匙初始化Cipher对象 294 | cipher.init(Cipher.DECRYPT_MODE, secretkey, random); 295 | // 真正开始解密操作 296 | return cipher.doFinal(src); 297 | } catch (Exception e) { 298 | e.printStackTrace(); 299 | } 300 | return null; 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/java/com/missile/secure/RefInvoke.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | 7 | public class RefInvoke { 8 | public static Object invokeStaticMethod(String className, String methodName, Class[] paramTypes, Object[] paramValues) { 9 | try { 10 | Class clazz = Class.forName(className); 11 | Method method = clazz.getMethod(methodName, paramTypes); 12 | return method.invoke(null, paramValues); 13 | } catch (ClassNotFoundException e) { 14 | e.printStackTrace(); 15 | } catch (NoSuchMethodException e) { 16 | e.printStackTrace(); 17 | } catch (IllegalAccessException e) { 18 | e.printStackTrace(); 19 | } catch (InvocationTargetException e) { 20 | e.printStackTrace(); 21 | } 22 | 23 | return null; 24 | } 25 | 26 | 27 | public static Object invokeMethod(String className, String methodName, Object obj, Class[] paramTypes, Object[] paramValues) { 28 | try { 29 | Class clazz = Class.forName(className); 30 | Method method = clazz.getMethod(methodName,paramTypes); 31 | return method.invoke(obj,paramValues); 32 | } catch (ClassNotFoundException e) { 33 | e.printStackTrace(); 34 | } catch (NoSuchMethodException e) { 35 | e.printStackTrace(); 36 | } catch (IllegalAccessException e) { 37 | e.printStackTrace(); 38 | } catch (InvocationTargetException e) { 39 | e.printStackTrace(); 40 | } 41 | return null; 42 | 43 | } 44 | 45 | public static Object getFieldObject(String className, Object obj, String fieldName) { 46 | 47 | try { 48 | Class clazz = Class.forName(className); 49 | Field field = clazz.getDeclaredField(fieldName); 50 | field.setAccessible(true); 51 | return field.get(obj); 52 | } catch (ClassNotFoundException e) { 53 | e.printStackTrace(); 54 | } catch (NoSuchFieldException e) { 55 | e.printStackTrace(); 56 | } catch (IllegalAccessException e) { 57 | e.printStackTrace(); 58 | } 59 | 60 | return null; 61 | 62 | } 63 | 64 | 65 | public static void setFieldObject(String className, String fieldName, Object obj, Object fieldValue) { 66 | try { 67 | Class clazz = Class.forName(className); 68 | Field field = clazz.getDeclaredField(fieldName); 69 | field.setAccessible(true); 70 | field.set(obj, fieldValue); 71 | } catch (ClassNotFoundException e) { 72 | e.printStackTrace(); 73 | } catch (NoSuchFieldException e) { 74 | e.printStackTrace(); 75 | } catch (IllegalAccessException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/layout/activity_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShell/secure/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AndroidShell 3 | 4 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidShell/secure/src/test/java/com/missile/secure/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.missile.secure; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /AndroidShell/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':secure', ':secure-jni' 2 | -------------------------------------------------------------------------------- /AndroidShellTools/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | /.idea/libraries 3 | /.idea/modules.xml 4 | /.idea/workspace.xml 5 | /out -------------------------------------------------------------------------------- /AndroidShellTools/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /AndroidShellTools/.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple Java application that includes a class with main() method -------------------------------------------------------------------------------- /AndroidShellTools/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AndroidShellTools/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AndroidShellTools/.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /AndroidShellTools/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AndroidShellTools/force/classes.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShellTools/force/classes.dex -------------------------------------------------------------------------------- /AndroidShellTools/force/demo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShellTools/force/demo.apk -------------------------------------------------------------------------------- /AndroidShellTools/force/shell.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/AndroidShellTools/force/shell.dex -------------------------------------------------------------------------------- /AndroidShellTools/src/DexShellTool.java: -------------------------------------------------------------------------------- 1 | import javax.crypto.Cipher; 2 | import javax.crypto.SecretKey; 3 | import javax.crypto.SecretKeyFactory; 4 | import javax.crypto.spec.DESKeySpec; 5 | import java.io.*; 6 | import java.security.MessageDigest; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.security.SecureRandom; 9 | import java.util.zip.Adler32; 10 | 11 | public class DexShellTool { 12 | 13 | public static void main(String[] args) { 14 | System.out.println("Hello World!"); 15 | try { 16 | File payloadSrcFile = new File("force/demo.apk"); 17 | File unShellDexFile = new File("force/shell.dex"); 18 | byte[] payloadArray = encrpt(readFileBytes(payloadSrcFile), "8A1ED465A5942AD6"); 19 | byte[] unShellDexArray = readFileBytes(unShellDexFile); 20 | 21 | int payloadLen = payloadArray.length; 22 | int unShellDexLen = unShellDexArray.length; 23 | 24 | int totalLen = payloadLen + unShellDexLen + 4; 25 | 26 | byte[] newDex = new byte[totalLen]; 27 | 28 | 29 | System.arraycopy(unShellDexArray, 0, newDex, 0, unShellDexLen); 30 | System.arraycopy(payloadArray, 0, newDex, unShellDexLen, payloadLen); 31 | System.arraycopy(intToByte(payloadLen), 0, newDex, totalLen - 4, 4); 32 | 33 | 34 | fixFileSizeHeader(newDex); 35 | fixSHA1Header(newDex); 36 | fixCheckSumHeader(newDex); 37 | 38 | 39 | String str = "force/classes.dex"; 40 | File file = new File(str); 41 | if (!file.exists()) { 42 | file.createNewFile(); 43 | } 44 | 45 | 46 | FileOutputStream localFileOutputStream = new FileOutputStream(str); 47 | localFileOutputStream.write(newDex); 48 | localFileOutputStream.flush(); 49 | localFileOutputStream.close(); 50 | 51 | 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } 55 | 56 | 57 | } 58 | 59 | 60 | /** 61 | * 修改dex头,CheckSum 校验码 62 | * 63 | * @param dexBytes 64 | */ 65 | private static void fixCheckSumHeader(byte[] dexBytes) { 66 | Adler32 adler = new Adler32(); 67 | adler.update(dexBytes, 12, dexBytes.length - 12);//从12到文件末尾计算校验码 68 | long value = adler.getValue(); 69 | int va = (int) value; 70 | byte[] newcs = intToByte(va); 71 | //高位在前,低位在前掉个个 72 | byte[] recs = new byte[4]; 73 | for (int i = 0; i < 4; i++) { 74 | recs[i] = newcs[newcs.length - 1 - i]; 75 | System.out.println(Integer.toHexString(newcs[i])); 76 | } 77 | System.arraycopy(recs, 0, dexBytes, 8, 4);//效验码赋值(8-11) 78 | System.out.println(Long.toHexString(value)); 79 | System.out.println(); 80 | } 81 | 82 | /** 83 | * 修改dex头 sha1值 84 | * 85 | * @param dexBytes 86 | * @throws NoSuchAlgorithmException 87 | */ 88 | private static void fixSHA1Header(byte[] dexBytes) 89 | throws NoSuchAlgorithmException { 90 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 91 | md.update(dexBytes, 32, dexBytes.length - 32);//从32为到结束计算sha--1 92 | byte[] newdt = md.digest(); 93 | System.arraycopy(newdt, 0, dexBytes, 12, 20);//修改sha-1值(12-31) 94 | //输出sha-1值,可有可无 95 | String hexstr = ""; 96 | for (int i = 0; i < newdt.length; i++) { 97 | hexstr += Integer.toString((newdt[i] & 0xff) + 0x100, 16) 98 | .substring(1); 99 | } 100 | System.out.println(hexstr); 101 | } 102 | 103 | /** 104 | * 修改dex头 file_size值 105 | * 106 | * @param dexBytes 107 | */ 108 | private static void fixFileSizeHeader(byte[] dexBytes) { 109 | //新文件长度 110 | byte[] newfs = intToByte(dexBytes.length); 111 | System.out.println(Integer.toHexString(dexBytes.length)); 112 | byte[] refs = new byte[4]; 113 | //高位在前,低位在前掉个个 114 | for (int i = 0; i < 4; i++) { 115 | refs[i] = newfs[newfs.length - 1 - i]; 116 | System.out.println(Integer.toHexString(newfs[i])); 117 | } 118 | System.arraycopy(refs, 0, dexBytes, 32, 4);//修改(32-35) 119 | } 120 | 121 | /* 122 | private static byte[] encrpt(byte[] srcdata) { 123 | for (int i = 0; i < srcdata.length; i++) { 124 | srcdata[i] = (byte) (0xFF ^ srcdata[i]); 125 | } 126 | return srcdata; 127 | }*/ 128 | 129 | 130 | private static byte[] encrpt(byte[] srcData, String key) { 131 | 132 | try { 133 | SecureRandom random = new SecureRandom(); 134 | DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); 135 | SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); 136 | SecretKey secretKey = factory.generateSecret(desKeySpec); 137 | 138 | Cipher cipher = Cipher.getInstance("DES"); 139 | cipher.init(Cipher.ENCRYPT_MODE, secretKey, random); 140 | return cipher.doFinal(srcData); 141 | 142 | } catch (Exception e) { 143 | e.printStackTrace(); 144 | } 145 | 146 | 147 | return null; 148 | } 149 | 150 | 151 | 152 | 153 | 154 | 155 | private static byte[] readFileBytes(File file) throws IOException { 156 | byte[] arrayOfByte = new byte[1024]; 157 | ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream(); 158 | FileInputStream fis = new FileInputStream(file); 159 | while (true) { 160 | int i = fis.read(arrayOfByte); 161 | if (i != -1) { 162 | localByteArrayOutputStream.write(arrayOfByte, 0, i); 163 | } else { 164 | return localByteArrayOutputStream.toByteArray(); 165 | } 166 | } 167 | } 168 | 169 | /** 170 | * int 转byte[] 171 | * 172 | * @param number 173 | * @return 174 | */ 175 | public static byte[] intToByte(int number) { 176 | byte[] b = new byte[4]; 177 | for (int i = 3; i >= 0; i--) { 178 | b[i] = (byte) (number % 256); 179 | number >>= 8; 180 | } 181 | return b; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AppShell 2 | 利用动态加载技术实现APK加壳 3 | 4 | ## Apk加壳原理 5 | [Apk加壳原理及用法](https://blog.csdn.net/jiangwei0910410003/article/details/48415225) 参考这篇博客 6 | 7 | ## 说明 8 | 9 | ### AndroidShell 是一个Android Studio项目工程,其中包含了app,secure,secure-jni三个module. 10 | app -- 源APP,即待加壳的apk (demo.apk)
11 | secure -- 壳APP, 使用java实现加壳的过程.(shell.apk)
12 | secure-jni -- 壳APP,使用**JNI**实现加壳的过程.(shell.apk) 13 | 14 | ### AndroidShellTools 一个对apk加密并将apk与dex合并的工具 15 | 主要功能是加密demo.apk,然后将加密后的demo.apk数据与shell.dex数据合并为classes.dex,修改classes.dex文件的头部,并添加apk文件的大小至尾部。 16 | 17 | ### Tools 用于对apk进行签名的工具 18 | 主要功能是对payload.apk签名,生成签名后的payload-release.apk 19 | 20 | #### apk签名指令介绍 21 | 22 | jarsigner -verbose -keystore 你的签名文件 -storepass 密码 -keypass alias的密码 -sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar 签名后的文件 签名前的apk 签名文件的alias名称 23 | 24 | eg: 25 | 26 | jarsigner -verbose -keystore secure.jks -storepass androidsecure -keypass androidsecure -sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar payload-release.apk payload.apk secure 27 | 28 | 签名文件的密码:androidsecure
29 | alais的密码:androidsecure 30 | -------------------------------------------------------------------------------- /Tools/README.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/Tools/README.txt -------------------------------------------------------------------------------- /Tools/payload-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/Tools/payload-release.apk -------------------------------------------------------------------------------- /Tools/payload.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/Tools/payload.apk -------------------------------------------------------------------------------- /Tools/secure.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowee/AppShell/c4e0365afab5497a575b10f5b71c007969a442cd/Tools/secure.jks -------------------------------------------------------------------------------- /Tools/sign.bat: -------------------------------------------------------------------------------- 1 | jarsigner -verbose -keystore secure.jks -storepass androidsecure -keypass androidsecure -sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar payload-release.apk payload.apk secure --------------------------------------------------------------------------------