├── 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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
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 |
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 |
--------------------------------------------------------------------------------
/AndroidShell/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
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 |
8 |
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
--------------------------------------------------------------------------------