keys = mPackages.keySet();
73 | for(String k : keys){
74 | LogUtils.d("key : "+k);
75 | }
76 |
77 | LogUtils.d("current package name : "+getPackageName());
78 | WeakReference wr = mPackages.get(getPackageName());
79 | if(wr==null){
80 | LogUtils.d("WeakReference is null");
81 | }else{
82 | Object loadedApk = wr.get();
83 | if(loadedApk!=null){
84 | LogUtils.d("loadedApk is not null");
85 | }else{
86 | LogUtils.d("loadedApk is null");
87 | }
88 | }
89 | } catch (ClassNotFoundException e) {
90 | e.printStackTrace();
91 | } catch (NoSuchMethodException e) {
92 | e.printStackTrace();
93 | } catch (InvocationTargetException e) {
94 | e.printStackTrace();
95 | } catch (IllegalAccessException e) {
96 | e.printStackTrace();
97 | } catch (NoSuchFieldException e) {
98 | e.printStackTrace();
99 | }
100 | }
101 |
102 | public void generateNewWeakReference(View view) {
103 | if(abc==null){
104 | abc=new Object();
105 | }
106 | testWr = new WeakReference(abc);
107 | }
108 |
109 | public void showWeakReference(View view) {
110 | if(testWr==null){
111 | LogUtils.d("wr is null");
112 | }else{
113 | Object obj = testWr.get();
114 | if(obj==null){
115 | LogUtils.d("obj = null");
116 | }else{
117 | LogUtils.d("obj is "+obj.toString());
118 | }
119 | }
120 | }
121 |
122 | public void removeStrongReference(View view) {
123 | abc=null;
124 | }
125 |
126 | public void useContentProvider(View view) {
127 | ContentValues cv = new ContentValues();
128 | cv.put("aa","bb");
129 | ContentResolver cr = getContentResolver();
130 | String authority = "content://dev.mars";
131 | Uri uri = Uri.parse(authority);
132 | cr.insert(uri,cv);
133 | }
134 |
135 | public void useService(View view) {
136 | Intent intent = new Intent(MainActivity.this,MyService.class);
137 | startService(intent);
138 | }
139 |
140 | public void sendBroadCast(View view) {
141 | Intent broadcastIntent = new Intent("dev_mars_broadcast_test");
142 | sendBroadcast(broadcastIntent);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/java/dev/mars/testapplication/MyApplication.java:
--------------------------------------------------------------------------------
1 | package dev.mars.testapplication;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.support.multidex.MultiDex;
6 |
7 | import java.io.OutputStream;
8 | import java.io.PrintWriter;
9 | import java.lang.reflect.InvocationTargetException;
10 | import java.lang.reflect.Method;
11 |
12 |
13 | /**
14 | * Created by ma.xuanwei on 2017/5/11.
15 | */
16 |
17 | public class MyApplication extends Application {
18 | //public static Methods methods = new Methods();
19 | // public static Methods2 methods2=new Methods2();
20 | static {
21 | System.loadLibrary("reflect");
22 | test();
23 | }
24 |
25 | private static native void test();
26 |
27 | /*static {
28 | try {
29 | Class methods2Class = Class.forName("dev.mars.testapplication.Methods2");
30 | Method l = methods2Class.getDeclaredMethod("l");
31 | l.invoke(methods2Class.newInstance());
32 | } catch (Exception e){
33 | e.printStackTrace();
34 | }
35 | }*/
36 |
37 |
38 | @Override
39 | protected void attachBaseContext(Context base) {
40 | super.attachBaseContext(base);
41 | LogUtils.d(getClass().getCanonicalName()+" attachBaseContext");
42 | // methods2.l();
43 | MultiDex.install(this);
44 | }
45 |
46 | @Override
47 | public void onCreate() {
48 | super.onCreate();
49 | LogUtils.d(this.getClass().getName()+" onCreate");
50 | instance = this;
51 | }
52 |
53 | private static MyApplication instance;
54 |
55 | public static MyApplication getInstance(){
56 | return instance;
57 | }
58 |
59 | public static void exit(){
60 | instance=null;
61 | }
62 |
63 | private static final String TEST_WORD = "A field from "+MyApplication.class.getName();
64 |
65 | public void test(String str){
66 | LogUtils.d(str+" : "+TEST_WORD);
67 | }
68 | }
69 |
70 |
71 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/java/dev/mars/testapplication/MyBroadCastReceiver.java:
--------------------------------------------------------------------------------
1 | package dev.mars.testapplication;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Handler;
7 |
8 | /**
9 | * Created by ma.xuanwei on 2017/5/11.
10 | */
11 |
12 | public class MyBroadCastReceiver extends BroadcastReceiver{
13 |
14 | /**
15 | * This method is called when the BroadcastReceiver is receiving an Intent
16 | * broadcast. During this time you can use the other methods on
17 | * BroadcastReceiver to view/modify the current result values. This method
18 | * is always called within the main thread of its process, unless you
19 | * explicitly asked for it to be scheduled on a different thread using
20 | * {@link Context#registerReceiver(BroadcastReceiver,
21 | * IntentFilter, String, Handler)}. When it runs on the main
22 | * thread you should
23 | * never perform long-running operations in it (there is a timeout of
24 | * 10 seconds that the system allows before considering the receiver to
25 | * be blocked and a candidate to be killed). You cannot launch a popup dialog
26 | * in your implementation of onReceive().
27 | *
28 | *
If this BroadcastReceiver was launched through a <receiver> tag,
29 | * then the object is no longer alive after returning from this
30 | * function. This means you should not perform any operations that
31 | * return a result to you asynchronously -- in particular, for interacting
32 | * with services, you should use
33 | * {@link Context#startService(Intent)} instead of
34 | * {@link Context#bindService(Intent, ServiceConnection, int)}. If you wish
35 | * to interact with a service that is already running, you can use
36 | * {@link #peekService}.
37 | *
38 | *
The Intent filters used in {@link Context#registerReceiver}
39 | * and in application manifests are not guaranteed to be exclusive. They
40 | * are hints to the operating system about how to find suitable recipients. It is
41 | * possible for senders to force delivery to specific recipients, bypassing filter
42 | * resolution. For this reason, {@link #onReceive(Context, Intent) onReceive()}
43 | * implementations should respond only to known actions, ignoring any unexpected
44 | * Intents that they may receive.
45 | *
46 | * @param context The Context in which the receiver is running.
47 | * @param intent The Intent being received.
48 | */
49 | @Override
50 | public void onReceive(Context context, Intent intent) {
51 | LogUtils.d(MyBroadCastReceiver.class.getName()+" onReceive");
52 |
53 | MyApplication.getInstance().test(this.getClass().getName());
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/java/dev/mars/testapplication/MyContentProvider.java:
--------------------------------------------------------------------------------
1 | package dev.mars.testapplication;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.database.ContentObserver;
6 | import android.database.Cursor;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 | import android.net.Uri;
9 | import android.support.annotation.Nullable;
10 |
11 | /**
12 | * Created by ma.xuanwei on 2017/5/11.
13 | */
14 |
15 | public class MyContentProvider extends ContentProvider {
16 | /**
17 | * Implement this to initialize your content provider on startup.
18 | * This method is called for all registered content providers on the
19 | * application main thread at application launch time. It must not perform
20 | * lengthy operations, or application startup will be delayed.
21 | *
22 | *
You should defer nontrivial initialization (such as opening,
23 | * upgrading, and scanning databases) until the content provider is used
24 | * (via {@link #query}, {@link #insert}, etc). Deferred initialization
25 | * keeps application startup fast, avoids unnecessary work if the provider
26 | * turns out not to be needed, and stops database errors (such as a full
27 | * disk) from halting application launch.
28 | *
29 | *
If you use SQLite, {@link SQLiteOpenHelper}
30 | * is a helpful utility class that makes it easy to manage databases,
31 | * and will automatically defer opening until first use. If you do use
32 | * SQLiteOpenHelper, make sure to avoid calling
33 | * {@link SQLiteOpenHelper#getReadableDatabase} or
34 | * {@link SQLiteOpenHelper#getWritableDatabase}
35 | * from this method. (Instead, override
36 | * {@link SQLiteOpenHelper#onOpen} to initialize the
37 | * database when it is first opened.)
38 | *
39 | * @return true if the provider was successfully loaded, false otherwise
40 | */
41 | @Override
42 | public boolean onCreate() {
43 | LogUtils.d(MyContentProvider.class.getName()+" onCreate");
44 | //Application此时还没有创建
45 | //MyApplication.getInstance().test("MyContentProvider");
46 | return false;
47 | }
48 |
49 | /**
50 | * Implement this to handle query requests from clients.
51 | * This method can be called from multiple threads, as described in
52 | * Processes
53 | * and Threads .
54 | *
55 | * Example client call:
56 | *
// Request a specific record.
57 | * Cursor managedCursor = managedQuery(
58 | * ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
59 | * projection, // Which columns to return.
60 | * null, // WHERE clause.
61 | * null, // WHERE clause value substitution
62 | * People.NAME + " ASC"); // Sort order.
63 | * Example implementation:
64 | *
// SQLiteQueryBuilder is a helper class that creates the
65 | * // proper SQL syntax for us.
66 | * SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
67 | *
68 | * // Set the table we're querying.
69 | * qBuilder.setTables(DATABASE_TABLE_NAME);
70 | *
71 | * // If the query ends in a specific record number, we're
72 | * // being asked for a specific record, so set the
73 | * // WHERE clause in our query.
74 | * if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
75 | * qBuilder.appendWhere("_id=" + uri.getPathLeafId());
76 | * }
77 | *
78 | * // Make the query.
79 | * Cursor c = qBuilder.query(mDb,
80 | * projection,
81 | * selection,
82 | * selectionArgs,
83 | * groupBy,
84 | * having,
85 | * sortOrder);
86 | * c.setNotificationUri(getContext().getContentResolver(), uri);
87 | * return c;
88 | *
89 | * @param uri The URI to query. This will be the full URI sent by the client;
90 | * if the client is requesting a specific record, the URI will end in a record number
91 | * that the implementation should parse and add to a WHERE or HAVING clause, specifying
92 | * that _id value.
93 | * @param projection The list of columns to put into the cursor. If
94 | * {@code null} all columns are included.
95 | * @param selection A selection criteria to apply when filtering rows.
96 | * If {@code null} then all rows are included.
97 | * @param selectionArgs You may include ?s in selection, which will be replaced by
98 | * the values from selectionArgs, in order that they appear in the selection.
99 | * The values will be bound as Strings.
100 | * @param sortOrder How the rows in the cursor should be sorted.
101 | * If {@code null} then the provider is free to define the sort order.
102 | * @return a Cursor or {@code null}.
103 | */
104 | @Nullable
105 | @Override
106 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
107 | return null;
108 | }
109 |
110 | /**
111 | * Implement this to handle requests for the MIME type of the data at the
112 | * given URI. The returned MIME type should start with
113 | * vnd.android.cursor.item
for a single record,
114 | * or vnd.android.cursor.dir/
for multiple items.
115 | * This method can be called from multiple threads, as described in
116 | * Processes
117 | * and Threads .
118 | *
119 | *
Note that there are no permissions needed for an application to
120 | * access this information; if your content provider requires read and/or
121 | * write permissions, or is not exported, all applications can still call
122 | * this method regardless of their access permissions. This allows them
123 | * to retrieve the MIME type for a URI when dispatching intents.
124 | *
125 | * @param uri the URI to query.
126 | * @return a MIME type string, or {@code null} if there is no type.
127 | */
128 | @Nullable
129 | @Override
130 | public String getType(Uri uri) {
131 | return null;
132 | }
133 |
134 | /**
135 | * Implement this to handle requests to insert a new row.
136 | * As a courtesy, call {@link ContentResolver#notifyChange(Uri, ContentObserver) notifyChange()}
137 | * after inserting.
138 | * This method can be called from multiple threads, as described in
139 | * Processes
140 | * and Threads .
141 | *
142 | * @param uri The content:// URI of the insertion request. This must not be {@code null}.
143 | * @param values A set of column_name/value pairs to add to the database.
144 | * This must not be {@code null}.
145 | * @return The URI for the newly inserted item.
146 | */
147 | @Nullable
148 | @Override
149 | public Uri insert(Uri uri, ContentValues values) {
150 | return null;
151 | }
152 |
153 | /**
154 | * Implement this to handle requests to delete one or more rows.
155 | * The implementation should apply the selection clause when performing
156 | * deletion, allowing the operation to affect multiple rows in a directory.
157 | * As a courtesy, call {@link ContentResolver#notifyChange(Uri, ContentObserver) notifyChange()}
158 | * after deleting.
159 | * This method can be called from multiple threads, as described in
160 | * Processes
161 | * and Threads .
162 | *
163 | *
The implementation is responsible for parsing out a row ID at the end
164 | * of the URI, if a specific row is being deleted. That is, the client would
165 | * pass in content://contacts/people/22
and the implementation is
166 | * responsible for parsing the record number (22) when creating a SQL statement.
167 | *
168 | * @param uri The full URI to query, including a row ID (if a specific record is requested).
169 | * @param selection An optional restriction to apply to rows when deleting.
170 | * @param selectionArgs
171 | * @return The number of rows affected.
172 | * @throws SQLException
173 | */
174 | @Override
175 | public int delete(Uri uri, String selection, String[] selectionArgs) {
176 | return 0;
177 | }
178 |
179 | /**
180 | * Implement this to handle requests to update one or more rows.
181 | * The implementation should update all rows matching the selection
182 | * to set the columns according to the provided values map.
183 | * As a courtesy, call {@link ContentResolver#notifyChange(Uri, ContentObserver) notifyChange()}
184 | * after updating.
185 | * This method can be called from multiple threads, as described in
186 | * Processes
187 | * and Threads .
188 | *
189 | * @param uri The URI to query. This can potentially have a record ID if this
190 | * is an update request for a specific record.
191 | * @param values A set of column_name/value pairs to update in the database.
192 | * This must not be {@code null}.
193 | * @param selection An optional filter to match rows to update.
194 | * @param selectionArgs
195 | * @return the number of rows affected.
196 | */
197 | @Override
198 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
199 | return 0;
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/java/dev/mars/testapplication/MyService.java:
--------------------------------------------------------------------------------
1 | package dev.mars.testapplication;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 |
7 | public class MyService extends Service {
8 | public MyService() {
9 | }
10 |
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | LogUtils.d(MyService.class.getName()+" onCreate");
15 | ((MyApplication)getApplication()).test(this.getClass().getName());
16 | }
17 |
18 | @Override
19 | public int onStartCommand(Intent intent, int flags, int startId) {
20 | return super.onStartCommand(intent, flags, startId);
21 | }
22 |
23 | @Override
24 | public IBinder onBind(Intent intent) {
25 | // TODO: Return the communication channel to the service.
26 | throw new UnsupportedOperationException("Not yet implemented");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/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 | reflect
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 | reflect.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 | reflect
42 |
43 | # Links the target library to the log library
44 | # included in the NDK.
45 | ${log-lib} )
46 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/jni/reflect.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 |
6 | extern "C" {
7 | JNIEXPORT void JNICALL
8 | Java_dev_mars_testapplication_MyApplication_test(JNIEnv *env, jobject instance) {
9 |
10 | // TODO
11 | jclass Methods2Class = env->FindClass("dev/mars/testapplication/Methods2");
12 | if(Methods2Class!=NULL){
13 | __android_log_print(ANDROID_LOG_DEBUG,"dev_mars_native","找到dev/mars/testapplication/Methods2");
14 | }else{
15 | __android_log_print(ANDROID_LOG_DEBUG,"dev_mars_native","未找到dev/mars/testapplication/Methods2");
16 | return;
17 | }
18 | jmethodID init = env->GetMethodID(Methods2Class,"","()V");
19 | jobject methods2Obj = env->NewObject(Methods2Class,init);
20 | jmethodID l = env->GetMethodID(Methods2Class,"l","()V");
21 | env->CallVoidMethod(methods2Obj,l);
22 |
23 |
24 | }
25 |
26 | }
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
18 |
19 |
25 |
26 |
31 |
32 |
38 |
39 |
45 |
46 |
52 |
53 |
59 |
60 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/dex/apksecure/testapplication/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/dex/apksecure/testapplication/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/dex/apksecure/testapplication/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/dex/apksecure/testapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/dex/apksecure/testapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TestApplication
3 |
4 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/dex/apksecure/testapplication/src/test/java/dev/mars/testapplication/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package dev.mars.testapplication;
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() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/java_tool/ApkSecure/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ApkSecure
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/=UTF-8
3 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/.settings/org.eclipse.core.runtime.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | line.separator=\r\n
3 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/libs/dom4j-2.0.0-RC1-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/java_tool/ApkSecure/libs/dom4j-2.0.0-RC1-sources.jar
--------------------------------------------------------------------------------
/java_tool/ApkSecure/libs/dom4j-2.0.0-RC1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/java_tool/ApkSecure/libs/dom4j-2.0.0-RC1.jar
--------------------------------------------------------------------------------
/java_tool/ApkSecure/libs/zip4j_1.3.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mars-ma/ApkSecure/2174c3d60d83ba8f10c630f97f873df25df5ab91/java_tool/ApkSecure/libs/zip4j_1.3.2.jar
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/DESUtils.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.security.Key;
8 |
9 | import javax.crypto.Cipher;
10 | import javax.crypto.CipherInputStream;
11 | import javax.crypto.CipherOutputStream;
12 | import javax.crypto.SecretKeyFactory;
13 | import javax.crypto.spec.DESKeySpec;
14 |
15 | public class DESUtils {
16 |
17 | /** 加密工具 */
18 | private Cipher encryptCipher = null;
19 |
20 | /** 解密工具 */
21 | private Cipher decryptCipher = null;
22 |
23 | public void initialize_encryptKey(String keyValue) throws Exception {
24 | Key key = getKey(keyValue.getBytes());
25 | encryptCipher = Cipher.getInstance("DES");
26 | encryptCipher.init(Cipher.ENCRYPT_MODE, key);
27 | }
28 |
29 | public void initalize_dencryptkey(String keyValue) throws Exception {
30 | Key key = getKey(keyValue.getBytes());
31 | decryptCipher = Cipher.getInstance("DES");
32 | decryptCipher.init(Cipher.DECRYPT_MODE, key);
33 | }
34 |
35 | /**
36 | * 从指定字符串生成密钥,密钥所需的字节数组长度为8位 不足8位时后面补0,超出8位只取前8位
37 | *
38 | * @param arrBTmp
39 | * 构成该字符串的字节数组
40 | * @return 生成的密钥
41 | * @throws java.lang.Exception
42 | */
43 | private Key getKey(byte[] arrBTmp) throws Exception {
44 | DESKeySpec desKeySpec = new DESKeySpec(arrBTmp);
45 | SecretKeyFactory secretKeyFactory=SecretKeyFactory.getInstance("DES");
46 | Key key =secretKeyFactory.generateSecret(desKeySpec);
47 | return key;
48 | }
49 |
50 | /**
51 | * 加密字节数组
52 | *
53 | * @param arrB
54 | * 需加密的字节数组
55 | * @return 加密后的字节数组
56 | * @throws Exception
57 | */
58 | public byte[] encrypt(byte[] arrB) throws Exception {
59 | return encryptCipher.doFinal(arrB);
60 | }
61 |
62 | /**
63 | * 解密字节数组
64 | *
65 | * @param arrB
66 | * 需解密的字节数组
67 | * @return 解密后的字节数组
68 | * @throws Exception
69 | */
70 | public byte[] decrypt(byte[] arrB) throws Exception {
71 | return decryptCipher.doFinal(arrB);
72 | }
73 |
74 | /**
75 | * 文件file进行加密并保存目标文件destFile中
76 | *
77 | * @param file
78 | * 要加密的文件 如c:/test/srcFile.txt
79 | * @param destFile
80 | * 加密后存放的文件名 如c:/加密后文件.txt
81 | */
82 | public void encrypt(String sourceFileName, String diminationFileName)
83 | throws Exception {
84 | InputStream is = new FileInputStream(sourceFileName);
85 | OutputStream out = new FileOutputStream(diminationFileName);
86 | CipherInputStream cis = new CipherInputStream(is, encryptCipher);
87 | byte[] buffer = new byte[1024];
88 | int r;
89 | while ((r = cis.read(buffer)) > 0) {
90 | out.write(buffer, 0, r);
91 | }
92 | cis.close();
93 | is.close();
94 | out.close();
95 | }
96 |
97 | /**
98 | * 文件采用DES算法解密文件
99 | *
100 | * @param file
101 | * 已加密的文件 如c:/加密后文件.txt * @param destFile 解密后存放的文件名 如c:/
102 | * test/解密后文件.txt
103 | */
104 | public void decrypt(String sourceFileName, String diminationFileName)
105 | throws Exception {
106 | InputStream is = new FileInputStream(sourceFileName);
107 | OutputStream out = new FileOutputStream(diminationFileName);
108 | CipherOutputStream cos = new CipherOutputStream(out, decryptCipher);
109 | byte[] buffer = new byte[1024];
110 | int r;
111 | while ((r = is.read(buffer)) >= 0) {
112 | cos.write(buffer, 0, r);
113 | }
114 | cos.close();
115 | out.close();
116 | is.close();
117 | }
118 |
119 | }
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/FileUtil.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.util.List;
9 |
10 | public class FileUtil {
11 |
12 | public static void delete(File file){
13 | if(file!=null&&file.exists()){
14 | if(file.isDirectory()){
15 | for(File f:file.listFiles()){
16 | delete(f);
17 | // System.out.println("已删除"+f.getAbsolutePath());
18 | }
19 | file.delete();
20 | // System.out.println("已删除"+file.getAbsolutePath());
21 | }else{
22 | file.delete();
23 | // System.out.println("已删除"+file.getAbsolutePath());
24 | }
25 | }
26 | }
27 |
28 | public static void copyDir(String oldPath, String newPath) throws IOException {
29 | File file = new File(oldPath);
30 | String[] filePath = file.list();
31 |
32 | if (!(new File(newPath)).exists()) {
33 | (new File(newPath)).mkdir();
34 | }
35 |
36 | for (int i = 0; i < filePath.length; i++) {
37 | if ((new File(oldPath + File.separator + filePath[i])).isDirectory()) {
38 | copyDir(oldPath + File.separator + filePath[i], newPath + File.separator + filePath[i]);
39 | }
40 |
41 | if (new File(oldPath + File.separator + filePath[i]).isFile()) {
42 | copyFile(oldPath + File.separator + filePath[i], newPath + File.separator + filePath[i]);
43 | }
44 |
45 | }
46 | }
47 |
48 | public static void copyFile(String oldPath, String newPath) throws IOException {
49 | File oldFile = new File(oldPath);
50 | File file = new File(newPath);
51 | FileInputStream in = new FileInputStream(oldFile);
52 | FileOutputStream out = new FileOutputStream(file);;
53 |
54 | byte[] buffer=new byte[2097152];
55 |
56 | while((in.read(buffer)) != -1){
57 | out.write(buffer);
58 | }
59 | out.flush();
60 | out.close();
61 | in.close();
62 |
63 | }
64 |
65 |
66 | public static void ListFiles(String path,List list) {
67 | File dir = new File(path);
68 | if (dir.exists()) {
69 |
70 | if (dir.isDirectory()) {
71 | File[] childs = dir.listFiles();
72 | for (File f : childs) {
73 | ListFiles(f.getAbsolutePath(),null);
74 | }
75 | }
76 | System.out.println("ListFiles----" + dir.getAbsolutePath()+" isDirectory ? "+dir.isDirectory());
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/Main.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.FileOutputStream;
7 | import java.io.FileWriter;
8 | import java.io.IOException;
9 | import java.io.Writer;
10 | import java.text.SimpleDateFormat;
11 | import java.util.Date;
12 | import java.util.Iterator;
13 | import java.util.LinkedList;
14 | import java.util.List;
15 |
16 | import org.dom4j.Attribute;
17 | import org.dom4j.Document;
18 | import org.dom4j.DocumentException;
19 | import org.dom4j.Element;
20 | import org.dom4j.io.OutputFormat;
21 | import org.dom4j.io.SAXReader;
22 | import org.dom4j.io.XMLWriter;
23 |
24 | /**
25 | * 将原APK与脱壳DEX合并,输出新的apk
26 | *
27 | * @author ma.xuanwei
28 | *
29 | */
30 | public class Main {
31 | private static final String DEX_APP_NAME = "dev.mars.secure.ProxyApplication";
32 | private static final String PASSWORD = "laChineestunlionendormi";
33 | private static final SimpleDateFormat sdf = new SimpleDateFormat(
34 | "yyyyMMddHHmmss");
35 | private static Config config;
36 |
37 | /**
38 | * @param args
39 | */
40 | public static void main(String[] args) {
41 | String cmd = args[0];
42 | if (!"b".equals(cmd)) {
43 | System.out.println("错误的参数:" + cmd);
44 | return;
45 | }
46 | // apk路径
47 | String apkPath = args[1];
48 | System.out.println("apkPath:" + apkPath);
49 | // 反编译目录
50 | String decompiledDirName = apkPath.split("\\.")[0];
51 | System.out.println("decompiledDir:" + decompiledDirName);
52 |
53 | // 删除反编译目录
54 | File outputFolder = new File(getWorkPath() + "\\output");
55 | if(!outputFolder.exists()){
56 | outputFolder.mkdir();
57 | System.out.println("创建生成目录:"+outputFolder.getAbsolutePath());
58 | }
59 | File decompiledFile = new File(outputFolder.getAbsolutePath() +"\\"+ decompiledDirName);
60 | if (decompiledFile.exists()) {
61 | FileUtil.delete(decompiledFile);
62 | System.out.println("已删除" + decompiledFile.getAbsolutePath());
63 | }
64 | // 创建反编译目录
65 | boolean decompiled = false;
66 | try {
67 | long startTime = System.currentTimeMillis();
68 | System.out.println("正在反编译" + apkPath);
69 |
70 | // 确保apktool.jar放在工作目录下
71 | SystemCommand.execute("java -jar apktool.jar d " + apkPath+" -o "+decompiledFile.getAbsolutePath());
72 | System.out.println("反编译耗时 "
73 | + (System.currentTimeMillis() - startTime) + " ms");
74 | System.out.println("反编译结束,生成目录" + decompiledFile.getAbsolutePath());
75 | decompiled = true;
76 | } catch (InterruptedException e) {
77 | // TODO Auto-generated catch block
78 | e.printStackTrace();
79 | } catch (IOException e) {
80 | // TODO Auto-generated catch block
81 | e.printStackTrace();
82 | }
83 | if (decompiled) {
84 | if (alterAndroidMainifest(decompiledFile.getAbsolutePath())) {
85 |
86 | // try {
87 | // buildAPK(decompiledDir, newPath);
88 | try {
89 | SystemCommand.execute("java -jar apktool.jar b "
90 | + decompiledFile.getAbsolutePath());
91 | System.out.println("编译成功");
92 | String compiledApkPath = decompiledFile.getAbsolutePath() + "\\dist\\"
93 | + decompiledDirName + ".apk";
94 | File compiledApkFile = new File(compiledApkPath);
95 | if (compiledApkFile.exists()) {
96 | System.out.println("找到修改Manifest后的apk:"
97 | + compiledApkFile.getAbsolutePath());
98 |
99 | // 解压新的apk,并找到classes.dex,将其移动到assets中
100 | String unzipFilePath = decompiledFile.getAbsolutePath() + "\\dist\\"
101 | + decompiledDirName;
102 | FileUtil.delete(new File(unzipFilePath));
103 | ZipUtil.upzipFile(compiledApkFile, unzipFilePath);
104 | System.out.println("解压完成 解压输出:" + unzipFilePath);
105 |
106 | File assetsFile = new File(unzipFilePath+"\\assets");
107 | if(!assetsFile.exists()){
108 | assetsFile.mkdir();
109 | System.out.println("生成assets文件夹");
110 | }
111 | // 找到素有.dex文件
112 | List allDexFiles = findAllDexFiles(unzipFilePath);
113 | String zipFilePath = unzipFilePath
114 | + "\\assets\\abc"+System.currentTimeMillis()+".zip";
115 | // 将所有dex文件压缩进assets下的abc.zip
116 | ZipUtil.zipFile(zipFilePath, allDexFiles);
117 | System.out.println("生成压缩文件:" + zipFilePath);
118 |
119 | DESUtils desUtils = new DESUtils();
120 | desUtils.initialize_encryptKey(PASSWORD);
121 | String outputPath = unzipFilePath + "\\assets\\apksecurefile";
122 | desUtils.encrypt(zipFilePath, outputPath);
123 | (new File(zipFilePath)).delete();
124 | System.out.println("生成加密文件:" + outputPath);
125 | // 删除原classes.dex
126 | for (File f : allDexFiles) {
127 | f.delete();
128 | }
129 |
130 | String decladdingDexPath = System
131 | .getProperty("user.dir") + "\\classes.dex";
132 | String libsFolderPath = System.getProperty("user.dir")
133 | + "\\secure-lib\\";
134 | String destLibsFolderPath = new File(unzipFilePath
135 | + "\\lib\\").getAbsolutePath();
136 | String destDexPath = unzipFilePath+"\\classes.dex";
137 | if (copyDecladdingDexAndLibs(decladdingDexPath,
138 | destDexPath, libsFolderPath,
139 | destLibsFolderPath)) {
140 | String newAppPath = unzipFilePath + "\\"
141 | + decompiledDirName + ".zip";
142 | packageApkFiles(unzipFilePath, newAppPath);
143 | File newZipFile = new File(newAppPath);
144 | if (newZipFile.exists()) {
145 | System.out.println("生成压缩文件:" + newAppPath);
146 | File unsignedApkFile = new File(unzipFilePath
147 | + "\\new-app.apk");
148 | newZipFile.renameTo(unsignedApkFile);
149 | System.out.println("打包APP:"
150 | + unsignedApkFile.getAbsolutePath());
151 |
152 | String signedApkPath = unzipFilePath + "\\"
153 | + decompiledDirName + "_signed_"
154 | + sdf.format(new Date()) + ".apk";
155 |
156 | signApk(unsignedApkFile.getAbsolutePath(),
157 | signedApkPath);
158 |
159 | } else {
160 | System.out.println("打包app失败");
161 | }
162 | } else {
163 | System.out.println("复制壳DEX或so失败");
164 | }
165 |
166 | } else {
167 | System.out.println("未找到新生成的apk");
168 | }
169 | } catch (IOException e) {
170 | // TODO Auto-generated catch block
171 | e.printStackTrace();
172 | } catch (InterruptedException e) {
173 | // TODO Auto-generated catch block
174 | e.printStackTrace();
175 | } catch (Exception e) {
176 | // TODO Auto-generated catch block
177 | e.printStackTrace();
178 | }
179 | }
180 | } else {
181 | System.out.println("反编译失败");
182 | }
183 | }
184 |
185 | /**
186 | * 从指定路径找到所有dex文件
187 | *
188 | * @param unzipFilePath
189 | * @return
190 | * @throws IOException
191 | */
192 | private static List findAllDexFiles(String unzipFilePath)
193 | throws IOException {
194 | LinkedList files = new LinkedList<>();
195 | File folderFile = new File(unzipFilePath);
196 | for (File f : folderFile.listFiles()) {
197 | if (f.getPath().endsWith(".dex")) {
198 | System.out.println("找到dex:" + f.getCanonicalPath());
199 | files.add(f);
200 | }
201 | }
202 | return files;
203 | }
204 |
205 | private static void packageApkFiles(String unzipFilePath, String newAppPath)
206 | throws IOException, InterruptedException {
207 | // TODO Auto-generated method stub
208 | /*String winRARPath = getConfig().winRARPath;
209 | String zipCommand = "cd " + unzipFilePath + " && \"" + winRARPath
210 | + "\" a -r " + newAppPath + " ./*";
211 | System.out.println("cmd:" + zipCommand);
212 | SystemCommand.execute(zipCommand);*/
213 | Zip4JUtil.zip(unzipFilePath, newAppPath, true);
214 |
215 | /*LinkedList files = new LinkedList<>();
216 | File root = new File(unzipFilePath);
217 | for(File f:root.listFiles()){
218 | files.add(f);
219 | }
220 |
221 | ZipUtil.zipFile(newAppPath, files);*/
222 | }
223 |
224 | /**
225 | * 执行此方法确保,jarsigner的路径被添加到系统环境变量中
226 | *
227 | * @param unsignedApkPath
228 | * 未签名的apk的路径
229 | * @param signedApkPath
230 | * 生成的签名apk的路径
231 | * @throws IOException
232 | * @throws InterruptedException
233 | */
234 | private static void signApk(String unsignedApkPath, String signedApkPath)
235 | throws IOException, InterruptedException {
236 |
237 | String signCommand = "jarsigner -verbose -keystore "
238 | + getConfig().signaturePath
239 | + " "
240 | + "-storepass "
241 | + getConfig().storePwd
242 | + " -keypass "
243 | + getConfig().aliasPwd
244 | + " "
245 | + "-sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar "
246 | + signedApkPath + " " + unsignedApkPath + " "
247 | + getConfig().alias;
248 | System.out.println("cmd:" + signCommand);
249 | ;
250 | SystemCommand.execute(signCommand);
251 | System.out.println("签名后的apk路径:" + signedApkPath);
252 | }
253 |
254 | private static boolean copyDecladdingDexAndLibs(String decladdingDexPath,
255 | String destPath, String libsFolderPath, String destLibsFolderPath) {
256 | // TODO Auto-generated method stub
257 | File dexFile = new File(decladdingDexPath);
258 | if (dexFile.exists()) {
259 | System.out.println("脱壳dex路径:" + decladdingDexPath);
260 | // 开始复制文件
261 | try {
262 | FileInputStream fis = new FileInputStream(dexFile);
263 | FileOutputStream fos = new FileOutputStream(new File(destPath));
264 | byte[] buffer = new byte[1024];
265 | int readLength = 0;
266 | while (readLength != -1) {
267 | readLength = fis.read(buffer);
268 | if (readLength > 0) {
269 | fos.write(buffer, 0, readLength);
270 | }
271 | }
272 | fos.flush();
273 | fis.close();
274 | fos.close();
275 | System.out.println("壳Dex已复制到:" + destPath);
276 |
277 | System.out.println("开始复制libs,原始路径:" + libsFolderPath + " 目标路径:"
278 | + destLibsFolderPath);
279 | FileUtil.copyDir(libsFolderPath, destLibsFolderPath);
280 | System.out.println("复制结束");
281 | return true;
282 | } catch (FileNotFoundException e) {
283 | // TODO Auto-generated catch block
284 | e.printStackTrace();
285 | } catch (IOException e) {
286 | // TODO Auto-generated catch block
287 | e.printStackTrace();
288 | }
289 |
290 | } else {
291 | System.out.println("脱壳dex未找到");
292 | }
293 | return false;
294 | }
295 |
296 | /**
297 | * 修改AndroidMinifest.xml中的Application Class为脱壳的Application Class名
298 | * 在Application标签中增加原Application Class名
299 | *
300 | * @param workPath
301 | */
302 | private static boolean alterAndroidMainifest(String workPath) {
303 | // TODO Auto-generated method stub
304 | String manifestFileName = "AndroidManifest.xml";
305 | File manifestFile = new File(workPath + "\\" + manifestFileName);
306 | if (!manifestFile.exists()) {
307 | System.err.println("找不到" + manifestFile.getAbsolutePath());
308 | return false;
309 | }
310 | SAXReader reader = new SAXReader();
311 | try {
312 | Document document = reader.read(manifestFile);
313 | Element root = document.getRootElement();
314 |
315 | System.out.println("当前包名:" + root.attribute("package").getText());
316 | Element applicationEle = root.element("application");
317 | System.out.println("遍历application标签的属性:");
318 | Iterator attrIterator = applicationEle
319 | .attributeIterator();
320 | String APP_NAME = null;
321 | while (attrIterator.hasNext()) {
322 | Attribute attr = attrIterator.next();
323 | System.out.println(attr.getNamespacePrefix() + ":"
324 | + attr.getName() + " = " + attr.getValue());
325 | if ("android".equals(attr.getNamespacePrefix())
326 | && "name".equals(attr.getName())) {
327 | APP_NAME = attr.getValue();
328 | attr.setValue(DEX_APP_NAME);
329 | System.out.println("原application name:" + APP_NAME);
330 | System.out.println("新application name:" + attr.getValue());
331 | }
332 | }
333 | Element mataDataEle = applicationEle.addElement("meta-data");
334 | mataDataEle.addAttribute("android:name", "APP_NAME");
335 | mataDataEle.addAttribute("android:value", APP_NAME);
336 |
337 | manifestFile.delete();
338 | OutputFormat format = OutputFormat.createPrettyPrint();
339 | format.setEncoding("UTF-8");// 设置编码
340 | Writer writer = new FileWriter(manifestFile.getAbsolutePath());
341 | XMLWriter outPut = new XMLWriter(writer, format);
342 | outPut.write(document);
343 | outPut.close();
344 | System.out.println("修改Manifest成功");
345 | return true;
346 | } catch (DocumentException e) {
347 | // TODO Auto-generated catch block
348 | e.printStackTrace();
349 | } catch (IOException e) {
350 | // TODO Auto-generated catch block
351 | e.printStackTrace();
352 | }
353 |
354 | return false;
355 | }
356 |
357 | private static Config getConfig() {
358 | if (config != null) {
359 | return config;
360 | }
361 |
362 | File signerConfigFile = new File(getWorkPath() + "\\" + "config.xml");
363 | if (!signerConfigFile.exists()) {
364 | System.err.println("找不到" + signerConfigFile.getAbsolutePath());
365 | return null;
366 | }
367 | // 读取XML
368 | SAXReader reader = new SAXReader();
369 | try {
370 | Document document = reader.read(signerConfigFile);
371 | Element root = document.getRootElement();
372 | Element signaturePathEle = root.element("signature-path");
373 | String signaturePath = signaturePathEle.getText();
374 |
375 | Element storePwdEle = root.element("store-pwd");
376 | String storePwd = storePwdEle.getText();
377 |
378 | Element aliasEle = root.element("alias");
379 | String alias = aliasEle.getText();
380 |
381 | Element aliasPwdEle = root.element("alias-pwd");
382 | String aliasPwd = aliasPwdEle.getText();
383 |
384 | System.out.println("signature-path:" + signaturePath
385 | + " store-pwd:" + storePwd + " alias:" + alias
386 | + " aliasPwd:" + aliasPwd );
387 | config = new Config();
388 | config.signaturePath = signaturePath;
389 | config.storePwd = storePwd;
390 | config.alias = alias;
391 | config.aliasPwd = aliasPwd;
392 | } catch (DocumentException e) {
393 | // TODO Auto-generated catch block
394 | e.printStackTrace();
395 | }
396 |
397 | return config;
398 | }
399 |
400 | private static String getWorkPath() {
401 | return System.getProperty("user.dir");
402 | }
403 |
404 | static class Config {
405 | public String signaturePath;
406 | public String storePwd;
407 | public String alias;
408 | public String aliasPwd;
409 | public String winRARPath;
410 | }
411 | }
412 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/SystemCommand.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | public class SystemCommand {
8 |
9 | public static void execute(String command) throws IOException, InterruptedException {
10 | Runtime runtime = Runtime.getRuntime();
11 | System.out.println("execute " + command);
12 | Process pr = runtime.exec("cmd /c "+command);
13 | BufferedReader input = new BufferedReader(new InputStreamReader(
14 | pr.getInputStream()));
15 |
16 | String line = null;
17 |
18 | while ((line = input.readLine()) != null) {
19 | System.out.println(line);
20 | }
21 |
22 | int exitVal = pr.waitFor();
23 | System.out.println("Exited with error code " + exitVal);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/Zip4JUtil.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 |
7 | import net.lingala.zip4j.core.ZipFile;
8 | import net.lingala.zip4j.exception.ZipException;
9 | import net.lingala.zip4j.model.ZipParameters;
10 | import net.lingala.zip4j.util.Zip4jConstants;
11 |
12 | import com.sun.xml.internal.ws.util.StringUtils;
13 |
14 | public class Zip4JUtil {
15 |
16 | /**
17 | * 使用给定密码压缩指定文件或文件夹到指定位置.
18 | *
19 | * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"".
20 | * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;
21 | * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名.
22 | * @param src 要压缩的文件或文件夹路径
23 | * @param dest 压缩文件存放路径
24 | * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.
25 | * 如果为false,将直接压缩目录下文件到压缩文件.
26 | * @param passwd 压缩使用的密码
27 | * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败.
28 | */
29 | public static String zip(String src, String dest, boolean isCreateDir) {
30 | File srcFile = new File(src);
31 | dest = buildDestinationZipFilePath(srcFile, dest);
32 | System.out.println("dest1 : "+dest);
33 | ZipParameters parameters = new ZipParameters();
34 | parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式
35 | parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别
36 | try {
37 | ZipFile zipFile = new ZipFile(dest);
38 | if (srcFile.isDirectory()) {
39 | // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构
40 | if (!isCreateDir) {
41 | File [] subFiles = srcFile.listFiles();
42 | ArrayList temp = new ArrayList();
43 | Collections.addAll(temp, subFiles);
44 | zipFile.addFiles(temp, parameters);
45 | return dest;
46 | }else{
47 | File [] subFiles = srcFile.listFiles();
48 | for(File f:subFiles){
49 | if(f.isDirectory()){
50 | System.out.println("找到文件夹:"+f.getAbsolutePath()+" 将其压缩");
51 | zipFile.addFolder(f, parameters);
52 | }else{
53 | System.out.println("找到文件:"+f.getAbsolutePath()+" 将其压缩");
54 | zipFile.addFile(f, parameters);
55 | }
56 | }
57 | }
58 | } else {
59 | }
60 | return dest;
61 | } catch (ZipException e) {
62 | e.printStackTrace();
63 | }
64 | return null;
65 | }
66 |
67 | /**
68 | * 构建压缩文件存放路径,如果不存在将会创建
69 | * 传入的可能是文件名或者目录,也可能不传,此方法用以转换最终压缩文件的存放路径
70 | * @param srcFile 源文件
71 | * @param destParam 压缩目标路径
72 | * @return 正确的压缩文件存放路径
73 | */
74 | private static String buildDestinationZipFilePath(File srcFile,String destParam) {
75 | if (destParam==null&&destParam.length()==0) {
76 | if (srcFile.isDirectory()) {
77 | destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip";
78 | } else {
79 | String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
80 | destParam = srcFile.getParent() + File.separator + fileName + ".zip";
81 | }
82 | } else {
83 | createDestDirectoryIfNecessary(destParam); // 在指定路径不存在的情况下将其创建出来
84 | if (destParam.endsWith(File.separator)) {
85 | String fileName = "";
86 | if (srcFile.isDirectory()) {
87 | fileName = srcFile.getName();
88 | } else {
89 | fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf("."));
90 | }
91 | destParam += fileName + ".zip";
92 | }
93 | }
94 | return destParam;
95 | }
96 |
97 | /**
98 | * 在必要的情况下创建压缩文件存放目录,比如指定的存放路径并没有被创建
99 | * @param destParam 指定的存放路径,有可能该路径并没有被创建
100 | */
101 | private static void createDestDirectoryIfNecessary(String destParam) {
102 | File destDir = null;
103 | if (destParam.endsWith(File.separator)) {
104 | destDir = new File(destParam);
105 | } else {
106 | destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator)));
107 | }
108 | if (!destDir.exists()) {
109 | destDir.mkdirs();
110 | }
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/java_tool/ApkSecure/src/dev/mars/apksecure/ZipUtil.java:
--------------------------------------------------------------------------------
1 | package dev.mars.apksecure;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.OutputStream;
12 | import java.util.ArrayList;
13 | import java.util.Enumeration;
14 | import java.util.List;
15 | import java.util.zip.ZipEntry;
16 | import java.util.zip.ZipFile;
17 | import java.util.zip.ZipOutputStream;
18 |
19 | public class ZipUtil {
20 |
21 | private static byte[] _byte = new byte[1024] ;
22 | /**
23 | * 压缩文件或路径
24 | * @param zip 压缩的目的地址
25 | * @param srcFiles 压缩的源文件
26 | */
27 | public static void zipFile( String zip , List srcFiles ){
28 | try {
29 | if( zip.endsWith(".zip") || zip.endsWith(".ZIP") ){
30 | ZipOutputStream _zipOut = new ZipOutputStream(new FileOutputStream(new File(zip))) ;
31 | _zipOut.setMethod(ZipOutputStream.DEFLATED);
32 | for( File _f : srcFiles ){
33 | handlerFile(zip , _zipOut , _f , "");
34 | }
35 | _zipOut.close();
36 | }else{
37 | System.out.println("target file[" + zip + "] is not .zip type file");
38 | }
39 | } catch (FileNotFoundException e) {
40 | } catch (IOException e) {
41 | }
42 | }
43 |
44 | /**压缩
45 | * @param sourcePath
46 | * @param zipPath
47 | */
48 | public static void zip(String sourcePath, String zipPath){
49 | try {
50 | OutputStream os = new FileOutputStream(zipPath);
51 | BufferedOutputStream bos = new BufferedOutputStream(os);
52 | ZipOutputStream zos = new ZipOutputStream(bos);
53 | File file = new File(sourcePath);
54 | String basePath = null;
55 | if(file.isDirectory()){//要压缩的是文件夹
56 | basePath = file.getPath();
57 | }else{
58 | basePath = file.getParent();
59 | }
60 | zipFile(file, basePath, zos);
61 | zos.closeEntry();
62 | zos.close();
63 | bos.close();
64 | os.close();
65 | } catch (Exception e) {
66 | e.printStackTrace();
67 | }
68 | }
69 |
70 | private static void zipFile(File sourceFile, String basePath, ZipOutputStream zos) {
71 | File[] files = new File[0];
72 | if(sourceFile.isDirectory()){
73 | files = sourceFile.listFiles();
74 | }else{
75 | files = new File[1];
76 | files[0] = sourceFile;
77 | }
78 | byte[] buffer = new byte[1024];
79 | int length = 0;
80 | try {
81 | for(File file : files){
82 | if(file.isDirectory()){
83 | String pathName = file.getPath().substring(basePath.length() + 1) + "/";
84 | zos.putNextEntry(new ZipEntry(pathName));
85 | zipFile(file, basePath, zos);//迭代
86 | }else{
87 | String pathName = file.getPath().substring(basePath.length() + 1);
88 | zos.putNextEntry(new ZipEntry(pathName));
89 | InputStream is = new FileInputStream(file);
90 | BufferedInputStream bis = new BufferedInputStream(is);
91 | while((length = bis.read(buffer)) > 0){
92 | zos.write(buffer, 0, length);
93 | }
94 | is.close();
95 | }
96 | }
97 | } catch (Exception e) {
98 | e.printStackTrace();
99 | }
100 | }
101 |
102 | /**
103 | *
104 | * @param zip 压缩的目的地址
105 | * @param zipOut
106 | * @param srcFile 被压缩的文件信息
107 | * @param path 在zip中的相对路径
108 | * @throws IOException
109 | */
110 | private static void handlerFile(String zip , ZipOutputStream zipOut , File srcFile , String path ) throws IOException{
111 | System.out.println(" begin to compression file[" + srcFile.getName() + "]");
112 | if( !"".equals(path) && ! path.endsWith(File.separator)){
113 | path += File.separator ;
114 | }
115 | if( ! srcFile.getPath().equals(zip) ){
116 | if( srcFile.isDirectory() ){
117 | File[] _files = srcFile.listFiles() ;
118 | if( _files.length == 0 ){
119 | zipOut.putNextEntry(new ZipEntry( path + srcFile.getName() + File.separator));
120 | zipOut.closeEntry();
121 | }else{
122 | for( File _f : _files ){
123 | handlerFile( zip ,zipOut , _f , path + srcFile.getName() );
124 | }
125 | }
126 | }else{
127 | InputStream _in = new FileInputStream(srcFile) ;
128 | zipOut.putNextEntry(new ZipEntry(path + srcFile.getName()));
129 | int len = 0 ;
130 | while( (len = _in.read(_byte)) > 0 ){
131 | zipOut.write(_byte, 0, len);
132 | }
133 | _in.close();
134 | zipOut.closeEntry();
135 | }
136 | }
137 | }
138 |
139 | /**
140 | * 解压缩ZIP文件,将ZIP文件里的内容解压到targetDIR目录下
141 | * @param zipName 待解压缩的ZIP文件名
142 | * @param targetBaseDirName 目标目录
143 | */
144 | public static List upzipFile(String zipPath, String descDir) {
145 | return upzipFile( new File(zipPath) , descDir ) ;
146 | }
147 |
148 | /**
149 | * 对.zip文件进行解压缩
150 | * @param zipFile 解压缩文件
151 | * @param descDir 压缩的目标地址,如:D:\\测试 或 /mnt/d/测试
152 | * @return
153 | */
154 | @SuppressWarnings("rawtypes")
155 | public static List upzipFile(File zipFile, String descDir) {
156 | List _list = new ArrayList() ;
157 | try {
158 | ZipFile _zipFile = new ZipFile(zipFile) ;
159 | for( Enumeration entries = _zipFile.entries() ; entries.hasMoreElements() ; ){
160 | ZipEntry entry = (ZipEntry)entries.nextElement() ;
161 | File _file = new File(descDir + File.separator + entry.getName()) ;
162 | if( entry.isDirectory() ){
163 | _file.mkdirs() ;
164 | }else{
165 | File _parent = _file.getParentFile() ;
166 | if( !_parent.exists() ){
167 | _parent.mkdirs() ;
168 | }
169 | InputStream _in = _zipFile.getInputStream(entry);
170 | OutputStream _out = new FileOutputStream(_file) ;
171 | int len = 0 ;
172 | while( (len = _in.read(_byte)) > 0){
173 | _out.write(_byte, 0, len);
174 | }
175 | _in.close();
176 | _out.flush();
177 | _out.close();
178 | _list.add(_file) ;
179 | }
180 | }
181 | } catch (IOException e) {
182 | }
183 | return _list ;
184 | }
185 |
186 | /**
187 | * 对临时生成的文件夹和文件夹下的文件进行删除
188 | */
189 | public static void deletefile(String delpath) {
190 | try {
191 | File file = new File(delpath);
192 | if (!file.isDirectory()) {
193 | file.delete();
194 | } else if (file.isDirectory()) {
195 | String[] filelist = file.list();
196 | for (int i = 0; i < filelist.length; i++) {
197 | File delfile = new File(delpath + File.separator + filelist[i]);
198 | if (!delfile.isDirectory()) {
199 | delfile.delete();
200 | } else if (delfile.isDirectory()) {
201 | deletefile(delpath + File.separator + filelist[i]);
202 | }
203 | }
204 | file.delete();
205 | }
206 | } catch (Exception e) {
207 | e.printStackTrace();
208 | }
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------