├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── Administrator.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── apkdexproccessor ├── .gitignore ├── Encrypt.apk ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── example │ └── MyClass.java ├── apktool └── apktool_2.1.1.jar ├── app ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── libs │ └── armeabi │ │ └── libbsjni.so ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── jd │ │ └── apploader │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── include │ │ │ ├── crypt.h │ │ │ ├── ioapi.h │ │ │ ├── ioapi_buf.h │ │ │ ├── ioapi_mem.h │ │ │ ├── native-lib.h │ │ │ ├── unzip.h │ │ │ └── zip.h │ │ ├── ioapi.c │ │ ├── ioapi_buf.c │ │ ├── ioapi_mem.c │ │ ├── native-lib.cpp │ │ ├── unzip.c │ │ └── zip.c │ ├── java │ │ └── com │ │ │ └── jd │ │ │ └── apploader │ │ │ └── App.java │ └── res │ │ ├── mipmap-xhdpi │ │ └── icon.png │ │ └── values │ │ ├── color.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── jd │ └── apploader │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── reinforce.apk ├── reinforceapk ├── .gitignore ├── build.gradle ├── libs │ ├── dom4j-1.6.1.jar │ └── snakeyaml-1.12.jar └── src │ └── main │ └── java │ └── com │ └── max │ └── reinforce │ ├── Main.java │ ├── bean │ ├── ManifestInfo.java │ ├── MetaInfo.java │ ├── PackageInfo.java │ ├── UsesFramework.java │ └── VersionInfo.java │ ├── shell │ └── ShellPack.java │ └── util │ ├── Apktool.java │ ├── Base64.java │ ├── FileUtils.java │ ├── InputStreamRunnable.java │ └── Utils.java ├── settings.gradle └── shell.apk /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/Administrator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | C:\Users\Administrator\AppData\Roaming\Subversion 45 | 46 | 47 | 48 | 49 | 50 | 51 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReinforceApp 2 | apk加固 3 | 原理解析:http://blog.csdn.net/qq_38270039/article/details/78528369 4 | -------------------------------------------------------------------------------- /apkdexproccessor/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /apkdexproccessor/Encrypt.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/apkdexproccessor/Encrypt.apk -------------------------------------------------------------------------------- /apkdexproccessor/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | } 6 | 7 | sourceCompatibility = "1.7" 8 | targetCompatibility = "1.7" 9 | -------------------------------------------------------------------------------- /apkdexproccessor/src/main/java/com/example/MyClass.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.security.MessageDigest; 9 | import java.security.NoSuchAlgorithmException; 10 | import java.util.zip.Adler32; 11 | 12 | public class MyClass { 13 | 14 | private static final String ENCRYPT_APK_DEST_PATH = "loader/assets/Ldal.bin"; 15 | private static final String FINAL_APK_PATH = "dest/"; 16 | 17 | public static void main(String[] args) { 18 | try { 19 | encryptApkFile("apkdexproccessor/Encrypt.apk", "app/src/main/assets/Ldal.bin"); 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | 24 | } 25 | 26 | private static void buildLoaderApk() { 27 | File[] srcFiles = listSrcFiles(); 28 | 29 | for(File file : srcFiles) { 30 | try { 31 | String destApkFile = FINAL_APK_PATH + file.getName(); 32 | encryptApkFile(file.getAbsolutePath(), ENCRYPT_APK_DEST_PATH); 33 | buildApk(destApkFile); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | 38 | } 39 | } 40 | 41 | private static void buildApk(String destFile) throws IOException { 42 | Runtime.getRuntime().exec("apktool.jar b loader o " + destFile); 43 | } 44 | 45 | private static File[] listSrcFiles() { 46 | File file = new File("src"); 47 | return file.listFiles(); 48 | } 49 | 50 | private static void encryptApkFile(String srcFilePath, String destPath) throws IOException { 51 | File apkFile = new File(srcFilePath); 52 | byte[] apkFileBytes = encrypt(readFileBytes(apkFile)); 53 | 54 | writeBytes2File(destPath, apkFileBytes); 55 | } 56 | 57 | private static void copyFile2Dex() { 58 | File apkFile = new File("apkdexproccessor/PopStar_baibao.apk"); 59 | File dexFile = new File("apkdexproccessor/oldclasses.dex"); 60 | try { 61 | byte[] apkFileBytes = encrypt(readFileBytes(apkFile));//readFileBytes(apkFile); // 62 | byte[] dexFileBytes = readFileBytes(dexFile); 63 | int apkFileLen = apkFileBytes.length; 64 | int dexFileLen = dexFileBytes.length; 65 | int totalLength = apkFileLen + dexFileLen + 4; 66 | System.out.println("old dex file length: " + dexFileLen); 67 | byte[] newDexBytes = new byte[totalLength]; 68 | // copy dex file 69 | System.arraycopy(dexFileBytes, 0, newDexBytes, 0, dexFileLen); 70 | // copy apk file 71 | System.arraycopy(apkFileBytes, 0, newDexBytes, dexFileLen, apkFileLen); 72 | // set apk file len 73 | System.arraycopy(intToByte(apkFileLen), 0, newDexBytes, totalLength - 4, 4); 74 | 75 | fixFileSizeHead(newDexBytes); 76 | 77 | fixSHA1Head(newDexBytes); 78 | 79 | fixCheckSumHead(newDexBytes); 80 | 81 | writeDexBytesToFile(newDexBytes); 82 | 83 | } catch (IOException e) { 84 | e.printStackTrace(); 85 | } catch (NoSuchAlgorithmException e) { 86 | e.printStackTrace(); 87 | } 88 | } 89 | 90 | private static byte[] readFileBytes(File file) throws IOException { 91 | byte[] buffers = new byte[1024]; 92 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 93 | FileInputStream is = new FileInputStream(file); 94 | int i = 0; 95 | while ((i = is.read(buffers)) > 0) { 96 | baos.write(buffers, 0, i); 97 | } 98 | 99 | byte[] fileBytes = baos.toByteArray(); 100 | baos.close(); 101 | is.close(); 102 | 103 | return fileBytes; 104 | } 105 | 106 | private static byte[] encrypt(byte[] data) { 107 | for(int i = 0; i < data.length; i++) { 108 | data[i] = (byte) (0xa1 ^ data[i]); 109 | } 110 | return data; 111 | } 112 | 113 | private static byte[] intToByte(int number) { 114 | byte[] b = new byte[4]; 115 | for(int i = 3; i >= 0; i--) { 116 | b[i] = (byte) (number % 256); 117 | number >>= 8; 118 | } 119 | 120 | return b; 121 | } 122 | 123 | private static void fixFileSizeHead(byte[] dexBytes) { 124 | byte[] fileLenBytes = intToByte(dexBytes.length); 125 | byte[] trans = new byte[4]; 126 | for(int i = 0; i < 4; i++) { 127 | trans[i] = fileLenBytes[3 - i]; 128 | } 129 | 130 | System.arraycopy(trans, 0, dexBytes, 32, 4); //size head position is 32 131 | } 132 | 133 | private static void fixSHA1Head(byte[] dexBytes) throws NoSuchAlgorithmException { 134 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 135 | md.update(dexBytes, 32, dexBytes.length - 32); //from 32 position to end 136 | byte[] newDgt = md.digest(); 137 | System.arraycopy(newDgt, 0, dexBytes, 12, 20); // sha1 head position is 12 138 | } 139 | 140 | private static void fixCheckSumHead(byte[] dexBytes) { 141 | Adler32 adler = new Adler32(); 142 | adler.update(dexBytes, 12, dexBytes.length - 12); // check sum from position 12 143 | long value = adler.getValue(); 144 | int va = (int) value; 145 | byte[] vaBytes = intToByte(va); 146 | byte[] trans = new byte[4]; 147 | for(int i = 0; i < 4; i++) { 148 | trans[i] = vaBytes[3 - i]; 149 | } 150 | 151 | System.arraycopy(trans, 0, dexBytes, 8, 4); // check sum position is 8 152 | } 153 | 154 | private static void writeDexBytesToFile(byte[] dexBytes) throws IOException { 155 | writeBytes2File("apkdexproccessor/classes.dex", dexBytes); 156 | } 157 | 158 | private static void writeBytes2File(String fileName, byte[] bytes) throws IOException { 159 | File file = new File(fileName); 160 | if(file.exists()) { 161 | file.delete(); 162 | } 163 | 164 | FileOutputStream fos = new FileOutputStream(file); 165 | fos.write(bytes); 166 | fos.flush(); 167 | fos.close(); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /apktool/apktool_2.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/apktool/apktool_2.1.1.jar -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/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 | INCLUDE_DIRECTORIES(src/main/cpp/include) 8 | 9 | # Creates and names a library, sets it as either STATIC 10 | # or SHARED, and provides the relative paths to its source code. 11 | # You can define multiple libraries, and CMake builds it for you. 12 | # Gradle automatically packages shared libraries with your APK. 13 | 14 | add_library( # Sets the name of the library. 15 | native-lib 16 | 17 | # Sets the library as a shared library. 18 | SHARED 19 | 20 | # Provides a relative path to your source file(s). 21 | # Associated headers in the same location as their source 22 | # file are automatically included. 23 | src/main/cpp/native-lib.cpp 24 | src/main/cpp/ioapi.c 25 | src/main/cpp/ioapi_buf.c 26 | src/main/cpp/ioapi_mem.c 27 | src/main/cpp/unzip.c 28 | src/main/cpp/zip.c) 29 | 30 | 31 | # src/main/cpp/inflate.cc 32 | # src/main/cpp/zutil.cc 33 | # src/main/cpp/inftrees.cc 34 | # src/main/cpp/inffast.cc 35 | # src/main/cpp/crc32.cc 36 | # src/main/cpp/adler32.cc 37 | # src/main/cpp/deflate.cc) 38 | 39 | # Searches for a specified prebuilt library and stores the path as a 40 | # variable. Because system libraries are included in the search path by 41 | # default, you only need to specify the name of the public NDK library 42 | # you want to add. CMake verifies that the library exists before 43 | # completing its build. 44 | 45 | find_library( # Sets the name of the path variable. 46 | log-lib 47 | 48 | # Specifies the name of the NDK library that 49 | # you want CMake to locate. 50 | log ) 51 | 52 | find_library( # Sets the name of the path variable. 53 | android-lib 54 | 55 | # Specifies the name of the NDK library that 56 | # you want CMake to locate. 57 | android ) 58 | 59 | find_library( # Sets the name of the path variable. 60 | z-lib 61 | 62 | # Specifies the name of the NDK library that 63 | # you want CMake to locate. 64 | z ) 65 | 66 | # Specifies libraries CMake should link to your target library. You 67 | # can link multiple libraries, such as libraries you define in the 68 | # build script, prebuilt third-party libraries, or system libraries. 69 | 70 | target_link_libraries( # Specifies the target library. 71 | native-lib 72 | 73 | # Links the target library to the log library 74 | # included in the NDK. 75 | ${log-lib} 76 | ${android-lib} 77 | ${z-lib}) 78 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.0" 6 | defaultConfig { 7 | applicationId "com.max.reinforce" //com.max.reinforce 8 | minSdkVersion 14 9 | targetSdkVersion 21 10 | versionCode 1 11 | versionName "1.0.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | externalNativeBuild { 14 | cmake { 15 | cppFlags "" 16 | } 17 | } 18 | 19 | ndk { 20 | abiFilters 'armeabi' 21 | } 22 | } 23 | signingConfigs { 24 | releaseConfig { 25 | storeFile file('C:\\Users\\Administrator\\.android\\VideoKey1.jks') 26 | storePassword '9876543210' 27 | keyAlias 'VideoKey1' 28 | keyPassword '9876543210' 29 | } 30 | } 31 | buildTypes { 32 | release { 33 | minifyEnabled true 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | 36 | signingConfig signingConfigs.releaseConfig 37 | } 38 | debug { 39 | signingConfig signingConfigs.releaseConfig 40 | } 41 | } 42 | 43 | sourceSets { 44 | main { 45 | jniLibs.srcDirs = ['libs'] 46 | } 47 | } 48 | externalNativeBuild { 49 | cmake { 50 | path "CMakeLists.txt" 51 | } 52 | } 53 | } 54 | 55 | dependencies { 56 | compile fileTree(dir: 'libs', include: ['*.jar']) 57 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 58 | exclude group: 'com.android.support', module: 'support-annotations' 59 | }) 60 | // compile 'com.android.support:appcompat-v7:24.2.1' 61 | testCompile 'junit:junit:4.12' 62 | } 63 | -------------------------------------------------------------------------------- /app/libs/armeabi/libbsjni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/app/libs/armeabi/libbsjni.so -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in G:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keep class com.jd.apploader.App { 20 | protected static ; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/jd/apploader/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.jd.apploader; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.jd.apploader", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/cpp/include/crypt.h: -------------------------------------------------------------------------------- 1 | /* crypt.h -- base code for crypt/uncrypt ZIPfile 2 | 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | This code is a modified version of crypting code in Infozip distribution 9 | 10 | The encryption/decryption parts of this source code (as opposed to the 11 | non-echoing password parts) were originally written in Europe. The 12 | whole source package can be freely distributed, including from the USA. 13 | (Prior to January 2000, re-export from the US was a violation of US law.) 14 | 15 | This encryption code is a direct transcription of the algorithm from 16 | Roger Schlafly, described by Phil Katz in the file appnote.txt. This 17 | file (appnote.txt) is distributed with the PKZIP program (even in the 18 | version without encryption capabilities). 19 | 20 | If you don't need crypting in your application, just define symbols 21 | NOCRYPT and NOUNCRYPT. 22 | 23 | This code support the "Traditional PKWARE Encryption". 24 | 25 | The new AES encryption added on Zip format by Winzip (see the page 26 | http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong 27 | Encryption is not supported. 28 | */ 29 | 30 | #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) 31 | 32 | /*********************************************************************** 33 | * Return the next byte in the pseudo-random sequence 34 | */ 35 | static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) 36 | { 37 | unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an 38 | * unpredictable manner on 16-bit systems; not a problem 39 | * with any known compiler so far, though */ 40 | 41 | temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; 42 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 43 | } 44 | 45 | /*********************************************************************** 46 | * Update the encryption keys with the next byte of plain text 47 | */ 48 | static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) 49 | { 50 | (*(pkeys+0)) = CRC32((*(pkeys+0)), c); 51 | (*(pkeys+1)) += (*(pkeys+0)) & 0xff; 52 | (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; 53 | { 54 | register int keyshift = (int)((*(pkeys+1)) >> 24); 55 | (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); 56 | } 57 | return c; 58 | } 59 | 60 | 61 | /*********************************************************************** 62 | * Initialize the encryption keys and the random header according to 63 | * the given password. 64 | */ 65 | static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) 66 | { 67 | *(pkeys+0) = 305419896L; 68 | *(pkeys+1) = 591751049L; 69 | *(pkeys+2) = 878082192L; 70 | while (*passwd != '\0') { 71 | update_keys(pkeys,pcrc_32_tab,(int)*passwd); 72 | passwd++; 73 | } 74 | } 75 | 76 | #define zdecode(pkeys,pcrc_32_tab,c) \ 77 | (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) 78 | 79 | #define zencode(pkeys,pcrc_32_tab,c,t) \ 80 | (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) 81 | 82 | #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED 83 | 84 | #define RAND_HEAD_LEN 12 85 | /* "last resort" source for second part of crypt seed pattern */ 86 | # ifndef ZCR_SEED2 87 | # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ 88 | # endif 89 | 90 | static int crypthead(const char* passwd, /* password string */ 91 | unsigned char* buf, /* where to write header */ 92 | int bufSize, 93 | unsigned long* pkeys, 94 | const unsigned long* pcrc_32_tab, 95 | unsigned long crcForCrypting) 96 | { 97 | int n; /* index in random header */ 98 | int t; /* temporary */ 99 | int c; /* random byte */ 100 | unsigned char header[RAND_HEAD_LEN-2]; /* random header */ 101 | static unsigned calls = 0; /* ensure different random header each time */ 102 | 103 | if (bufSize> 7) & 0xff; 118 | header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); 119 | } 120 | /* Encrypt random header (last two bytes is high word of crc) */ 121 | init_keys(passwd, pkeys, pcrc_32_tab); 122 | for (n = 0; n < RAND_HEAD_LEN-2; n++) 123 | { 124 | buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); 125 | } 126 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); 127 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); 128 | return n; 129 | } 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /app/src/main/cpp/include/ioapi.h: -------------------------------------------------------------------------------- 1 | /* ioapi.h -- IO base function header for compress/uncompress .zip 2 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 3 | 4 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 5 | 6 | Modifications for Zip64 support 7 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 8 | 9 | For more info read MiniZip_info.txt 10 | 11 | Changes 12 | 13 | Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) 14 | Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. 15 | More if/def section may be needed to support other platforms 16 | Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. 17 | (but you should use iowin32.c for windows instead) 18 | 19 | */ 20 | 21 | #define USE_FILE32API 22 | 23 | #ifndef _ZLIBIOAPI64_H 24 | #define _ZLIBIOAPI64_H 25 | 26 | #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) 27 | /* Linux needs this to support file operation on files larger then 4+GB 28 | But might need better if/def to select just the platforms that needs them. */ 29 | #ifndef __USE_FILE_OFFSET64 30 | #define __USE_FILE_OFFSET64 31 | #endif 32 | #ifndef __USE_LARGEFILE64 33 | #define __USE_LARGEFILE64 34 | #endif 35 | #ifndef _LARGEFILE64_SOURCE 36 | #define _LARGEFILE64_SOURCE 37 | #endif 38 | #ifndef _FILE_OFFSET_BIT 39 | #define _FILE_OFFSET_BIT 64 40 | #endif 41 | #endif 42 | 43 | #include 44 | #include 45 | #include "zlib.h" 46 | 47 | #if defined(USE_FILE32API) 48 | #define fopen64 fopen 49 | #define ftello64 ftell 50 | #define fseeko64 fseek 51 | #else 52 | #ifdef __FreeBSD__ 53 | #define fopen64 fopen 54 | #define ftello64 ftello 55 | #define fseeko64 fseeko 56 | #endif 57 | #ifdef _MSC_VER 58 | #define fopen64 fopen 59 | #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) 60 | #define ftello64 _ftelli64 61 | #define fseeko64 _fseeki64 62 | #else // old MSC 63 | #define ftello64 ftell 64 | #define fseeko64 fseek 65 | #endif 66 | #endif 67 | #endif 68 | 69 | /* a type choosen by DEFINE */ 70 | #ifdef HAVE_64BIT_INT_CUSTOM 71 | typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; 72 | #else 73 | #ifdef HAS_STDINT_H 74 | #include "stdint.h" 75 | typedef uint64_t ZPOS64_T; 76 | #else 77 | 78 | #if defined(_MSC_VER) || defined(__BORLANDC__) 79 | typedef unsigned __int64 ZPOS64_T; 80 | #else 81 | typedef unsigned long long int ZPOS64_T; 82 | #endif 83 | #endif 84 | #endif 85 | 86 | #ifdef __cplusplus 87 | extern "C" { 88 | #endif 89 | 90 | #define ZLIB_FILEFUNC_SEEK_CUR (1) 91 | #define ZLIB_FILEFUNC_SEEK_END (2) 92 | #define ZLIB_FILEFUNC_SEEK_SET (0) 93 | 94 | #define ZLIB_FILEFUNC_MODE_READ (1) 95 | #define ZLIB_FILEFUNC_MODE_WRITE (2) 96 | #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) 97 | 98 | #define ZLIB_FILEFUNC_MODE_EXISTING (4) 99 | #define ZLIB_FILEFUNC_MODE_CREATE (8) 100 | 101 | #ifndef ZCALLBACK 102 | #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \ 103 | defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) 104 | #define ZCALLBACK CALLBACK 105 | #else 106 | #define ZCALLBACK 107 | #endif 108 | #endif 109 | 110 | typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); 111 | typedef voidpf (ZCALLBACK *opendisk_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); 112 | typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); 113 | typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); 114 | typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); 115 | typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); 116 | 117 | typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); 118 | typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); 119 | 120 | /* here is the "old" 32 bits structure structure */ 121 | typedef struct zlib_filefunc_def_s 122 | { 123 | open_file_func zopen_file; 124 | opendisk_file_func zopendisk_file; 125 | read_file_func zread_file; 126 | write_file_func zwrite_file; 127 | tell_file_func ztell_file; 128 | seek_file_func zseek_file; 129 | close_file_func zclose_file; 130 | testerror_file_func zerror_file; 131 | voidpf opaque; 132 | } zlib_filefunc_def; 133 | 134 | typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); 135 | typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); 136 | typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); 137 | typedef voidpf (ZCALLBACK *opendisk64_file_func)OF((voidpf opaque, voidpf stream, int number_disk, int mode)); 138 | 139 | typedef struct zlib_filefunc64_def_s 140 | { 141 | open64_file_func zopen64_file; 142 | opendisk64_file_func zopendisk64_file; 143 | read_file_func zread_file; 144 | write_file_func zwrite_file; 145 | tell64_file_func ztell64_file; 146 | seek64_file_func zseek64_file; 147 | close_file_func zclose_file; 148 | testerror_file_func zerror_file; 149 | voidpf opaque; 150 | } zlib_filefunc64_def; 151 | 152 | void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); 153 | void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); 154 | 155 | /* now internal definition, only for zip.c and unzip.h */ 156 | typedef struct zlib_filefunc64_32_def_s 157 | { 158 | zlib_filefunc64_def zfile_func64; 159 | open_file_func zopen32_file; 160 | opendisk_file_func zopendisk32_file; 161 | tell_file_func ztell32_file; 162 | seek_file_func zseek32_file; 163 | } zlib_filefunc64_32_def; 164 | 165 | #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) 166 | #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) 167 | //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) 168 | //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) 169 | #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) 170 | #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) 171 | 172 | voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); 173 | voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)); 174 | long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); 175 | ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); 176 | 177 | void fill_zlib_filefunc64_32_def_from_filefunc32 OF((zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)); 178 | 179 | #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) 180 | #define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode))) 181 | #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) 182 | #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /app/src/main/cpp/include/ioapi_buf.h: -------------------------------------------------------------------------------- 1 | /* ioapi_buf.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | This version of ioapi is designed to buffer IO. 5 | 6 | Based on Unzip ioapi.c version 0.22, May 19th, 2003 7 | 8 | Copyright (C) 1998-2003 Gilles Vollant 9 | (C) 2003 Justin Fletcher 10 | (C) 2012 Nathan Moinvaziri 11 | 12 | This file is under the same license as the Unzip tool it is distributed 13 | with. 14 | */ 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "zlib.h" 22 | #include "ioapi.h" 23 | 24 | #define IOBUF_BUFFERSIZE (64 * 1024) 25 | 26 | voidpf ZCALLBACK fopen_buf_func OF((voidpf opaque,const char* filename,int mode)); 27 | voidpf ZCALLBACK fopen64_buf_func OF((voidpf opaque,const char* filename,int mode)); 28 | voidpf ZCALLBACK fopendisk_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); 29 | voidpf ZCALLBACK fopendisk64_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); 30 | uLong ZCALLBACK fread_buf_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); 31 | uLong ZCALLBACK fwrite_buf_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); 32 | long ZCALLBACK ftell_buf_func OF((voidpf opaque,voidpf stream)); 33 | ZPOS64_T ZCALLBACK ftell64_buf_func OF((voidpf opaque, voidpf stream)); 34 | long ZCALLBACK fseek_buf_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); 35 | long ZCALLBACK fseek64_buf_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); 36 | int ZCALLBACK fclose_buf_func OF((voidpf opaque,voidpf stream)); 37 | int ZCALLBACK ferror_buf_func OF((voidpf opaque,voidpf stream)); 38 | 39 | typedef struct ourbuffer_s { 40 | zlib_filefunc_def filefunc; 41 | zlib_filefunc64_def filefunc64; 42 | } ourbuffer_t; 43 | 44 | void fill_buffer_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); 45 | void fill_buffer_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); -------------------------------------------------------------------------------- /app/src/main/cpp/include/ioapi_mem.h: -------------------------------------------------------------------------------- 1 | /* ioapi_mem.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | This version of ioapi is designed to access memory rather than files. 5 | We do use a region of memory to put data in to and take it out of. We do 6 | not have auto-extending buffers and do not inform anyone else that the 7 | data has been written. It is really intended for accessing a zip archive 8 | embedded in an application such that I can write an installer with no 9 | external files. Creation of archives has not been attempted, although 10 | parts of the framework are present. 11 | 12 | Based on Unzip ioapi.c version 0.22, May 19th, 2003 13 | 14 | Copyright (C) 1998-2003 Gilles Vollant 15 | (C) 2003 Justin Fletcher 16 | 17 | This file is under the same license as the Unzip tool it is distributed 18 | with. 19 | */ 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "zlib.h" 27 | #include "ioapi.h" 28 | 29 | 30 | voidpf ZCALLBACK fopen_mem_func OF((voidpf opaque,const char* filename,int mode)); 31 | voidpf ZCALLBACK fopendisk_mem_func OF((voidpf opaque, voidpf stream, int number_disk, int mode)); 32 | uLong ZCALLBACK fread_mem_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); 33 | uLong ZCALLBACK fwrite_mem_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); 34 | long ZCALLBACK ftell_mem_func OF((voidpf opaque,voidpf stream)); 35 | long ZCALLBACK fseek_mem_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); 36 | int ZCALLBACK fclose_mem_func OF((voidpf opaque,voidpf stream)); 37 | int ZCALLBACK ferror_mem_func OF((voidpf opaque,voidpf stream)); 38 | 39 | typedef struct ourmemory_s { 40 | char *base; /* Base of the region of memory we're using */ 41 | uLong size; /* Size of the region of memory we're using */ 42 | uLong limit; /* Furthest we've written */ 43 | uLong cur_offset; /* Current offset in the area */ 44 | } ourmemory_t; 45 | 46 | void fill_memory_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourmemory_t *ourmem)); -------------------------------------------------------------------------------- /app/src/main/cpp/include/native-lib.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Administrator on 2016/12/7. 3 | // 4 | 5 | #ifndef APPLOADER_NATIVE_LIB_H_H 6 | #define APPLOADER_NATIVE_LIB_H_H 7 | 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "AppLoader", __VA_ARGS__) 16 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "AppLoader", __VA_ARGS__) 17 | //#define LOGD(...) 18 | //#define LOGE(...) 19 | const int MAX_FILENAME_LEN = 256; 20 | 21 | char *packageName; 22 | jstring jPackageName; 23 | char *apkFilePath; 24 | char *apkLibPath; 25 | char *apkFileName; 26 | 27 | char *GetApkFilePath(JNIEnv *env, jobject app); 28 | char *GetApkFileName(const char *apkFilePath); 29 | char* Jstring2CStr(JNIEnv *env, jstring jstr); 30 | int CreateDir(const char *pDir); 31 | void LoadResource(JNIEnv *env, jstring apkFileName); 32 | jobject createGameApplication(JNIEnv *env, jstring appName, jstring apkFileName); 33 | void Java_com_jd_apploader_App_onAppCreate(JNIEnv *, jobject, jobject, jobject, jstring); 34 | jobject Java_com_jd_apploader_App_onAppAttach(JNIEnv *, jobject, jobject, jstring); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | #endif //APPLOADER_NATIVE_LIB_H_H 40 | -------------------------------------------------------------------------------- /app/src/main/cpp/include/unzip.h: -------------------------------------------------------------------------------- 1 | /* unzip.h -- IO for uncompress .zip files using zlib 2 | Version 1.1, February 14h, 2010 3 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 4 | 5 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 6 | 7 | Modifications of Unzip for Zip64 8 | Copyright (C) 2007-2008 Even Rouault 9 | 10 | Modifications for Zip64 support on both zip and unzip 11 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 12 | 13 | For more info read MiniZip_info.txt 14 | 15 | --------------------------------------------------------------------------------- 16 | 17 | Condition of use and distribution are the same than zlib : 18 | 19 | This software is provided 'as-is', without any express or implied 20 | warranty. In no event will the authors be held liable for any damages 21 | arising from the use of this software. 22 | 23 | Permission is granted to anyone to use this software for any purpose, 24 | including commercial applications, and to alter it and redistribute it 25 | freely, subject to the following restrictions: 26 | 27 | 1. The origin of this software must not be misrepresented; you must not 28 | claim that you wrote the original software. If you use this software 29 | in a product, an acknowledgment in the product documentation would be 30 | appreciated but is not required. 31 | 2. Altered source versions must be plainly marked as such, and must not be 32 | misrepresented as being the original software. 33 | 3. This notice may not be removed or altered from any source distribution. 34 | 35 | --------------------------------------------------------------------------------- 36 | */ 37 | 38 | #ifndef _unz64_H 39 | #define _unz64_H 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #ifndef _ZLIB_H 46 | #include "zlib.h" 47 | #endif 48 | 49 | #ifndef _ZLIBIOAPI_H 50 | #include "ioapi.h" 51 | #endif 52 | 53 | #ifdef HAVE_BZIP2 54 | #include "bzlib.h" 55 | #endif 56 | 57 | #define Z_BZIP2ED 12 58 | 59 | #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) 60 | /* like the STRICT of WIN32, we define a pointer that cannot be converted 61 | from (void*) without cast */ 62 | typedef struct TagunzFile__ { int unused; } unzFile__; 63 | typedef unzFile__ *unzFile; 64 | #else 65 | typedef voidp unzFile; 66 | #endif 67 | 68 | 69 | #define UNZ_OK (0) 70 | #define UNZ_END_OF_LIST_OF_FILE (-100) 71 | #define UNZ_ERRNO (Z_ERRNO) 72 | #define UNZ_EOF (0) 73 | #define UNZ_PARAMERROR (-102) 74 | #define UNZ_BADZIPFILE (-103) 75 | #define UNZ_INTERNALERROR (-104) 76 | #define UNZ_CRCERROR (-105) 77 | 78 | /* tm_unz contain date/time info */ 79 | typedef struct tm_unz_s 80 | { 81 | uInt tm_sec; /* seconds after the minute - [0,59] */ 82 | uInt tm_min; /* minutes after the hour - [0,59] */ 83 | uInt tm_hour; /* hours since midnight - [0,23] */ 84 | uInt tm_mday; /* day of the month - [1,31] */ 85 | uInt tm_mon; /* months since January - [0,11] */ 86 | uInt tm_year; /* years - [1980..2044] */ 87 | } tm_unz; 88 | 89 | /* unz_global_info structure contain global data about the ZIPfile 90 | These data comes from the end of central dir */ 91 | typedef struct unz_global_info64_s 92 | { 93 | ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ 94 | uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ 95 | uLong size_comment; /* size of the global comment of the zipfile */ 96 | } unz_global_info64; 97 | 98 | typedef struct unz_global_info_s 99 | { 100 | uLong number_entry; /* total number of entries in the central dir on this disk */ 101 | uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ 102 | uLong size_comment; /* size of the global comment of the zipfile */ 103 | } unz_global_info; 104 | 105 | /* unz_file_info contain information about a file in the zipfile */ 106 | typedef struct unz_file_info64_s 107 | { 108 | uLong version; /* version made by 2 bytes */ 109 | uLong version_needed; /* version needed to extract 2 bytes */ 110 | uLong flag; /* general purpose bit flag 2 bytes */ 111 | uLong compression_method; /* compression method 2 bytes */ 112 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ 113 | uLong crc; /* crc-32 4 bytes */ 114 | ZPOS64_T compressed_size; /* compressed size 8 bytes */ 115 | ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ 116 | uLong size_filename; /* filename length 2 bytes */ 117 | uLong size_file_extra; /* extra field length 2 bytes */ 118 | uLong size_file_comment; /* file comment length 2 bytes */ 119 | 120 | uLong disk_num_start; /* disk number start 2 bytes */ 121 | uLong internal_fa; /* internal file attributes 2 bytes */ 122 | uLong external_fa; /* external file attributes 4 bytes */ 123 | 124 | tm_unz tmu_date; 125 | ZPOS64_T disk_offset; 126 | uLong size_file_extra_internal; 127 | } unz_file_info64; 128 | 129 | typedef struct unz_file_info_s 130 | { 131 | uLong version; /* version made by 2 bytes */ 132 | uLong version_needed; /* version needed to extract 2 bytes */ 133 | uLong flag; /* general purpose bit flag 2 bytes */ 134 | uLong compression_method; /* compression method 2 bytes */ 135 | uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ 136 | uLong crc; /* crc-32 4 bytes */ 137 | uLong compressed_size; /* compressed size 4 bytes */ 138 | uLong uncompressed_size; /* uncompressed size 4 bytes */ 139 | uLong size_filename; /* filename length 2 bytes */ 140 | uLong size_file_extra; /* extra field length 2 bytes */ 141 | uLong size_file_comment; /* file comment length 2 bytes */ 142 | 143 | uLong disk_num_start; /* disk number start 2 bytes */ 144 | uLong internal_fa; /* internal file attributes 2 bytes */ 145 | uLong external_fa; /* external file attributes 4 bytes */ 146 | 147 | tm_unz tmu_date; 148 | uLong disk_offset; 149 | } unz_file_info; 150 | 151 | /***************************************************************************/ 152 | /* Opening and close a zip file */ 153 | 154 | extern unzFile ZEXPORT unzOpen OF((const char *path)); 155 | extern unzFile ZEXPORT unzOpen64 OF((const void *path)); 156 | /* Open a Zip file. 157 | 158 | path should contain the full pathname (by example, on a Windows XP computer 159 | "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". 160 | return NULL if zipfile cannot be opened or doesn't exist 161 | return unzFile handle if no error 162 | 163 | NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the 164 | open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path 165 | is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ 166 | 167 | extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); 168 | /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */ 169 | extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); 170 | /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */ 171 | 172 | extern int ZEXPORT unzClose OF((unzFile file)); 173 | /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile, 174 | these files MUST be closed with unzipCloseCurrentFile before call unzipClose. 175 | 176 | return UNZ_OK if there is no error */ 177 | 178 | extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); 179 | extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); 180 | /* Write info about the ZipFile in the *pglobal_info structure. 181 | 182 | return UNZ_OK if no error */ 183 | 184 | extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *comment, uLong comment_size)); 185 | /* Get the global comment string of the ZipFile, in the comment buffer. 186 | 187 | uSizeBuf is the size of the szComment buffer. 188 | return the number of byte copied or an error code <0 */ 189 | 190 | /***************************************************************************/ 191 | /* Reading the content of the current zipfile, you can open it, read data from it, and close it 192 | (you can close it before reading all the file) */ 193 | 194 | extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); 195 | /* Open for reading data the current file in the zipfile. 196 | 197 | return UNZ_OK if no error */ 198 | 199 | extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); 200 | /* Open for reading data the current file in the zipfile. 201 | password is a crypting password 202 | 203 | return UNZ_OK if no error */ 204 | 205 | extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); 206 | /* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress) 207 | if raw==1 *method will receive method of compression, *level will receive level of compression 208 | 209 | NOTE: you can set level parameter as NULL (if you did not want known level, 210 | but you CANNOT set method parameter as NULL */ 211 | 212 | extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); 213 | /* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */ 214 | 215 | extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); 216 | /* Read bytes from the current file (opened by unzOpenCurrentFile) 217 | buf contain buffer where data must be copied 218 | len the size of buf. 219 | 220 | return the number of byte copied if somes bytes are copied 221 | return 0 if the end of file was reached 222 | return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ 223 | 224 | extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *filename, 225 | uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); 226 | extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, 227 | uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); 228 | /* Get Info about the current file 229 | 230 | pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file 231 | filename if != NULL, the file name string will be copied in filename 232 | filename_size is the size of the filename buffer 233 | extrafield if != NULL, the extra field information from the central header will be copied in to 234 | extrafield_size is the size of the extraField buffer 235 | comment if != NULL, the comment string of the file will be copied in to 236 | comment_size is the size of the comment buffer */ 237 | 238 | extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); 239 | 240 | extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); 241 | /* Read extra field from the current file (opened by unzOpenCurrentFile) 242 | This is the local-header version of the extra field (sometimes, there is 243 | more info in the local-header version than in the central-header) 244 | 245 | if buf == NULL, it return the size of the local extra field 246 | if buf != NULL, len is the size of the buffer, the extra header is copied in buf. 247 | 248 | return number of bytes copied in buf, or (if <0) the error code */ 249 | 250 | extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); 251 | /* Close the file in zip opened with unzOpenCurrentFile 252 | 253 | return UNZ_CRCERROR if all the file was read but the CRC is not good */ 254 | 255 | /***************************************************************************/ 256 | /* Browse the directory of the zipfile */ 257 | 258 | typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2); 259 | typedef int (*unzIteratorFunction)(unzFile file); 260 | typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename, 261 | uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size); 262 | 263 | extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); 264 | /* Set the current file of the zipfile to the first file. 265 | 266 | return UNZ_OK if no error */ 267 | 268 | extern int ZEXPORT unzGoToFirstFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, 269 | uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); 270 | /* Set the current file of the zipfile to the first file and retrieves the current info on success. 271 | Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo. 272 | 273 | return UNZ_OK if no error */ 274 | 275 | extern int ZEXPORT unzGoToNextFile OF((unzFile file)); 276 | /* Set the current file of the zipfile to the next file. 277 | 278 | return UNZ_OK if no error 279 | return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ 280 | 281 | extern int ZEXPORT unzGoToNextFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, 282 | uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); 283 | /* Set the current file of the zipfile to the next file and retrieves the current 284 | info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo. 285 | 286 | return UNZ_OK if no error 287 | return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ 288 | 289 | extern int ZEXPORT unzLocateFile OF((unzFile file, const char *filename, unzFileNameComparer filename_compare_func)); 290 | /* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function. 291 | 292 | return UNZ_OK if the file is found (it becomes the current file) 293 | return UNZ_END_OF_LIST_OF_FILE if the file is not found */ 294 | 295 | /***************************************************************************/ 296 | /* Raw access to zip file */ 297 | 298 | typedef struct unz_file_pos_s 299 | { 300 | uLong pos_in_zip_directory; /* offset in zip file directory */ 301 | uLong num_of_file; /* # of file */ 302 | } unz_file_pos; 303 | 304 | extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos)); 305 | extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos)); 306 | 307 | typedef struct unz64_file_pos_s 308 | { 309 | ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ 310 | ZPOS64_T num_of_file; /* # of file */ 311 | } unz64_file_pos; 312 | 313 | extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos)); 314 | extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos)); 315 | 316 | extern uLong ZEXPORT unzGetOffset OF((unzFile file)); 317 | extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file)); 318 | /* Get the current file offset */ 319 | 320 | extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos)); 321 | extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos)); 322 | /* Set the current file offset */ 323 | 324 | extern z_off_t ZEXPORT unztell OF((unzFile file)); 325 | extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); 326 | /* return current position in uncompressed data */ 327 | 328 | extern int ZEXPORT unzeof OF((unzFile file)); 329 | /* return 1 if the end of file was reached, 0 elsewhere */ 330 | 331 | /***************************************************************************/ 332 | 333 | #ifdef __cplusplus 334 | } 335 | #endif 336 | 337 | #endif /* _unz64_H */ 338 | -------------------------------------------------------------------------------- /app/src/main/cpp/include/zip.h: -------------------------------------------------------------------------------- 1 | /* zip.h -- IO on .zip files using zlib 2 | Version 1.1, February 14h, 2010 3 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 4 | 5 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 6 | 7 | Modifications for Zip64 support 8 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 9 | 10 | For more info read MiniZip_info.txt 11 | 12 | --------------------------------------------------------------------------- 13 | 14 | Condition of use and distribution are the same than zlib : 15 | 16 | This software is provided 'as-is', without any express or implied 17 | warranty. In no event will the authors be held liable for any damages 18 | arising from the use of this software. 19 | 20 | Permission is granted to anyone to use this software for any purpose, 21 | including commercial applications, and to alter it and redistribute it 22 | freely, subject to the following restrictions: 23 | 24 | 1. The origin of this software must not be misrepresented; you must not 25 | claim that you wrote the original software. If you use this software 26 | in a product, an acknowledgment in the product documentation would be 27 | appreciated but is not required. 28 | 2. Altered source versions must be plainly marked as such, and must not be 29 | misrepresented as being the original software. 30 | 3. This notice may not be removed or altered from any source distribution. 31 | 32 | --------------------------------------------------------------------------- 33 | */ 34 | 35 | #ifndef _zip12_H 36 | #define _zip12_H 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #ifndef _ZLIB_H 43 | #include "zlib.h" 44 | #endif 45 | 46 | #ifndef _ZLIBIOAPI_H 47 | #include "ioapi.h" 48 | #endif 49 | 50 | #ifdef HAVE_BZIP2 51 | #include "bzlib.h" 52 | #endif 53 | 54 | #define Z_BZIP2ED 12 55 | 56 | #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) 57 | /* like the STRICT of WIN32, we define a pointer that cannot be converted 58 | from (void*) without cast */ 59 | typedef struct TagzipFile__ { int unused; } zipFile__; 60 | typedef zipFile__ *zipFile; 61 | #else 62 | typedef voidp zipFile; 63 | #endif 64 | 65 | #define ZIP_OK (0) 66 | #define ZIP_EOF (0) 67 | #define ZIP_ERRNO (Z_ERRNO) 68 | #define ZIP_PARAMERROR (-102) 69 | #define ZIP_BADZIPFILE (-103) 70 | #define ZIP_INTERNALERROR (-104) 71 | 72 | #ifndef DEF_MEM_LEVEL 73 | # if MAX_MEM_LEVEL >= 8 74 | # define DEF_MEM_LEVEL 8 75 | # else 76 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL 77 | # endif 78 | #endif 79 | /* default memLevel */ 80 | 81 | /* tm_zip contain date/time info */ 82 | typedef struct tm_zip_s 83 | { 84 | uInt tm_sec; /* seconds after the minute - [0,59] */ 85 | uInt tm_min; /* minutes after the hour - [0,59] */ 86 | uInt tm_hour; /* hours since midnight - [0,23] */ 87 | uInt tm_mday; /* day of the month - [1,31] */ 88 | uInt tm_mon; /* months since January - [0,11] */ 89 | uInt tm_year; /* years - [1980..2044] */ 90 | } tm_zip; 91 | 92 | typedef struct 93 | { 94 | tm_zip tmz_date; /* date in understandable format */ 95 | uLong dosDate; /* if dos_date == 0, tmu_date is used */ 96 | uLong internal_fa; /* internal file attributes 2 bytes */ 97 | uLong external_fa; /* external file attributes 4 bytes */ 98 | } zip_fileinfo; 99 | 100 | typedef const char* zipcharpc; 101 | 102 | #define APPEND_STATUS_CREATE (0) 103 | #define APPEND_STATUS_CREATEAFTER (1) 104 | #define APPEND_STATUS_ADDINZIP (2) 105 | 106 | /***************************************************************************/ 107 | /* Writing a zip file */ 108 | 109 | extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); 110 | extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); 111 | /* Create a zipfile. 112 | 113 | pathname should contain the full pathname (by example, on a Windows XP computer 114 | "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". 115 | 116 | return NULL if zipfile cannot be opened 117 | return zipFile handle if no error 118 | 119 | If the file pathname exist and append == APPEND_STATUS_CREATEAFTER, the zip 120 | will be created at the end of the file. (useful if the file contain a self extractor code) 121 | If the file pathname exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing 122 | zip (be sure you don't add file that doesn't exist) 123 | 124 | NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, 125 | you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy 126 | the file you did not want delete. */ 127 | 128 | extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, 129 | zlib_filefunc_def* pzlib_filefunc_def)); 130 | 131 | extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, 132 | zlib_filefunc64_def* pzlib_filefunc_def)); 133 | 134 | extern zipFile ZEXPORT zipOpen3 OF((const char *pathname, int append, ZPOS64_T disk_size, 135 | zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); 136 | /* Same as zipOpen2 but allows specification of spanned zip size */ 137 | 138 | extern zipFile ZEXPORT zipOpen3_64 OF((const void *pathname, int append, ZPOS64_T disk_size, 139 | zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); 140 | 141 | extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 142 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 143 | uInt size_extrafield_global, const char* comment, int method, int level)); 144 | /* Open a file in the ZIP for writing. 145 | 146 | filename : the filename in zip (if NULL, '-' without quote will be used 147 | *zipfi contain supplemental information 148 | extrafield_local buffer to store the local header extra field data, can be NULL 149 | size_extrafield_local size of extrafield_local buffer 150 | extrafield_global buffer to store the global header extra field data, can be NULL 151 | size_extrafield_global size of extrafield_local buffer 152 | comment buffer for comment string 153 | method contain the compression method (0 for store, Z_DEFLATED for deflate) 154 | level contain the level of compression (can be Z_DEFAULT_COMPRESSION) 155 | zip64 is set to 1 if a zip64 extended information block should be added to the local file header. 156 | this MUST be '1' if the uncompressed size is >= 0xffffffff. */ 157 | 158 | extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 159 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 160 | uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); 161 | /* Same as zipOpenNewFileInZip with zip64 support */ 162 | 163 | extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 164 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 165 | uInt size_extrafield_global, const char* comment, int method, int level, int raw)); 166 | /* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */ 167 | 168 | extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 169 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 170 | uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); 171 | /* Same as zipOpenNewFileInZip3 with zip64 support */ 172 | 173 | extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 174 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 175 | uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, 176 | int strategy, const char* password, uLong crcForCrypting)); 177 | /* Same as zipOpenNewFileInZip2, except 178 | windowBits, memLevel, strategy : see parameter strategy in deflateInit2 179 | password : crypting password (NULL for no crypting) 180 | crcForCrypting : crc of file to compress (needed for crypting) */ 181 | 182 | extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 183 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 184 | uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, 185 | int strategy, const char* password, uLong crcForCrypting, int zip64)); 186 | /* Same as zipOpenNewFileInZip3 with zip64 support */ 187 | 188 | extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 189 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 190 | uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, 191 | int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase)); 192 | /* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */ 193 | 194 | extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, 195 | const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, 196 | uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, 197 | int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64)); 198 | /* Same as zipOpenNewFileInZip4 with zip64 support */ 199 | 200 | extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); 201 | /* Write data in the zipfile */ 202 | 203 | extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); 204 | /* Close the current file in the zipfile */ 205 | 206 | extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); 207 | extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); 208 | /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 209 | uncompressed_size and crc32 are value for the uncompressed size */ 210 | 211 | extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); 212 | /* Close the zipfile */ 213 | 214 | /***************************************************************************/ 215 | 216 | #ifdef __cplusplus 217 | } 218 | #endif 219 | 220 | #endif /* _zip64_H */ 221 | -------------------------------------------------------------------------------- /app/src/main/cpp/ioapi.c: -------------------------------------------------------------------------------- 1 | /* ioapi.h -- IO base function header for compress/uncompress .zip 2 | part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) 3 | 4 | Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) 5 | 6 | Modifications for Zip64 support 7 | Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) 8 | 9 | For more info read MiniZip_info.txt 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #include "ioapi.h" 16 | 17 | #if (defined(_WIN32)) 18 | #include 19 | #define snprintf _snprintf 20 | #ifndef _CRT_SECURE_NO_WARNINGS 21 | #define _CRT_SECURE_NO_WARNINGS 22 | #endif 23 | #endif 24 | 25 | #if defined(__APPLE__) || defined(IOAPI_NO_64) 26 | // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions 27 | #define FOPEN_FUNC(filename, mode) fopen(filename, mode) 28 | #define FTELLO_FUNC(stream) ftello(stream) 29 | #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) 30 | #else 31 | #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) 32 | #define FTELLO_FUNC(stream) ftello64(stream) 33 | #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) 34 | #endif 35 | 36 | /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ 37 | #ifndef SEEK_CUR 38 | #define SEEK_CUR 1 39 | #endif 40 | #ifndef SEEK_END 41 | #define SEEK_END 2 42 | #endif 43 | #ifndef SEEK_SET 44 | #define SEEK_SET 0 45 | #endif 46 | 47 | voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) 48 | { 49 | if (pfilefunc->zfile_func64.zopen64_file != NULL) 50 | return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); 51 | return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); 52 | } 53 | 54 | voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)) 55 | { 56 | if (pfilefunc->zfile_func64.zopendisk64_file != NULL) 57 | return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); 58 | return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); 59 | } 60 | 61 | long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) 62 | { 63 | uLong offsetTruncated; 64 | if (pfilefunc->zfile_func64.zseek64_file != NULL) 65 | return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); 66 | offsetTruncated = (uLong)offset; 67 | if (offsetTruncated != offset) 68 | return -1; 69 | return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); 70 | } 71 | 72 | ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) 73 | { 74 | uLong tell_uLong; 75 | if (pfilefunc->zfile_func64.zseek64_file != NULL) 76 | return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); 77 | tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); 78 | if ((tell_uLong) == 0xffffffff) 79 | return (ZPOS64_T)-1; 80 | return tell_uLong; 81 | } 82 | 83 | void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) 84 | { 85 | p_filefunc64_32->zfile_func64.zopen64_file = NULL; 86 | p_filefunc64_32->zfile_func64.zopendisk64_file = NULL; 87 | p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; 88 | p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file; 89 | p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; 90 | p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; 91 | p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; 92 | p_filefunc64_32->zfile_func64.ztell64_file = NULL; 93 | p_filefunc64_32->zfile_func64.zseek64_file = NULL; 94 | p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; 95 | p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; 96 | p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; 97 | p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; 98 | p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; 99 | } 100 | 101 | static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); 102 | static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); 103 | static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); 104 | static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); 105 | static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); 106 | static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); 107 | static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); 108 | 109 | typedef struct 110 | { 111 | FILE *file; 112 | int filenameLength; 113 | void *filename; 114 | } FILE_IOPOSIX; 115 | 116 | 117 | static voidpf file_build_ioposix(FILE *file, const char *filename) 118 | { 119 | FILE_IOPOSIX *ioposix = NULL; 120 | if (file == NULL) 121 | return NULL; 122 | ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX)); 123 | ioposix->file = file; 124 | ioposix->filenameLength = strlen(filename) + 1; 125 | ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char)); 126 | strncpy(ioposix->filename, filename, ioposix->filenameLength); 127 | return (voidpf)ioposix; 128 | } 129 | 130 | static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) 131 | { 132 | FILE* file = NULL; 133 | const char* mode_fopen = NULL; 134 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 135 | mode_fopen = "rb"; 136 | else 137 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 138 | mode_fopen = "r+b"; 139 | else 140 | if (mode & ZLIB_FILEFUNC_MODE_CREATE) 141 | mode_fopen = "wb"; 142 | 143 | if ((filename != NULL) && (mode_fopen != NULL)) 144 | { 145 | file = fopen(filename, mode_fopen); 146 | return file_build_ioposix(file, filename); 147 | } 148 | return file; 149 | } 150 | 151 | static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) 152 | { 153 | FILE* file = NULL; 154 | const char* mode_fopen = NULL; 155 | if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 156 | mode_fopen = "rb"; 157 | else 158 | if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 159 | mode_fopen = "r+b"; 160 | else 161 | if (mode & ZLIB_FILEFUNC_MODE_CREATE) 162 | mode_fopen = "wb"; 163 | 164 | if ((filename != NULL) && (mode_fopen != NULL)) 165 | { 166 | file = FOPEN_FUNC((const char*)filename, mode_fopen); 167 | return file_build_ioposix(file, (const char*)filename); 168 | } 169 | return file; 170 | } 171 | 172 | static voidpf ZCALLBACK fopendisk64_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) 173 | { 174 | FILE_IOPOSIX *ioposix = NULL; 175 | char *diskFilename = NULL; 176 | voidpf ret = NULL; 177 | int i = 0; 178 | 179 | if (stream == NULL) 180 | return NULL; 181 | ioposix = (FILE_IOPOSIX*)stream; 182 | diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); 183 | strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); 184 | for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) 185 | { 186 | if (diskFilename[i] != '.') 187 | continue; 188 | snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); 189 | break; 190 | } 191 | if (i >= 0) 192 | ret = fopen64_file_func(opaque, diskFilename, mode); 193 | free(diskFilename); 194 | return ret; 195 | } 196 | 197 | static voidpf ZCALLBACK fopendisk_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) 198 | { 199 | FILE_IOPOSIX *ioposix = NULL; 200 | char *diskFilename = NULL; 201 | voidpf ret = NULL; 202 | int i = 0; 203 | 204 | if (stream == NULL) 205 | return NULL; 206 | ioposix = (FILE_IOPOSIX*)stream; 207 | diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); 208 | strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); 209 | for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) 210 | { 211 | if (diskFilename[i] != '.') 212 | continue; 213 | snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); 214 | break; 215 | } 216 | if (i >= 0) 217 | ret = fopen_file_func(opaque, diskFilename, mode); 218 | free(diskFilename); 219 | return ret; 220 | } 221 | 222 | static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) 223 | { 224 | FILE_IOPOSIX *ioposix = NULL; 225 | uLong ret; 226 | if (stream == NULL) 227 | return -1; 228 | ioposix = (FILE_IOPOSIX*)stream; 229 | ret = (uLong)fread(buf, 1, (size_t)size, ioposix->file); 230 | return ret; 231 | } 232 | 233 | static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) 234 | { 235 | FILE_IOPOSIX *ioposix = NULL; 236 | uLong ret; 237 | if (stream == NULL) 238 | return -1; 239 | ioposix = (FILE_IOPOSIX*)stream; 240 | ret = (uLong)fwrite(buf, 1, (size_t)size, ioposix->file); 241 | return ret; 242 | } 243 | 244 | static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) 245 | { 246 | FILE_IOPOSIX *ioposix = NULL; 247 | long ret = -1; 248 | if (stream == NULL) 249 | return ret; 250 | ioposix = (FILE_IOPOSIX*)stream; 251 | ret = ftell(ioposix->file); 252 | return ret; 253 | } 254 | 255 | static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) 256 | { 257 | FILE_IOPOSIX *ioposix = NULL; 258 | ZPOS64_T ret = -1; 259 | if (stream == NULL) 260 | return ret; 261 | ioposix = (FILE_IOPOSIX*)stream; 262 | ret = FTELLO_FUNC(ioposix->file); 263 | return ret; 264 | } 265 | 266 | static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) 267 | { 268 | FILE_IOPOSIX *ioposix = NULL; 269 | int fseek_origin = 0; 270 | long ret; 271 | 272 | if (stream == NULL) 273 | return -1; 274 | ioposix = (FILE_IOPOSIX*)stream; 275 | 276 | switch (origin) 277 | { 278 | case ZLIB_FILEFUNC_SEEK_CUR: 279 | fseek_origin = SEEK_CUR; 280 | break; 281 | case ZLIB_FILEFUNC_SEEK_END: 282 | fseek_origin = SEEK_END; 283 | break; 284 | case ZLIB_FILEFUNC_SEEK_SET: 285 | fseek_origin = SEEK_SET; 286 | break; 287 | default: return -1; 288 | } 289 | ret = 0; 290 | if (fseek(ioposix->file, offset, fseek_origin) != 0) 291 | ret = -1; 292 | return ret; 293 | } 294 | 295 | static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) 296 | { 297 | FILE_IOPOSIX *ioposix = NULL; 298 | int fseek_origin = 0; 299 | long ret; 300 | 301 | if (stream == NULL) 302 | return -1; 303 | ioposix = (FILE_IOPOSIX*)stream; 304 | 305 | switch (origin) 306 | { 307 | case ZLIB_FILEFUNC_SEEK_CUR: 308 | fseek_origin = SEEK_CUR; 309 | break; 310 | case ZLIB_FILEFUNC_SEEK_END: 311 | fseek_origin = SEEK_END; 312 | break; 313 | case ZLIB_FILEFUNC_SEEK_SET: 314 | fseek_origin = SEEK_SET; 315 | break; 316 | default: return -1; 317 | } 318 | ret = 0; 319 | 320 | if(FSEEKO_FUNC(ioposix->file, offset, fseek_origin) != 0) 321 | ret = -1; 322 | 323 | return ret; 324 | } 325 | 326 | 327 | static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) 328 | { 329 | FILE_IOPOSIX *ioposix = NULL; 330 | int ret = -1; 331 | if (stream == NULL) 332 | return ret; 333 | ioposix = (FILE_IOPOSIX*)stream; 334 | if (ioposix->filename != NULL) 335 | free(ioposix->filename); 336 | ret = fclose(ioposix->file); 337 | free(ioposix); 338 | return ret; 339 | } 340 | 341 | static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) 342 | { 343 | FILE_IOPOSIX *ioposix = NULL; 344 | int ret = -1; 345 | if (stream == NULL) 346 | return ret; 347 | ioposix = (FILE_IOPOSIX*)stream; 348 | ret = ferror(ioposix->file); 349 | return ret; 350 | } 351 | 352 | void fill_fopen_filefunc (pzlib_filefunc_def) 353 | zlib_filefunc_def* pzlib_filefunc_def; 354 | { 355 | pzlib_filefunc_def->zopen_file = fopen_file_func; 356 | pzlib_filefunc_def->zopendisk_file = fopendisk_file_func; 357 | pzlib_filefunc_def->zread_file = fread_file_func; 358 | pzlib_filefunc_def->zwrite_file = fwrite_file_func; 359 | pzlib_filefunc_def->ztell_file = ftell_file_func; 360 | pzlib_filefunc_def->zseek_file = fseek_file_func; 361 | pzlib_filefunc_def->zclose_file = fclose_file_func; 362 | pzlib_filefunc_def->zerror_file = ferror_file_func; 363 | pzlib_filefunc_def->opaque = NULL; 364 | } 365 | 366 | void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) 367 | { 368 | pzlib_filefunc_def->zopen64_file = fopen64_file_func; 369 | pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func; 370 | pzlib_filefunc_def->zread_file = fread_file_func; 371 | pzlib_filefunc_def->zwrite_file = fwrite_file_func; 372 | pzlib_filefunc_def->ztell64_file = ftell64_file_func; 373 | pzlib_filefunc_def->zseek64_file = fseek64_file_func; 374 | pzlib_filefunc_def->zclose_file = fclose_file_func; 375 | pzlib_filefunc_def->zerror_file = ferror_file_func; 376 | pzlib_filefunc_def->opaque = NULL; 377 | } 378 | -------------------------------------------------------------------------------- /app/src/main/cpp/ioapi_buf.c: -------------------------------------------------------------------------------- 1 | /* ioapi_buf.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | This version of ioapi is designed to buffer IO. 5 | 6 | Based on Unzip ioapi.c version 0.22, May 19th, 2003 7 | 8 | Copyright (C) 1998-2003 Gilles Vollant 9 | (C) 2003 Justin Fletcher 10 | (C) 2012 Nathan Moinvaziri 11 | 12 | This file is under the same license as the Unzip tool it is distributed 13 | with. 14 | */ 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "zlib.h" 23 | #include "ioapi.h" 24 | 25 | #include "ioapi_buf.h" 26 | 27 | #if defined(_WIN32) 28 | #include 29 | #define PRINTF _cprintf 30 | #define VPRINTF _vcprintf 31 | #else 32 | #define PRINTF printf 33 | #define VPRINTF vprintf 34 | #endif 35 | 36 | //#define IOBUF_VERBOSE 37 | 38 | #ifdef __GNUC__ 39 | #ifndef max 40 | #define max(x,y) ({ \ 41 | const typeof(x) _x = (x); \ 42 | const typeof(y) _y = (y); \ 43 | (void) (&_x == &_y); \ 44 | _x > _y ? _x : _y; }) 45 | #endif /* __GNUC__ */ 46 | 47 | #ifndef min 48 | #define min(x,y) ({ \ 49 | const typeof(x) _x = (x); \ 50 | const typeof(y) _y = (y); \ 51 | (void) (&_x == &_y); \ 52 | _x < _y ? _x : _y; }) 53 | #endif 54 | #endif 55 | 56 | typedef struct ourstream_s { 57 | char readBuffer[IOBUF_BUFFERSIZE]; 58 | uInt readBufferLength; 59 | uInt readBufferPos; 60 | uInt readBufferHits; 61 | uInt readBufferMisses; 62 | char writeBuffer[IOBUF_BUFFERSIZE]; 63 | uInt writeBufferLength; 64 | uInt writeBufferPos; 65 | uInt writeBufferHits; 66 | uInt writeBufferMisses; 67 | ZPOS64_T position; 68 | voidpf stream; 69 | } ourstream_t; 70 | 71 | #if defined(IOBUF_VERBOSE) 72 | #define print_buf(o,s,f,...) print_buf_internal(o,s,f,__VA_ARGS__); 73 | #else 74 | #define print_buf(o,s,f,...) 75 | #endif 76 | 77 | void print_buf_internal(voidpf opaque, voidpf stream, char *format, ...) 78 | { 79 | ourstream_t *streamio = (ourstream_t *)stream; 80 | va_list arglist; 81 | PRINTF("Buf stream %p - ", streamio); 82 | va_start(arglist, format); 83 | VPRINTF(format, arglist); 84 | va_end(arglist); 85 | } 86 | 87 | voidpf fopen_buf_internal_func (opaque, stream, number_disk, mode) 88 | voidpf opaque; 89 | voidpf stream; 90 | int number_disk; 91 | int mode; 92 | { 93 | ourstream_t *streamio = NULL; 94 | if (stream == NULL) 95 | return NULL; 96 | streamio = (ourstream_t *)malloc(sizeof(ourstream_t)); 97 | if (streamio == NULL) 98 | return NULL; 99 | memset(streamio, 0, sizeof(ourstream_t)); 100 | streamio->stream = stream; 101 | print_buf(opaque, streamio, "open [num %d mode %d]\n", number_disk, mode); 102 | return streamio; 103 | } 104 | 105 | voidpf ZCALLBACK fopen_buf_func (opaque, filename, mode) 106 | voidpf opaque; 107 | const char* filename; 108 | int mode; 109 | { 110 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 111 | voidpf stream = bufio->filefunc.zopen_file(bufio->filefunc.opaque, filename, mode); 112 | return fopen_buf_internal_func(opaque, stream, 0, mode); 113 | } 114 | 115 | voidpf ZCALLBACK fopen64_buf_func (opaque, filename, mode) 116 | voidpf opaque; 117 | const char* filename; 118 | int mode; 119 | { 120 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 121 | voidpf stream = bufio->filefunc64.zopen64_file(bufio->filefunc64.opaque, filename, mode); 122 | return fopen_buf_internal_func(opaque, stream, 0, mode); 123 | } 124 | 125 | voidpf ZCALLBACK fopendisk_buf_func (opaque, stream_cd, number_disk, mode) 126 | voidpf opaque; 127 | voidpf stream_cd; 128 | int number_disk; 129 | int mode; 130 | { 131 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 132 | ourstream_t *streamio = (ourstream_t *)stream_cd; 133 | voidpf *stream = bufio->filefunc.zopendisk_file(bufio->filefunc.opaque, streamio->stream, number_disk, mode); 134 | return fopen_buf_internal_func(opaque, stream, number_disk, mode); 135 | } 136 | 137 | voidpf ZCALLBACK fopendisk64_buf_func (opaque, stream_cd, number_disk, mode) 138 | voidpf opaque; 139 | voidpf stream_cd; 140 | int number_disk; 141 | int mode; 142 | { 143 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 144 | ourstream_t *streamio = (ourstream_t *)stream_cd; 145 | voidpf stream = bufio->filefunc64.zopendisk64_file(bufio->filefunc64.opaque, streamio->stream, number_disk, mode); 146 | return fopen_buf_internal_func(opaque, stream, number_disk, mode); 147 | } 148 | 149 | long fflush_buf OF((voidpf opaque, voidpf stream)); 150 | long fflush_buf (opaque, stream) 151 | voidpf opaque; 152 | voidpf stream; 153 | { 154 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 155 | ourstream_t *streamio = (ourstream_t *)stream; 156 | uInt totalBytesWritten = 0; 157 | uInt bytesToWrite = streamio->writeBufferLength; 158 | uInt bytesLeftToWrite = streamio->writeBufferLength; 159 | int bytesWritten = 0; 160 | 161 | while (bytesLeftToWrite > 0) 162 | { 163 | if (bufio->filefunc64.zwrite_file != NULL) 164 | bytesWritten = bufio->filefunc64.zwrite_file(bufio->filefunc64.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); 165 | else 166 | bytesWritten = bufio->filefunc.zwrite_file(bufio->filefunc.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); 167 | 168 | streamio->writeBufferMisses += 1; 169 | 170 | print_buf(opaque, stream, "write flush [%d:%d len %d]\n", bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); 171 | 172 | if (bytesWritten < 0) 173 | return bytesWritten; 174 | 175 | totalBytesWritten += bytesWritten; 176 | bytesLeftToWrite -= bytesWritten; 177 | streamio->position += bytesWritten; 178 | } 179 | streamio->writeBufferLength = 0; 180 | streamio->writeBufferPos = 0; 181 | return totalBytesWritten; 182 | } 183 | 184 | uLong ZCALLBACK fread_buf_func (opaque, stream, buf, size) 185 | voidpf opaque; 186 | voidpf stream; 187 | void* buf; 188 | uLong size; 189 | { 190 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 191 | ourstream_t *streamio = (ourstream_t *)stream; 192 | uInt bytesToRead = 0; 193 | uInt bufLength = 0; 194 | uInt bytesToCopy = 0; 195 | uInt bytesLeftToRead = size; 196 | uInt bytesRead = -1; 197 | 198 | print_buf(opaque, stream, "read [size %ld pos %lld]\n", size, streamio->position); 199 | 200 | if (streamio->writeBufferLength > 0) 201 | { 202 | print_buf(opaque, stream, "switch from write to read, not yet supported [%lld]\n", streamio->position); 203 | } 204 | 205 | while (bytesLeftToRead > 0) 206 | { 207 | if ((streamio->readBufferLength == 0) || (streamio->readBufferPos == streamio->readBufferLength)) 208 | { 209 | if (streamio->readBufferLength == IOBUF_BUFFERSIZE) 210 | { 211 | streamio->readBufferPos = 0; 212 | streamio->readBufferLength = 0; 213 | } 214 | 215 | bytesToRead = IOBUF_BUFFERSIZE -(streamio->readBufferLength - streamio->readBufferPos); 216 | 217 | if (bufio->filefunc64.zread_file != NULL) 218 | bytesRead = bufio->filefunc64.zread_file(bufio->filefunc64.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); 219 | else 220 | bytesRead = bufio->filefunc.zread_file(bufio->filefunc.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); 221 | 222 | streamio->readBufferMisses += 1; 223 | streamio->readBufferLength += bytesRead; 224 | streamio->position += bytesRead; 225 | 226 | print_buf(opaque, stream, "filled [read %d/%d buf %d:%d pos %lld]\n", bytesRead, bytesToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); 227 | 228 | if (bytesRead == 0) 229 | break; 230 | } 231 | 232 | if ((streamio->readBufferLength - streamio->readBufferPos) > 0) 233 | { 234 | bytesToCopy = min(bytesLeftToRead, (streamio->readBufferLength - streamio->readBufferPos)); 235 | memcpy((char *)buf + bufLength, streamio->readBuffer + streamio->readBufferPos, bytesToCopy); 236 | 237 | bufLength += bytesToCopy; 238 | bytesLeftToRead -= bytesToCopy; 239 | 240 | streamio->readBufferHits += 1; 241 | streamio->readBufferPos += bytesToCopy; 242 | 243 | print_buf(opaque, stream, "emptied [copied %d remaining %d buf %d:%d pos %lld]\n", bytesToCopy, bytesLeftToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); 244 | } 245 | } 246 | 247 | return size - bytesLeftToRead; 248 | } 249 | 250 | uLong ZCALLBACK fwrite_buf_func (opaque, stream, buf, size) 251 | voidpf opaque; 252 | voidpf stream; 253 | const void* buf; 254 | uLong size; 255 | { 256 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 257 | ourstream_t *streamio = (ourstream_t *)stream; 258 | uInt bytesToWrite = size; 259 | uInt bytesLeftToWrite = size; 260 | uInt bytesToCopy = 0; 261 | int retVal = 0; 262 | 263 | print_buf(opaque, stream, "write [size %ld len %d pos %lld]\n", size, streamio->writeBufferLength, streamio->position); 264 | 265 | if (streamio->readBufferLength > 0) 266 | { 267 | streamio->position -= streamio->readBufferLength; 268 | streamio->position += streamio->readBufferPos; 269 | 270 | streamio->readBufferLength = 0; 271 | streamio->readBufferPos = 0; 272 | 273 | print_buf(opaque, stream, "switch from read to write [%lld]\n", streamio->position); 274 | 275 | if (bufio->filefunc64.zseek64_file != NULL) 276 | retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, streamio->position, ZLIB_FILEFUNC_SEEK_SET); 277 | else 278 | retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, (uLong)streamio->position, ZLIB_FILEFUNC_SEEK_SET); 279 | 280 | if (retVal != 0) 281 | return -1; 282 | } 283 | 284 | while (bytesLeftToWrite > 0) 285 | { 286 | if (streamio->writeBufferLength == IOBUF_BUFFERSIZE) 287 | { 288 | if (fflush_buf(opaque, stream) < 0) 289 | return 0; 290 | } 291 | 292 | bytesToCopy = min(bytesLeftToWrite, (IOBUF_BUFFERSIZE - min(streamio->writeBufferLength, streamio->writeBufferPos))); 293 | memcpy(streamio->writeBuffer + streamio->writeBufferPos, (char *)buf + (bytesToWrite - bytesLeftToWrite), bytesToCopy); 294 | 295 | print_buf(opaque, stream, "write copy [remaining %d write %d:%d len %d]\n", bytesToCopy, bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); 296 | 297 | bytesLeftToWrite -= bytesToCopy; 298 | 299 | streamio->writeBufferPos += bytesToCopy; 300 | streamio->writeBufferHits += 1; 301 | if (streamio->writeBufferPos > streamio->writeBufferLength) 302 | streamio->writeBufferLength += streamio->writeBufferPos - streamio->writeBufferLength; 303 | } 304 | 305 | return size - bytesLeftToWrite; 306 | } 307 | 308 | ZPOS64_T ftell_buf_internal_func (opaque, stream, position) 309 | voidpf opaque; 310 | voidpf stream; 311 | ZPOS64_T position; 312 | { 313 | ourstream_t *streamio = (ourstream_t *)stream; 314 | streamio->position = position; 315 | print_buf(opaque, stream, "tell [pos %llu readpos %d writepos %d err %d]\n", streamio->position, streamio->readBufferPos, streamio->writeBufferPos, errno); 316 | if (streamio->readBufferLength > 0) 317 | position -= (streamio->readBufferLength - streamio->readBufferPos); 318 | if (streamio->writeBufferLength > 0) 319 | position += streamio->writeBufferPos; 320 | return position; 321 | } 322 | 323 | long ZCALLBACK ftell_buf_func (opaque, stream) 324 | voidpf opaque; 325 | voidpf stream; 326 | { 327 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 328 | ourstream_t *streamio = (ourstream_t *)stream; 329 | ZPOS64_T position = bufio->filefunc.ztell_file(bufio->filefunc.opaque, streamio->stream); 330 | return (long)ftell_buf_internal_func(opaque, stream, position); 331 | } 332 | 333 | ZPOS64_T ZCALLBACK ftell64_buf_func (opaque, stream) 334 | voidpf opaque; 335 | voidpf stream; 336 | { 337 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 338 | ourstream_t *streamio = (ourstream_t *)stream; 339 | ZPOS64_T position = bufio->filefunc64.ztell64_file(bufio->filefunc64.opaque, streamio->stream); 340 | return ftell_buf_internal_func(opaque, stream, position); 341 | } 342 | 343 | int fseek_buf_internal_func (opaque, stream, offset, origin) 344 | voidpf opaque; 345 | voidpf stream; 346 | ZPOS64_T offset; 347 | int origin; 348 | { 349 | ourstream_t *streamio = (ourstream_t *)stream; 350 | 351 | print_buf(opaque, stream, "seek [origin %d offset %llu pos %lld]\n", origin, offset, streamio->position); 352 | 353 | switch (origin) 354 | { 355 | case ZLIB_FILEFUNC_SEEK_SET: 356 | 357 | if (streamio->writeBufferLength > 0) 358 | { 359 | if ((offset >= streamio->position) && (offset <= streamio->position + streamio->writeBufferLength)) 360 | { 361 | streamio->writeBufferPos = (uLong)(offset - streamio->position); 362 | return 0; 363 | } 364 | } 365 | if ((streamio->readBufferLength > 0) && (offset < streamio->position) && (offset >= streamio->position - streamio->readBufferLength)) 366 | { 367 | streamio->readBufferPos = (uLong)(offset - (streamio->position - streamio->readBufferLength)); 368 | return 0; 369 | } 370 | if (fflush_buf(opaque, stream) < 0) 371 | return -1; 372 | streamio->position = offset; 373 | break; 374 | 375 | case ZLIB_FILEFUNC_SEEK_CUR: 376 | 377 | if (streamio->readBufferLength > 0) 378 | { 379 | if (offset <= (streamio->readBufferLength - streamio->readBufferPos)) 380 | { 381 | streamio->readBufferPos += (uLong)offset; 382 | return 0; 383 | } 384 | offset -= (streamio->readBufferLength - streamio->readBufferPos); 385 | streamio->position += offset; 386 | } 387 | if (streamio->writeBufferLength > 0) 388 | { 389 | if (offset <= (streamio->writeBufferLength - streamio->writeBufferPos)) 390 | { 391 | streamio->writeBufferPos += (uLong)offset; 392 | return 0; 393 | } 394 | offset -= (streamio->writeBufferLength - streamio->writeBufferPos); 395 | } 396 | 397 | if (fflush_buf(opaque, stream) < 0) 398 | return -1; 399 | 400 | break; 401 | 402 | case ZLIB_FILEFUNC_SEEK_END: 403 | 404 | if (streamio->writeBufferLength > 0) 405 | { 406 | streamio->writeBufferPos = streamio->writeBufferLength; 407 | return 0; 408 | } 409 | break; 410 | } 411 | 412 | streamio->readBufferLength = 0; 413 | streamio->readBufferPos = 0; 414 | streamio->writeBufferLength = 0; 415 | streamio->writeBufferPos = 0; 416 | return 1; 417 | } 418 | 419 | long ZCALLBACK fseek_buf_func (opaque, stream, offset, origin) 420 | voidpf opaque; 421 | voidpf stream; 422 | uLong offset; 423 | int origin; 424 | { 425 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 426 | ourstream_t *streamio = (ourstream_t *)stream; 427 | int retVal = -1; 428 | if (bufio->filefunc.zseek_file == NULL) 429 | return retVal; 430 | retVal = fseek_buf_internal_func(opaque, stream, offset, origin); 431 | if (retVal == 1) 432 | retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, offset, origin); 433 | return retVal; 434 | } 435 | 436 | long ZCALLBACK fseek64_buf_func (opaque, stream, offset, origin) 437 | voidpf opaque; 438 | voidpf stream; 439 | ZPOS64_T offset; 440 | int origin; 441 | { 442 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 443 | ourstream_t *streamio = (ourstream_t *)stream; 444 | int retVal = -1; 445 | if (bufio->filefunc64.zseek64_file == NULL) 446 | return retVal; 447 | retVal = fseek_buf_internal_func(opaque, stream, offset, origin); 448 | if (retVal == 1) 449 | retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, offset, origin); 450 | return retVal; 451 | } 452 | 453 | int ZCALLBACK fclose_buf_func (opaque, stream) 454 | voidpf opaque; 455 | voidpf stream; 456 | { 457 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 458 | ourstream_t *streamio = (ourstream_t *)stream; 459 | int retVal = 0; 460 | fflush_buf(opaque, stream); 461 | print_buf(opaque, stream, "close\n"); 462 | if (streamio->readBufferHits + streamio->readBufferMisses > 0) 463 | print_buf(opaque, stream, "read efficency %.02f%%\n", (streamio->readBufferHits / ((float)streamio->readBufferHits + streamio->readBufferMisses)) * 100); 464 | if (streamio->writeBufferHits + streamio->writeBufferMisses > 0) 465 | print_buf(opaque, stream, "write efficency %.02f%%\n", (streamio->writeBufferHits / ((float)streamio->writeBufferHits + streamio->writeBufferMisses)) * 100); 466 | if (bufio->filefunc64.zclose_file != NULL) 467 | retVal = bufio->filefunc64.zclose_file(bufio->filefunc64.opaque, streamio->stream); 468 | else 469 | retVal = bufio->filefunc.zclose_file(bufio->filefunc.opaque, streamio->stream); 470 | free(streamio); 471 | return retVal; 472 | } 473 | 474 | int ZCALLBACK ferror_buf_func (opaque, stream) 475 | voidpf opaque; 476 | voidpf stream; 477 | { 478 | ourbuffer_t *bufio = (ourbuffer_t *)opaque; 479 | ourstream_t *streamio = (ourstream_t *)stream; 480 | if (bufio->filefunc64.zerror_file != NULL) 481 | return bufio->filefunc64.zerror_file(bufio->filefunc64.opaque, streamio->stream); 482 | return bufio->filefunc.zerror_file(bufio->filefunc.opaque, streamio->stream); 483 | } 484 | 485 | 486 | void fill_buffer_filefunc (pzlib_filefunc_def, ourbuf) 487 | zlib_filefunc_def* pzlib_filefunc_def; 488 | ourbuffer_t *ourbuf; 489 | { 490 | pzlib_filefunc_def->zopen_file = fopen_buf_func; 491 | pzlib_filefunc_def->zopendisk_file = fopendisk_buf_func; 492 | pzlib_filefunc_def->zread_file = fread_buf_func; 493 | pzlib_filefunc_def->zwrite_file = fwrite_buf_func; 494 | pzlib_filefunc_def->ztell_file = ftell_buf_func; 495 | pzlib_filefunc_def->zseek_file = fseek_buf_func; 496 | pzlib_filefunc_def->zclose_file = fclose_buf_func; 497 | pzlib_filefunc_def->zerror_file = ferror_buf_func; 498 | pzlib_filefunc_def->opaque = ourbuf; 499 | } 500 | 501 | void fill_buffer_filefunc64 (pzlib_filefunc_def, ourbuf) 502 | zlib_filefunc64_def* pzlib_filefunc_def; 503 | ourbuffer_t *ourbuf; 504 | { 505 | pzlib_filefunc_def->zopen64_file = fopen64_buf_func; 506 | pzlib_filefunc_def->zopendisk64_file = fopendisk64_buf_func; 507 | pzlib_filefunc_def->zread_file = fread_buf_func; 508 | pzlib_filefunc_def->zwrite_file = fwrite_buf_func; 509 | pzlib_filefunc_def->ztell64_file = ftell64_buf_func; 510 | pzlib_filefunc_def->zseek64_file = fseek64_buf_func; 511 | pzlib_filefunc_def->zclose_file = fclose_buf_func; 512 | pzlib_filefunc_def->zerror_file = ferror_buf_func; 513 | pzlib_filefunc_def->opaque = ourbuf; 514 | } 515 | -------------------------------------------------------------------------------- /app/src/main/cpp/ioapi_mem.c: -------------------------------------------------------------------------------- 1 | /* ioapi_mem.h -- IO base function header for compress/uncompress .zip 2 | files using zlib + zip or unzip API 3 | 4 | This version of ioapi is designed to access memory rather than files. 5 | We do use a region of memory to put data in to and take it out of. We do 6 | not have auto-extending buffers and do not inform anyone else that the 7 | data has been written. It is really intended for accessing a zip archive 8 | embedded in an application such that I can write an installer with no 9 | external files. Creation of archives has not been attempted, although 10 | parts of the framework are present. 11 | 12 | Based on Unzip ioapi.c version 0.22, May 19th, 2003 13 | 14 | Copyright (C) 1998-2003 Gilles Vollant 15 | (C) 2003 Justin Fletcher 16 | 17 | This file is under the same license as the Unzip tool it is distributed 18 | with. 19 | */ 20 | 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "zlib.h" 27 | #include "ioapi.h" 28 | 29 | #include "ioapi_mem.h" 30 | 31 | voidpf ZCALLBACK fopen_mem_func (opaque, filename, mode) 32 | voidpf opaque; 33 | const char* filename; 34 | int mode; 35 | { 36 | ourmemory_t *mem = (ourmemory_t *)opaque; 37 | if (mem==NULL) 38 | return NULL; /* Mem structure passed in was null */ 39 | 40 | if (mode & ZLIB_FILEFUNC_MODE_CREATE) 41 | mem->limit=0; /* When writing we start with 0 bytes written */ 42 | else 43 | mem->limit=mem->size; 44 | 45 | mem->cur_offset = 0; 46 | 47 | return mem; 48 | } 49 | 50 | voidpf ZCALLBACK fopendisk_mem_func (opaque, stream, number_disk, mode) 51 | voidpf opaque; 52 | voidpf stream; 53 | int number_disk; 54 | int mode; 55 | { 56 | /* Not used */ 57 | return NULL; 58 | } 59 | 60 | uLong ZCALLBACK fread_mem_func (opaque, stream, buf, size) 61 | voidpf opaque; 62 | voidpf stream; 63 | void* buf; 64 | uLong size; 65 | { 66 | ourmemory_t *mem = (ourmemory_t *)stream; 67 | 68 | if (size > mem->size - mem->cur_offset) 69 | size = mem->size - mem->cur_offset; 70 | 71 | memcpy(buf, mem->base + mem->cur_offset, size); 72 | mem->cur_offset+=size; 73 | 74 | return size; 75 | } 76 | 77 | 78 | uLong ZCALLBACK fwrite_mem_func (opaque, stream, buf, size) 79 | voidpf opaque; 80 | voidpf stream; 81 | const void* buf; 82 | uLong size; 83 | { 84 | ourmemory_t *mem = (ourmemory_t *)stream; 85 | 86 | if (size > mem->size - mem->cur_offset) 87 | size = mem->size - mem->cur_offset; 88 | 89 | memcpy(mem->base + mem->cur_offset, buf, size); 90 | mem->cur_offset+=size; 91 | if (mem->cur_offset > mem->limit) 92 | mem->limit = mem->cur_offset; 93 | 94 | return size; 95 | } 96 | 97 | long ZCALLBACK ftell_mem_func (opaque, stream) 98 | voidpf opaque; 99 | voidpf stream; 100 | { 101 | ourmemory_t *mem = (ourmemory_t *)stream; 102 | 103 | return mem->cur_offset; 104 | } 105 | 106 | long ZCALLBACK fseek_mem_func (opaque, stream, offset, origin) 107 | voidpf opaque; 108 | voidpf stream; 109 | uLong offset; 110 | int origin; 111 | { 112 | ourmemory_t *mem = (ourmemory_t *)stream; 113 | uLong new_pos; 114 | switch (origin) 115 | { 116 | case ZLIB_FILEFUNC_SEEK_CUR : 117 | new_pos = mem->cur_offset + offset; 118 | break; 119 | case ZLIB_FILEFUNC_SEEK_END : 120 | new_pos = mem->limit + offset; 121 | break; 122 | case ZLIB_FILEFUNC_SEEK_SET : 123 | new_pos = offset; 124 | break; 125 | default: 126 | return -1; 127 | } 128 | 129 | if (new_pos > mem->size) 130 | return 1; /* Failed to seek that far */ 131 | 132 | mem->cur_offset = new_pos; 133 | return 0; 134 | } 135 | 136 | int ZCALLBACK fclose_mem_func (opaque, stream) 137 | voidpf opaque; 138 | voidpf stream; 139 | { 140 | return 0; 141 | } 142 | 143 | int ZCALLBACK ferror_mem_func (opaque, stream) 144 | voidpf opaque; 145 | voidpf stream; 146 | { 147 | /* We never return errors */ 148 | return 0; 149 | } 150 | 151 | 152 | void fill_memory_filefunc (pzlib_filefunc_def, ourmem) 153 | zlib_filefunc_def* pzlib_filefunc_def; 154 | ourmemory_t *ourmem; 155 | { 156 | pzlib_filefunc_def->zopen_file = fopen_mem_func; 157 | pzlib_filefunc_def->zopendisk_file = fopendisk_mem_func; 158 | pzlib_filefunc_def->zread_file = fread_mem_func; 159 | pzlib_filefunc_def->zwrite_file = fwrite_mem_func; 160 | pzlib_filefunc_def->ztell_file = ftell_mem_func; 161 | pzlib_filefunc_def->zseek_file = fseek_mem_func; 162 | pzlib_filefunc_def->zclose_file = fclose_mem_func; 163 | pzlib_filefunc_def->zerror_file = ferror_mem_func; 164 | pzlib_filefunc_def->opaque = ourmem; 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/cpp/native-lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "unzip.h" 9 | #include 10 | #include "native-lib.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | void Java_com_jd_apploader_App_onAppCreate(JNIEnv *env, jobject obj, jobject app, jobject gameApp, jstring appName) { 17 | if(gameApp == NULL) { 18 | if(appName == NULL) { 19 | return; 20 | } else { 21 | // char *apkfile = GetApkFileName(GetApkFilePath(env, app)); 22 | 23 | gameApp = createGameApplication(env, appName, env->NewStringUTF(apkFileName)); 24 | } 25 | } 26 | 27 | jclass clsActThread = env->FindClass("android/app/ActivityThread"); 28 | jmethodID curThreadMthId = env->GetStaticMethodID(clsActThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 29 | jobject actThread = env->CallStaticObjectMethod(clsActThread, curThreadMthId); 30 | 31 | jfieldID initAppId = env->GetFieldID(clsActThread, "mInitialApplication", "Landroid/app/Application;"); 32 | jobject mInitialApplication = env->GetObjectField(actThread, initAppId); 33 | 34 | jfieldID allAppId = env->GetFieldID(clsActThread, "mAllApplications", "Ljava/util/ArrayList;"); 35 | jobject mAllApplications = env->GetObjectField(actThread, allAppId); 36 | 37 | jclass clsArrList = env->FindClass("java/util/ArrayList"); 38 | jmethodID removeMth = env->GetMethodID(clsArrList, "remove", "(Ljava/lang/Object;)Z"); 39 | env->CallBooleanMethod(mAllApplications, removeMth, mInitialApplication); 40 | 41 | env->SetObjectField(actThread, initAppId, gameApp); 42 | 43 | jfieldID boundAppId = env->GetFieldID(clsActThread, "mBoundApplication", "Landroid/app/ActivityThread$AppBindData;"); 44 | jobject mBoundApplication = env->GetObjectField(actThread, boundAppId); 45 | 46 | jclass clsAppBindData = env->FindClass("android/app/ActivityThread$AppBindData"); 47 | jfieldID infoId = env->GetFieldID(clsAppBindData, "info", "Landroid/app/LoadedApk;"); 48 | jobject info = env->GetObjectField(mBoundApplication, infoId); 49 | 50 | jclass clsLoadedApk = env->FindClass("android/app/LoadedApk"); 51 | jfieldID appId = env->GetFieldID(clsLoadedApk, "mApplication", "Landroid/app/Application;"); 52 | env->SetObjectField(info, appId, gameApp); 53 | 54 | jclass clsApplication = env->FindClass("android/app/Application"); 55 | jmethodID onCreate = env->GetMethodID(clsApplication, "onCreate", "()V"); 56 | env->CallVoidMethod(gameApp, onCreate); 57 | 58 | env->ReleaseStringUTFChars(jPackageName, packageName); 59 | free(apkFilePath); 60 | free(apkLibPath); 61 | free(apkFileName); 62 | 63 | } 64 | 65 | 66 | jobject createGameApplication(JNIEnv *env, jstring appName, jstring apkFileName) { 67 | jclass clsActThread = env->FindClass("android/app/ActivityThread"); 68 | jmethodID curThreadMthId = env->GetStaticMethodID(clsActThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 69 | jobject actThread = env->CallStaticObjectMethod(clsActThread, curThreadMthId); 70 | 71 | jfieldID boundAppId = env->GetFieldID(clsActThread, "mBoundApplication", "Landroid/app/ActivityThread$AppBindData;"); 72 | jobject mBoundApplication = env->GetObjectField(actThread, boundAppId); 73 | 74 | jclass clsAppBindData = env->FindClass("android/app/ActivityThread$AppBindData"); 75 | jfieldID infoId = env->GetFieldID(clsAppBindData, "info", "Landroid/app/LoadedApk;"); 76 | jobject info = env->GetObjectField(mBoundApplication, infoId); 77 | 78 | jclass clsLoadedApk = env->FindClass("android/app/LoadedApk"); 79 | jfieldID appId = env->GetFieldID(clsLoadedApk, "mApplication", "Landroid/app/Application;"); 80 | env->SetObjectField(info, appId, NULL); 81 | 82 | // jfieldID initAppId = env->GetFieldID(clsActThread, "mInitialApplication", "Landroid/app/Application;"); 83 | // jobject mInitialApplication = env->GetObjectField(actThread, initAppId); 84 | 85 | // jfieldID allAppId = env->GetFieldID(clsActThread, "mAllApplications", "Ljava/util/ArrayList;"); 86 | // jobject mAllApplications = env->GetObjectField(actThread, allAppId); 87 | // 88 | // jclass clsArrList = env->FindClass("java/util/ArrayList"); 89 | // jmethodID removeMth = env->GetMethodID(clsArrList, "remove", "(Ljava/lang/Object;)Z"); 90 | // env->CallBooleanMethod(mAllApplications, removeMth, mInitialApplication); 91 | 92 | jfieldID appInfoId = env->GetFieldID(clsLoadedApk, "mApplicationInfo", "Landroid/content/pm/ApplicationInfo;"); 93 | jobject mApplicationInfo = env->GetObjectField(info, appInfoId); 94 | 95 | jfieldID appBindAppInfoId = env->GetFieldID(clsAppBindData, "appInfo", "Landroid/content/pm/ApplicationInfo;"); 96 | jobject appInfo = env->GetObjectField(mBoundApplication, appBindAppInfoId); 97 | 98 | // LOGE("createGameApplication app name: %s", Jstring2CStr(env, appName)); 99 | // LOGE("createGameApplication app name: %s", env->GetStringUTFChars(appName, false)); 100 | // jstring appClsName = env->NewStringUTF("com.duole.PetGame.CmgameApplication"); 101 | jclass clsAppInfo = env->FindClass("android/content/pm/ApplicationInfo"); 102 | jfieldID clsNameId = env->GetFieldID(clsAppInfo, "className", "Ljava/lang/String;"); 103 | env->SetObjectField(mApplicationInfo, clsNameId, appName); 104 | env->SetObjectField(appInfo, clsNameId, appName); 105 | 106 | jfieldID sourceDirId = env->GetFieldID(clsAppInfo, "sourceDir", "Ljava/lang/String;"); 107 | env->SetObjectField(mApplicationInfo, sourceDirId, apkFileName); 108 | 109 | jfieldID resDirId = env->GetFieldID(clsLoadedApk, "mResDir", "Ljava/lang/String;"); 110 | env->SetObjectField(info, resDirId, apkFileName); 111 | 112 | jfieldID mResource = env->GetFieldID(clsLoadedApk, "mResources", "Landroid/content/res/Resources;"); 113 | env->SetObjectField(info, mResource, NULL); 114 | 115 | jmethodID makeAppMth = env->GetMethodID(clsLoadedApk, "makeApplication", "(ZLandroid/app/Instrumentation;)Landroid/app/Application;"); 116 | jobject gameApp = env->CallObjectMethod(info, makeAppMth, false, NULL); 117 | 118 | LOGE("game application created, return app object"); 119 | 120 | return gameApp; 121 | } 122 | 123 | char* Jstring2CStr(JNIEnv *env, jstring jstr) { 124 | char* rtn = NULL; 125 | jclass clsstring = env->FindClass("java/lang/String"); 126 | jstring strencode = env->NewStringUTF("utf-8"); 127 | jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); 128 | jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode); 129 | jsize len = env->GetArrayLength(barr); 130 | jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE); 131 | if(len > 0) { 132 | rtn = (char *) malloc(len); 133 | memcpy(rtn, ba, len); 134 | rtn[len] = 0; 135 | } 136 | 137 | env->ReleaseByteArrayElements(barr, ba, 0); 138 | return rtn; 139 | } 140 | 141 | int GetOSVersion() { 142 | char sdk_ver_str[10]; 143 | __system_property_get("ro.build.version.sdk", sdk_ver_str); 144 | LOGD("sdk version: %s", sdk_ver_str); 145 | return atoi(sdk_ver_str); 146 | } 147 | 148 | jstring GetPackageName(JNIEnv *env, jobject app) { 149 | // jclass myAppCls = env->FindClass("com/jd/apploader/App"); 150 | // jfieldID sAppId = env->GetStaticFieldID(myAppCls, "sApplication", "Landroid/app/Application;"); 151 | // jobject application = env->GetStaticObjectField(myAppCls, sAppId); 152 | jclass applicationCls = env->FindClass("android/app/Application"); 153 | jmethodID getPkgNameId = env->GetMethodID(applicationCls, "getPackageName", "()Ljava/lang/String;"); 154 | jstring packageName = (jstring) env->CallObjectMethod(app, getPkgNameId); 155 | return packageName; 156 | } 157 | 158 | void InitPackageName(JNIEnv *env, jobject app) { 159 | jPackageName = GetPackageName(env, app); 160 | packageName = (char *) env->GetStringUTFChars(jPackageName, false); 161 | // packageName = Jstring2CStr(env, GetPackageName(env, app)); 162 | LOGD("package name: %s", packageName); 163 | } 164 | 165 | char* GetDexFilePath(JNIEnv *env, jobject app) { 166 | const char* root = "/data/data/"; 167 | // char* package = Jstring2CStr(env, GetPackageName(env, app)); 168 | const char* path = "/files/dex/"; 169 | 170 | int len = strlen(root) + strlen(packageName) + strlen(path) + 1; 171 | char *buf = (char *) malloc(len); 172 | buf[len] = 0; 173 | sprintf(buf, "%s%s%s", root, packageName, path); 174 | LOGD("dex file path: %s", buf); 175 | // free(package); 176 | 177 | return buf; 178 | } 179 | 180 | char* GetApkFilePath(JNIEnv *env, jobject app) { 181 | const char* root = "/data/data/"; 182 | // char* package = Jstring2CStr(env, GetPackageName(env, app)); 183 | const char* path = "/files/apkFile/"; 184 | 185 | int rootLen = strlen(root); 186 | int packageLen = strlen(packageName); 187 | int pathLen = strlen(path); 188 | int len = rootLen + packageLen + pathLen; 189 | char *buf = (char *) malloc(len); 190 | sprintf(buf, "%s%s%s", root, packageName, path); 191 | buf[len] = 0; 192 | LOGD("apk file path: %s", buf); 193 | // free(package); 194 | 195 | return buf; 196 | } 197 | 198 | char* GetApkFileName(const char *apkFilePath) { 199 | const char* decryptFileName = "loader.apk"; 200 | int len = strlen(apkFilePath) + strlen(decryptFileName); 201 | char *apkFileName = (char *) malloc(len + 1); 202 | 203 | sprintf(apkFileName, "%s%s", apkFilePath, decryptFileName); 204 | apkFileName[len] = 0; 205 | LOGD("apk file: %s", apkFileName); 206 | 207 | return apkFileName; 208 | } 209 | 210 | char* GetApkLibPath(JNIEnv *env, jobject app) { 211 | const char* root = "/data/data/"; 212 | // char* package = Jstring2CStr(env, GetPackageName(env, app)); 213 | const char* path = "/files/apkLib/"; 214 | int len = strlen(root) + strlen(packageName) + strlen(path); 215 | char *buf = (char *) malloc(len + 1); 216 | sprintf(buf, "%s%s%s", root, packageName, path); 217 | buf[len] = 0; 218 | LOGD("apk lib path: %s", buf); 219 | // free(package); 220 | 221 | return buf; 222 | } 223 | 224 | jobject GetAssetsManager(JNIEnv *env, jobject app) { 225 | jclass myAppCls = env->FindClass("com/jd/apploader/App"); 226 | // jfieldID sAppId = env->GetStaticFieldID(myAppCls, "sApplication", "Landroid/app/Application;"); 227 | // jobject application = env->GetStaticObjectField(myAppCls, sAppId); 228 | jmethodID methodGetAssets = env->GetMethodID(myAppCls, "getAssets", "()Landroid/content/res/AssetManager;"); 229 | return env->CallObjectMethod(app, methodGetAssets); 230 | } 231 | 232 | int CreateDir(const char *pDir) { 233 | int i = 0; 234 | int iRet; 235 | int iLen; 236 | char* pszDir; 237 | 238 | if(NULL == pDir) 239 | { 240 | return 0; 241 | } 242 | 243 | iRet = access(pDir, 0); 244 | if(iRet == 0) { 245 | LOGD("%s is exists", pDir); 246 | return 0; 247 | } 248 | 249 | LOGD("pDir len: %d", strlen(pDir)); 250 | 251 | pszDir = strdup(pDir); 252 | iLen = strlen(pszDir); 253 | 254 | LOGD("pszDir: %s", pszDir); 255 | 256 | for(; i < iLen; i++) { 257 | if(pszDir[i] == '\\' || pszDir[i] == '/') { 258 | pszDir[i] = '\0'; 259 | LOGD("pszDir: %s", pszDir); 260 | 261 | iRet = access(pszDir, 0); 262 | if(iRet != 0) { 263 | iRet = mkdir(pszDir, 0777); 264 | LOGD("mkdir: %s, ret: %d", pszDir, iRet); 265 | } 266 | 267 | pszDir[i] = '/'; 268 | } 269 | } 270 | 271 | if(pszDir[iLen - 1] != '/') { 272 | iRet = mkdir(pszDir, 0777); 273 | LOGD("mkdir: %s, ret: %d", pszDir, iRet); 274 | } 275 | free(pszDir); 276 | return iRet; 277 | } 278 | 279 | char* GetLibFileName(const char *libFullName) { 280 | int len = strlen(libFullName); 281 | int i = len - 1; 282 | for(; i >= 0; i--) { 283 | if(libFullName[i] == '/') { 284 | int size = len - i; 285 | char *fileName = (char *) malloc(size + 1); 286 | char *nameStart = (char *) &libFullName[i + 1]; 287 | memcpy(fileName, nameStart, size); 288 | LOGD("lib file name: %s", fileName); 289 | fileName[size] = 0; 290 | return fileName; 291 | } 292 | } 293 | 294 | return NULL; 295 | } 296 | 297 | void setFileTime(const char *filename, uLong dosdate, tm_unz tmu_date) { 298 | struct tm newdate; 299 | newdate.tm_sec = tmu_date.tm_sec; 300 | newdate.tm_min = tmu_date.tm_min; 301 | newdate.tm_hour = tmu_date.tm_hour; 302 | newdate.tm_mday = tmu_date.tm_mday; 303 | newdate.tm_mon = tmu_date.tm_mon; 304 | 305 | if (tmu_date.tm_year > 1900) { 306 | newdate.tm_year = tmu_date.tm_year - 1900; 307 | } else { 308 | newdate.tm_year = tmu_date.tm_year; 309 | } 310 | newdate.tm_isdst = -1; 311 | 312 | struct utimbuf ut; 313 | ut.actime = ut.modtime = mktime(&newdate); 314 | utime(filename, &ut); 315 | } 316 | 317 | int ExtractFileInZip(unzFile uf, const char *destFile, unz_file_info64 file_info) { 318 | LOGD("ExtractFileInZip, dest file name: %s", destFile); 319 | uint size_buf = 2048; 320 | void* buf = (void*) malloc(size_buf); 321 | if (buf == NULL) return UNZ_INTERNALERROR; 322 | int status = unzOpenCurrentFile(uf); 323 | FILE* fout = NULL; 324 | if (status == UNZ_OK) { 325 | fout = fopen(destFile, "a+"); 326 | } 327 | 328 | // Read from the zip, unzip to buffer, and write to disk 329 | if (fout != NULL) { 330 | do { 331 | status = unzReadCurrentFile(uf, buf, size_buf); 332 | // LOGD("read zip file status: %d", status); 333 | if (status <= 0) break; 334 | if (fwrite(buf, status, 1, fout) != 1) { 335 | status = UNZ_ERRNO; 336 | break; 337 | } 338 | } while (status > 0); 339 | 340 | LOGD("file len: %d", ftell(fout)); 341 | 342 | if (fout) fclose(fout); 343 | 344 | // Set the time of the file that has been unzipped 345 | if (status == 0) { 346 | setFileTime(destFile, file_info.dosDate, file_info.tmu_date); 347 | } 348 | } 349 | 350 | unzCloseCurrentFile(uf); 351 | 352 | free(buf); 353 | return status; 354 | } 355 | 356 | void CopyApkLib(JNIEnv *env, const char *apkFileName, const char *apkLibPath) { 357 | int ret = CreateDir(apkLibPath); 358 | if(ret != 0) { 359 | LOGD("create apk lib path failed"); 360 | return ; 361 | } 362 | 363 | LOGD("CopyApkLib, apk file: %s", apkFileName); 364 | LOGD("CopyApkLib, is apk file exists: %d", access(apkFileName, 0)); 365 | 366 | unzFile uf = unzOpen64(apkFileName); 367 | if(uf == NULL) { 368 | LOGD("open zip file failed."); 369 | return; 370 | } 371 | 372 | unz_file_info64 file_info = { 0 }; 373 | int status; 374 | char filename_in_zip[MAX_FILENAME_LEN] = { 0 }; 375 | // int status = unzGetCurrentFileInfo64(uf, &file_info, filename_in_zip, sizeof(filename_in_zip), NULL, 0, NULL, 0); 376 | // if (status != UNZ_OK) { 377 | // LOGD("unzip file failed."); 378 | // unzClose(uf); 379 | // return ; 380 | // } 381 | 382 | // LOGD("file name in zip: %s", filename_in_zip); 383 | 384 | while (true) { 385 | status = unzGetCurrentFileInfo64(uf, &file_info, filename_in_zip, sizeof(filename_in_zip), NULL, 0, NULL, 0); 386 | if (status != UNZ_OK) { 387 | LOGD("unzip file failed."); 388 | unzCloseCurrentFile(uf); 389 | unzClose(uf); 390 | return ; 391 | } 392 | 393 | char fileDir[5] = {0}; 394 | fileDir[4] = 0; 395 | memcpy(fileDir, filename_in_zip, 4); 396 | int res = strcmp(fileDir, "lib/"); 397 | if(res == 0) { 398 | char *fileName = GetLibFileName(filename_in_zip); 399 | int len = strlen(fileName) + strlen(apkLibPath); 400 | char *libFileFullPath = (char *) malloc(len + 1); 401 | strcpy(libFileFullPath, apkLibPath); 402 | strcat(libFileFullPath, fileName); 403 | libFileFullPath[len] = 0; 404 | LOGD("extract lib file full path: %s", libFileFullPath); 405 | 406 | if(access(libFileFullPath, 0) == 0) { 407 | FILE *file = fopen(libFileFullPath, "a+"); 408 | long size = ftell(file); 409 | LOGD("lib file is exists file size: %d", size); 410 | if(size == file_info.uncompressed_size) { 411 | LOGD("lib file is exists and file len is same, do not extract"); 412 | fclose(file); 413 | free(libFileFullPath); 414 | free(fileName); 415 | unzCloseCurrentFile(uf); 416 | int ret = unzGoToNextFile(uf); 417 | if(ret != UNZ_OK) { 418 | LOGD("go to file end."); 419 | unzClose(uf); 420 | return; 421 | } 422 | continue; 423 | } else { 424 | fclose(file); 425 | remove(libFileFullPath); 426 | } 427 | } 428 | ExtractFileInZip(uf, libFileFullPath, file_info); 429 | free(fileName); 430 | free(libFileFullPath); 431 | } 432 | 433 | unzCloseCurrentFile(uf); 434 | int ret = unzGoToNextFile(uf); 435 | if(ret != UNZ_OK) { 436 | LOGD("go to file end."); 437 | unzClose(uf); 438 | return; 439 | } 440 | } 441 | 442 | } 443 | 444 | bool CopyApkFile(JNIEnv *env, const char *apkFileName, const char *apkFilePath, const char *apkLibPath, jobject app) { 445 | AAssetManager *mgr = AAssetManager_fromJava(env, GetAssetsManager(env, app)); 446 | const char *mfile = "Ldal.bin"; 447 | AAsset *asset = AAssetManager_open(mgr, mfile, AASSET_MODE_UNKNOWN); 448 | if(asset == NULL) { 449 | LOGD("%s", "asset is NULL"); 450 | return NULL; 451 | } 452 | 453 | int ret = CreateDir(apkFilePath); 454 | if(ret != 0) { 455 | LOGD("create apk file path failed"); 456 | AAsset_close(asset); 457 | return false; 458 | } 459 | 460 | // const char* decryptFileName = "loader.so"; 461 | // int len = strlen(apkFilePath) + strlen(decryptFileName) + 1; 462 | // char *apkFileName = (char *) malloc(len); 463 | // apkFileName[len] = 0; 464 | // sprintf(apkFileName, "%s%s", apkFilePath, decryptFileName); 465 | // LOGD("apk file: %s", apkFileName); 466 | 467 | // char *apkFileName = GetApkFileName(apkFilePath); 468 | 469 | off_t fileLen = AAsset_getLength(asset); 470 | LOGD("file length: %d", fileLen); 471 | FILE *file = fopen(apkFileName, "a+"); 472 | if(file == NULL) { 473 | // free(apkFileName); 474 | AAsset_close(asset); 475 | LOGE("apk file is NULL, error: %s", strerror(errno)); 476 | return NULL; 477 | } 478 | 479 | if(access(apkFileName, 0) == 0) { 480 | long size = ftell(file); 481 | LOGD("apk file size: %d", size); 482 | if(size == fileLen) { 483 | LOGE("apk file %s is exists", apkFileName); 484 | AAsset_close(asset); 485 | fclose(file); 486 | CopyApkLib(env, apkFileName, apkLibPath); 487 | return true; 488 | } else { 489 | fclose(file); 490 | remove(apkFileName); 491 | file = fopen(apkFileName, "w"); 492 | } 493 | } 494 | 495 | char *buffer = (char *) malloc(2048); 496 | int numBytesRead = 0; 497 | while ((numBytesRead = AAsset_read(asset, buffer, 2048)) > 0) { 498 | for(int i = 0; i < numBytesRead; i++) { 499 | buffer[i] ^= 0xa1; 500 | } 501 | fwrite(buffer, numBytesRead, 1, file); 502 | } 503 | free(buffer); 504 | fclose(file); 505 | AAsset_close(asset); 506 | 507 | CopyApkLib(env, apkFileName, apkLibPath); 508 | 509 | return true; 510 | } 511 | 512 | char* getSourceApkFilePath(JNIEnv *env, jobject app) { 513 | jclass clsApplication = env->FindClass("android/app/Application"); 514 | // jfieldID sAppId = env->GetStaticFieldID(myAppCls, "sApplication", "Landroid/app/Application;"); 515 | // jobject application = env->GetStaticObjectField(myAppCls, sAppId); 516 | 517 | jmethodID getApplicationInfo = env->GetMethodID(clsApplication, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;"); 518 | jobject applicationInfo = env->CallObjectMethod(app, getApplicationInfo); 519 | 520 | jclass clsAppInfo = env->FindClass("android/content/pm/ApplicationInfo"); 521 | jfieldID sourDirId = env->GetFieldID(clsAppInfo, "sourceDir", "Ljava/lang/String;"); 522 | jstring sourceDir = (jstring) env->GetObjectField(applicationInfo, sourDirId); 523 | 524 | // return Jstring2CStr(env, sourceDir); 525 | return (char *) env->GetStringUTFChars(sourceDir, false); 526 | } 527 | 528 | void UNZipDexFile(JNIEnv *env, const char *dexFilePath, jobject app) { 529 | 530 | jclass clsApplication = env->FindClass("android/app/Application"); 531 | jmethodID getApplicationInfo = env->GetMethodID(clsApplication, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;"); 532 | jobject applicationInfo = env->CallObjectMethod(app, getApplicationInfo); 533 | 534 | jclass clsAppInfo = env->FindClass("android/content/pm/ApplicationInfo"); 535 | jfieldID sourDirId = env->GetFieldID(clsAppInfo, "sourceDir", "Ljava/lang/String;"); 536 | jstring sourceDir = (jstring) env->GetObjectField(applicationInfo, sourDirId); 537 | 538 | char *sourceApkFile = (char *) env->GetStringUTFChars(sourceDir, false); 539 | LOGD("source apk file: %s", sourceApkFile); 540 | unz_file_info64 file_info = { 0 }; 541 | int status; 542 | char filename_in_zip[MAX_FILENAME_LEN] = { 0 }; 543 | 544 | unzFile uf = unzOpen64(sourceApkFile); 545 | if(uf == NULL) { 546 | LOGD("open zip file failed."); 547 | // free(sourceApkFile); 548 | env->ReleaseStringUTFChars(sourceDir, sourceApkFile); 549 | return; 550 | } 551 | 552 | while (true) { 553 | status = unzGetCurrentFileInfo64(uf, &file_info, filename_in_zip, sizeof(filename_in_zip), NULL, 0, NULL, 0); 554 | if(status != UNZ_OK) { 555 | LOGD("unzip file failed."); 556 | unzClose(uf); 557 | // free(sourceApkFile); 558 | env->ReleaseStringUTFChars(sourceDir, sourceApkFile); 559 | return; 560 | } 561 | 562 | int res = strcmp(filename_in_zip, "classes.dex"); 563 | LOGD("is dex file: %d, file: %s", res, filename_in_zip); 564 | if(res == 0) { 565 | FILE *dexFile = fopen(dexFilePath, "a+"); 566 | if(dexFile == NULL) { 567 | LOGD("open dex file failed, file path: %s, err: %s", dexFilePath, strerror(errno)); 568 | unzClose(uf); 569 | // free(sourceApkFile); 570 | env->ReleaseStringUTFChars(sourceDir, sourceApkFile); 571 | return; 572 | } 573 | 574 | if(access(dexFilePath, 0) == 0) { 575 | int dexFileLen = ftell(dexFile); 576 | if(dexFileLen == file_info.uncompressed_size) { 577 | LOGD("dex file has uncompressed."); 578 | fclose(dexFile); 579 | break; 580 | } 581 | 582 | remove(dexFilePath); 583 | } 584 | fclose(dexFile); 585 | ExtractFileInZip(uf, dexFilePath, file_info); 586 | 587 | break; 588 | } 589 | 590 | int ret = unzGoToNextFile(uf); 591 | if(ret != UNZ_OK) { 592 | LOGD("go to file end."); 593 | unzClose(uf); 594 | // free(sourceApkFile); 595 | env->ReleaseStringUTFChars(sourceDir, sourceApkFile); 596 | return; 597 | } 598 | } 599 | 600 | unzClose(uf); 601 | env->ReleaseStringUTFChars(sourceDir, sourceApkFile); 602 | // free(sourceApkFile); 603 | } 604 | 605 | int GetApkFileLength(const char *dexFilePath) { 606 | FILE *file = fopen(dexFilePath, "rb"); 607 | fseek(file, 0, SEEK_END); 608 | long fileLen = ftell(file); 609 | LOGD("dex file length: %d", fileLen); 610 | if(fileLen == 0) { 611 | fclose(file); 612 | return 0; 613 | } 614 | 615 | fseek(file, -4, SEEK_END); 616 | int index = ftell(file); 617 | LOGD("GetApkFileLength, dex read index: %d", index); 618 | char apkLenBytes[4] = {0}; 619 | fread(apkLenBytes, sizeof(char), 4, file); 620 | fclose(file); 621 | 622 | int apkLen = apkLenBytes[0] & 0xff; 623 | for(int i = 1; i < 4; i++) { 624 | apkLen = (apkLen << 8) | (apkLenBytes[i] & 0xff); 625 | } 626 | LOGD("apk file len: %d", apkLen); 627 | return apkLen; 628 | } 629 | 630 | char* CopyFileFromDex(JNIEnv *env, const char *apkFilePath, const char *apkLibPath, jobject app) { 631 | char *dexFilePath = GetDexFilePath(env, app); 632 | LOGD("dex file: %s", dexFilePath); 633 | CreateDir(dexFilePath); 634 | int dexPathLen = strlen(dexFilePath) + strlen("classes.dex"); 635 | char *dexFileName = (char *) malloc(dexPathLen + 1); 636 | dexFileName[dexPathLen] = 0; 637 | strcpy(dexFileName, dexFilePath); 638 | strcat(dexFileName, "classes.dex"); 639 | 640 | int ret = CreateDir(apkFilePath); 641 | if(ret != 0) { 642 | LOGD("create apk file path failed"); 643 | free(dexFilePath); 644 | free(dexFileName); 645 | return NULL; 646 | } 647 | 648 | char *apkFileName = GetApkFileName(apkFilePath); 649 | 650 | FILE *apkFile = fopen(apkFileName, "a+"); 651 | if(apkFile == NULL) { 652 | free(dexFilePath); 653 | free(dexFileName); 654 | free(apkFileName); 655 | LOGD("apk file is NULL, error: %s", strerror(errno)); 656 | return NULL; 657 | } 658 | 659 | UNZipDexFile(env, dexFileName, app); 660 | 661 | if(access(dexFileName, 0) == 0) { 662 | int apkFileLen = GetApkFileLength(dexFileName); 663 | if(apkFileLen == 0) { 664 | free(dexFilePath); 665 | free(dexFileName); 666 | free(apkFileName); 667 | return NULL; 668 | } 669 | if(access(apkFileName, 0) == 0) { 670 | long size = ftell(apkFile); 671 | LOGD("apk file size: %d", size); 672 | if(size == apkFileLen) { 673 | LOGD("apk file %s is exists", apkFileName); 674 | fclose(apkFile); 675 | free(dexFilePath); 676 | free(dexFileName); 677 | CopyApkLib(env, apkFileName, apkLibPath); 678 | return apkFileName; 679 | } else if(size > 0){ 680 | fclose(apkFile); 681 | remove(apkFileName); 682 | apkFile = fopen(apkFileName, "a+"); 683 | } 684 | } 685 | 686 | FILE *dexFile = fopen(dexFileName, "rb"); 687 | fseek(dexFile, -(apkFileLen + 4), SEEK_END); 688 | LOGD("read apk index: %d", ftell(dexFile)); 689 | char *buffer = (char *) malloc(16384); 690 | int readSize = 0; 691 | while ((readSize = fread(buffer, sizeof(char), 16384, dexFile)) > 0) { 692 | if(readSize < 16384) { 693 | readSize -= 4; 694 | } 695 | 696 | // decrypt(buffer); 697 | // LOGD("read apk file size: %d", readSize); 698 | for(int i = 0; i < readSize; i++) { 699 | buffer[i] ^= 0xa1; 700 | } 701 | fwrite(buffer, readSize, 1, apkFile); 702 | } 703 | 704 | free(buffer); 705 | 706 | LOGD("apk file size: %d", ftell(apkFile)); 707 | char bytes[4] = {0}; 708 | fseek(apkFile, 0, SEEK_SET); 709 | fread(bytes, sizeof(char), 4, apkFile); 710 | fseek(apkFile, -4, SEEK_END); 711 | fread(bytes, sizeof(char), 4, apkFile); 712 | fclose(apkFile); 713 | 714 | LOGD("apk file is exists: %d", access(apkFileName, 0)); 715 | CopyApkLib(env, apkFileName, apkLibPath); 716 | } else { 717 | fclose(apkFile); 718 | } 719 | 720 | free(dexFilePath); 721 | free(dexFileName); 722 | 723 | return apkFileName; 724 | } 725 | 726 | void LoadResource(JNIEnv *env, jstring apkFileName) { 727 | jclass clsAssetsMgr = env->FindClass("android/content/res/AssetManager"); 728 | jmethodID initMethodId = env->GetMethodID(clsAssetsMgr, "", "()V"); 729 | jobject assetsMgr = env->NewObject(clsAssetsMgr, initMethodId); 730 | 731 | jmethodID addAssetsMthd = env->GetMethodID(clsAssetsMgr, "addAssetPath", "(Ljava/lang/String;)I"); 732 | env->CallIntMethod(assetsMgr, addAssetsMthd, apkFileName); 733 | 734 | jclass myAppCls = env->FindClass("com/jd/apploader/App"); 735 | jfieldID fieldAssets = env->GetStaticFieldID(myAppCls, "mAssetManager", "Landroid/content/res/AssetManager;"); 736 | env->SetStaticObjectField(myAppCls, fieldAssets, assetsMgr); 737 | 738 | // InitResource(env, objLoadedApk); 739 | 740 | // jclass myAppCls = env->FindClass("com/jd/apploader/App"); 741 | // jfieldID sAppId = env->GetStaticFieldID(myAppCls, "sApplication", "Landroid/app/Application;"); 742 | // jobject application = env->GetStaticObjectField(myAppCls, sAppId); 743 | 744 | // jmethodID loadRes = env->GetMethodID(myAppCls, "loadResources", "(Ljava/lang/String;)V"); 745 | // env->CallVoidMethod(application, loadRes, apkFileName); 746 | } 747 | 748 | jobject Java_com_jd_apploader_App_onAppAttach(JNIEnv *env, jobject thiz, jobject app, jstring appName) { 749 | InitPackageName(env, app); 750 | apkFilePath = GetApkFilePath(env, app); 751 | apkLibPath = GetApkLibPath(env, app); 752 | apkFileName = GetApkFileName(apkFilePath); 753 | 754 | LOGD("apkFilePath: %s", apkFilePath); 755 | LOGD("apkLibPath: %s", apkLibPath); 756 | LOGD("apkFileName: %s", apkFileName); 757 | 758 | bool ret = CopyApkFile(env, apkFileName, apkFilePath, apkLibPath, app); 759 | if(!ret) { 760 | return NULL; 761 | } 762 | 763 | jstring strApkFileName = env->NewStringUTF(apkFileName); 764 | jstring strApkFilePath = env->NewStringUTF(apkFilePath); 765 | jstring strApkLibPath = env->NewStringUTF(apkLibPath); 766 | 767 | // LoadResource(env, strApkFileName); 768 | 769 | jclass clsActThread = env->FindClass("android/app/ActivityThread"); 770 | jmethodID currentActivityThread = env->GetStaticMethodID(clsActThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 771 | jobject actThread = env->CallStaticObjectMethod(clsActThread, currentActivityThread); 772 | jfieldID mPackagesId; 773 | if(GetOSVersion() >= 19) { 774 | mPackagesId = env->GetFieldID(clsActThread, "mPackages", "Landroid/util/ArrayMap;"); 775 | } else { 776 | mPackagesId = env->GetFieldID(clsActThread, "mPackages", "Ljava/util/HashMap;"); 777 | } 778 | jobject mPackages = env->GetObjectField(actThread, mPackagesId); 779 | 780 | jclass mapCls = env->FindClass("java/util/Map"); 781 | jmethodID getId = env->GetMethodID(mapCls, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 782 | jobject wr = env->CallObjectMethod(mPackages, getId, jPackageName); 783 | 784 | jclass wrclass = env->FindClass("java/lang/ref/WeakReference"); 785 | jmethodID methodGet = env->GetMethodID(wrclass, "get", "()Ljava/lang/Object;"); 786 | jobject objApkLoader = env->CallObjectMethod(wr, methodGet); 787 | 788 | jclass clsApkLoader = env->FindClass("android/app/LoadedApk"); 789 | jfieldID fieldClassLoader = env->GetFieldID(clsApkLoader, "mClassLoader", "Ljava/lang/ClassLoader;"); 790 | jobject classDexLoader = env->GetObjectField(objApkLoader, fieldClassLoader); 791 | 792 | jclass dexClassLoader = env->FindClass("dalvik/system/DexClassLoader"); 793 | jmethodID initDexLoaderMethod = env->GetMethodID(dexClassLoader, "", 794 | "(Ljava/lang/String;Ljava/lang/String;" 795 | "Ljava/lang/String;Ljava/lang/ClassLoader;)V"); 796 | jobject dexLoader = env->NewObject(dexClassLoader, initDexLoaderMethod, strApkFileName, strApkFilePath, strApkLibPath, classDexLoader); 797 | env->SetObjectField(objApkLoader, fieldClassLoader, dexLoader); 798 | 799 | LoadResource(env, strApkFileName); 800 | 801 | jfieldID resDirId = env->GetFieldID(clsApkLoader, "mResDir", "Ljava/lang/String;"); 802 | jstring resDir = (jstring) env->GetObjectField(objApkLoader, resDirId); 803 | // LOGD("res dir: %s", Jstring2CStr(env, resDir)); 804 | // LOGD("res dir: %s", env->GetStringUTFChars(resDir, false)); 805 | env->SetObjectField(objApkLoader, resDirId, strApkFileName); 806 | // 807 | // jfieldID mResource = env->GetFieldID(clsApkLoader, "mResources", "Landroid/content/res/Resources;"); 808 | // env->SetObjectField(objApkLoader, mResource, NULL); 809 | 810 | // LoadResource(env, strApkFileName); 811 | // jmethodID getResources = env->GetMethodID(clsApkLoader, "getResources", "(Landroid/app/ActivityThread;)Landroid/content/res/Resources;"); 812 | // env->CallObjectMethod(objApkLoader, getResources, actThread); 813 | 814 | // jfieldID applicationInfoId = env->GetFieldID(clsApkLoader, "mApplicationInfo", "Landroid/content/pm/ApplicationInfo;"); 815 | // jobject mApplicationInfo = env->GetObjectField(objApkLoader, applicationInfoId); 816 | 817 | // jclass clsAppInfo = env->FindClass("android/content/pm/ApplicationInfo"); 818 | // jfieldID sourceDirId = env->GetFieldID(clsAppInfo, "sourceDir", "Ljava/lang/String;"); 819 | // env->SetObjectField(mApplicationInfo, sourceDirId, strApkFileName); 820 | 821 | jobject gameApp = NULL; 822 | if(appName != NULL) { 823 | // LOGE("app name: %s", Jstring2CStr(env, appName)); 824 | // LOGE("app name: %s", env->GetStringUTFChars(appName, false)); 825 | gameApp = createGameApplication(env, appName, strApkFileName); 826 | } 827 | 828 | // if(apkFilePath != NULL) { 829 | // free(apkFilePath); 830 | // apkFilePath = NULL; 831 | // } 832 | // if(apkLibPath != NULL) { 833 | // free(apkLibPath); 834 | // apkLibPath = NULL; 835 | // } 836 | // if(apkFileName != NULL) { 837 | // free(apkFileName); 838 | // apkFileName = NULL; 839 | // } 840 | 841 | LOGE("onAppAttach finish, return game application object"); 842 | 843 | return gameApp; 844 | } 845 | 846 | //JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { 847 | // JNIEnv* env = NULL; 848 | // 849 | // if(vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { 850 | // return -1; 851 | // } 852 | // 853 | // char *apkFilePath = GetApkFilePath(env); 854 | // char *apkLibPath = GetApkLibPath(env); 855 | // char *apkFileName = CopyApkFile(env, apkFilePath, apkLibPath); 856 | // 857 | // jstring strApkFileName = env->NewStringUTF(apkFileName); 858 | // jstring strApkFilePath = env->NewStringUTF(apkFilePath); 859 | // jstring strApkLibPath = env->NewStringUTF(apkLibPath); 860 | // 861 | //// LoadResource(env, strApkFileName); 862 | // 863 | // jclass clsActThread = env->FindClass("android/app/ActivityThread"); 864 | // jmethodID currentActivityThread = env->GetStaticMethodID(clsActThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 865 | // jobject actThread = env->CallStaticObjectMethod(clsActThread, currentActivityThread); 866 | // jfieldID mPackagesId; 867 | // if(GetOSVersion() >= 19) { 868 | // mPackagesId = env->GetFieldID(clsActThread, "mPackages", "Landroid/util/ArrayMap;"); 869 | // } else { 870 | // mPackagesId = env->GetFieldID(clsActThread, "mPackages", "Ljava/util/HashMap;"); 871 | // } 872 | // jobject mPackages = env->GetObjectField(actThread, mPackagesId); 873 | // 874 | // jclass mapCls = env->FindClass("java/util/Map"); 875 | // jmethodID getId = env->GetMethodID(mapCls, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 876 | // jobject wr = env->CallObjectMethod(mPackages, getId, GetPackageName(env)); 877 | // 878 | // jclass wrclass = env->FindClass("java/lang/ref/WeakReference"); 879 | // jmethodID methodGet = env->GetMethodID(wrclass, "get", "()Ljava/lang/Object;"); 880 | // jobject objApkLoader = env->CallObjectMethod(wr, methodGet); 881 | // 882 | // jclass clsApkLoader = env->FindClass("android/app/LoadedApk"); 883 | // jfieldID fieldClassLoader = env->GetFieldID(clsApkLoader, "mClassLoader", "Ljava/lang/ClassLoader;"); 884 | // jobject classDexLoader = env->GetObjectField(objApkLoader, fieldClassLoader); 885 | // 886 | // jclass dexClassLoader = env->FindClass("dalvik/system/DexClassLoader"); 887 | // jmethodID initDexLoaderMethod = env->GetMethodID(dexClassLoader, "", 888 | // "(Ljava/lang/String;Ljava/lang/String;" 889 | // "Ljava/lang/String;Ljava/lang/ClassLoader;)V"); 890 | // jobject dexLoader = env->NewObject(dexClassLoader, initDexLoaderMethod, strApkFileName, strApkFilePath, strApkLibPath, classDexLoader); 891 | // env->SetObjectField(objApkLoader, fieldClassLoader, dexLoader); 892 | // 893 | // LoadResource(env, strApkFileName); 894 | // 895 | // jfieldID resDirId = env->GetFieldID(clsApkLoader, "mResDir", "Ljava/lang/String;"); 896 | // jstring resDir = (jstring) env->GetObjectField(objApkLoader, resDirId); 897 | // LOGD("res dir: %s", Jstring2CStr(env, resDir)); 898 | // env->SetObjectField(objApkLoader, resDirId, strApkFileName); 899 | //// 900 | //// jfieldID mResource = env->GetFieldID(clsApkLoader, "mResources", "Landroid/content/res/Resources;"); 901 | //// env->SetObjectField(objApkLoader, mResource, NULL); 902 | // 903 | //// LoadResource(env, strApkFileName); 904 | //// jmethodID getResources = env->GetMethodID(clsApkLoader, "getResources", "(Landroid/app/ActivityThread;)Landroid/content/res/Resources;"); 905 | //// env->CallObjectMethod(objApkLoader, getResources, actThread); 906 | // 907 | //// jfieldID applicationInfoId = env->GetFieldID(clsApkLoader, "mApplicationInfo", "Landroid/content/pm/ApplicationInfo;"); 908 | //// jobject mApplicationInfo = env->GetObjectField(objApkLoader, applicationInfoId); 909 | //// 910 | //// jclass clsAppInfo = env->FindClass("android/content/pm/ApplicationInfo"); 911 | //// jfieldID sourceDirId = env->GetFieldID(clsAppInfo, "sourceDir", "Ljava/lang/String;"); 912 | //// env->SetObjectField(mApplicationInfo, sourceDirId, strApkFileName); 913 | // 914 | // free(apkFilePath); 915 | // free(apkLibPath); 916 | // free(apkFileName); 917 | // 918 | // 919 | // return JNI_VERSION_1_4; 920 | //} 921 | 922 | #ifdef __cplusplus 923 | } 924 | #endif -------------------------------------------------------------------------------- /app/src/main/java/com/jd/apploader/App.java: -------------------------------------------------------------------------------- 1 | package com.jd.apploader; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.pm.ApplicationInfo; 6 | import android.content.pm.PackageManager; 7 | import android.content.res.AssetManager; 8 | import android.content.res.Resources; 9 | import android.util.Log; 10 | 11 | /** 12 | * Created by Administrator on 2016/11/25. 13 | */ 14 | 15 | public class App extends Application { 16 | 17 | // public static Application sApplication; 18 | // private String apkFileName; 19 | // private String apkFilePath; 20 | // private String apkLibPath; 21 | 22 | private Object obj; 23 | 24 | static { 25 | System.loadLibrary("native-lib"); 26 | } 27 | 28 | @Override 29 | protected void attachBaseContext(Context base) { 30 | super.attachBaseContext(base); 31 | 32 | // printAssets(); 33 | 34 | String appName = getReinforceApkAppName(); 35 | 36 | obj = onAppAttach(this, appName); 37 | 38 | Log.e("AppLoader", "attachBaseContext"); 39 | // try { 40 | // loadApp(this); 41 | // } catch (IOException e) { 42 | // e.printStackTrace(); 43 | // } 44 | // 45 | // loadResources(apkFileName); 46 | 47 | } 48 | 49 | // private void printAssets() { 50 | // try { 51 | // Log.e("AppLoader", "assets files: " + Arrays.asList(getAssets().list(""))); 52 | // } catch (IOException e) { 53 | // e.printStackTrace(); 54 | // } 55 | // } 56 | 57 | @Override 58 | public void onCreate() { 59 | super.onCreate(); 60 | 61 | // String appName = getReinforceApkAppName(); 62 | 63 | onAppCreate(this, obj, null); //"com.snowfish.cn.ganga.offline.helper.SFOfflineApplication" 64 | 65 | Log.e("AppLoader", "onApplicationCreate"); 66 | // try { 67 | // createApkApp("com.souying.pay.SouYingApplication"); 68 | // } catch (Exception e) { 69 | // e.printStackTrace(); 70 | // } 71 | } 72 | 73 | private String getReinforceApkAppName() { 74 | String appName = null; 75 | try { 76 | ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); 77 | appName = applicationInfo.metaData.getString("application_name"); 78 | appName = "null".equals(appName) ? null : appName; 79 | } catch (PackageManager.NameNotFoundException e) { 80 | e.printStackTrace(); 81 | } 82 | 83 | return appName; 84 | } 85 | 86 | // private void changeProvider(Object currentActivityThread, Object app) { 87 | // ArrayMap mProviderMap = (ArrayMap) RefInvoke.getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mProviderMap"); 88 | // Iterator it = mProviderMap.values().iterator(); 89 | // while (it.hasNext()) { 90 | // Object providerClientRecord = it.next(); 91 | // Object provider = RefInvoke.getFieldOjbect("android.app.ActivityThread$ProviderClientRecord", providerClientRecord, "mLocalProvider"); 92 | // if(provider != null) { 93 | // RefInvoke.setFieldOjbect("android.content.ContentProvider", "mContext", provider, app); 94 | // } 95 | // } 96 | // } 97 | 98 | // public void loadApp(Application application) throws IOException { 99 | // File apkPath = application.getDir("apkFile", Context.MODE_PRIVATE); 100 | // File libPath = application.getDir("apkLib", Context.MODE_PRIVATE); 101 | // apkFilePath = apkPath.getAbsolutePath(); 102 | // apkLibPath = libPath.getAbsolutePath(); 103 | // apkFileName = apkPath.getAbsolutePath() + "/loader.apk"; 104 | // 105 | // Log.d("AppLoader", "apk lib path: " + apkLibPath); 106 | // 107 | // copyApkFile(application); 108 | // Object currentActivityThread = RefInvoke.invokeStaticMethod( 109 | // "android.app.ActivityThread", "currentActivityThread", 110 | // new Class[] {}, new Object[] {}); 111 | // Map mPackages = (Map) RefInvoke.getFieldOjbect( 112 | // "android.app.ActivityThread", currentActivityThread, 113 | // "mPackages"); 114 | // WeakReference wr = (WeakReference) mPackages.get(application.getPackageName()); 115 | // DexClassLoader dLoader = new DexClassLoader(apkFileName, apkFilePath, 116 | // apkLibPath, (ClassLoader) RefInvoke.getFieldOjbect( 117 | // "android.app.LoadedApk", wr.get(), "mClassLoader")); 118 | // RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader", 119 | // wr.get(), dLoader); 120 | // RefInvoke.setFieldOjbect("android.app.LoadedApk", "mResDir", wr.get(), apkFileName); 121 | // 122 | // } 123 | 124 | // private void copyApkFile(Application application) throws IOException { 125 | // InputStream in = application.getAssets().open("Ldal.bin"); 126 | // File apkFile = new File(apkFileName); 127 | // if(apkFile.exists()) { 128 | // if(apkFile.length() == in.available()) { 129 | // in.close(); 130 | // return; 131 | // } else { 132 | // apkFile.delete(); 133 | // } 134 | // } 135 | // 136 | // apkFile.createNewFile(); 137 | // 138 | // FileOutputStream fout = new FileOutputStream(apkFile); 139 | // byte[] buffer = new byte[1024]; 140 | // int readLen = 0; 141 | // while ((readLen = in.read(buffer)) > 0) { 142 | // for(int i = 0; i < readLen; i++) { 143 | // buffer[i] = (byte) (buffer[i] ^ 0xa1); 144 | // } 145 | // 146 | // fout.write(buffer, 0, readLen); 147 | // } 148 | // 149 | // fout.flush(); 150 | // fout.close(); 151 | // in.close(); 152 | // 153 | // copyLibFile(); 154 | // } 155 | 156 | // private void copyLibFile() throws IOException { 157 | // File apkFile = new File(apkFileName); 158 | // ZipInputStream localZipInputStream = new ZipInputStream( 159 | // new BufferedInputStream(new FileInputStream(apkFile))); 160 | // while (true) { 161 | // ZipEntry localZipEntry = localZipInputStream.getNextEntry(); 162 | // if (localZipEntry == null) { 163 | // localZipInputStream.close(); 164 | // break; 165 | // } 166 | // String name = localZipEntry.getName(); 167 | // if (name.startsWith("lib/") && name.endsWith(".so")) { 168 | // File storeFile = new File(apkLibPath + "/" 169 | // + name.substring(name.lastIndexOf('/'))); 170 | // storeFile.createNewFile(); 171 | // FileOutputStream fos = new FileOutputStream(storeFile); 172 | // byte[] arrayOfByte = new byte[1024]; 173 | // while (true) { 174 | // int i = localZipInputStream.read(arrayOfByte); 175 | // if (i == -1) 176 | // break; 177 | // fos.write(arrayOfByte, 0, i); 178 | // } 179 | // fos.flush(); 180 | // fos.close(); 181 | // } 182 | // localZipInputStream.closeEntry(); 183 | // } 184 | // localZipInputStream.close(); 185 | // } 186 | 187 | // private void createApkApp(String appName) throws Exception { 188 | // if(TextUtils.isEmpty(appName)) { 189 | // appName = "android.app.Application"; 190 | // } 191 | // Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[0], new Object[0]); 192 | // Object mBoundApplication = RefInvoke.getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mBoundApplication"); 193 | // Object loadedApkInfo = RefInvoke.getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "info"); 194 | // RefInvoke.setFieldOjbect("android.app.LoadedApk", "mApplication", loadedApkInfo, null); 195 | // Object oldApplication = RefInvoke.getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mInitialApplication"); 196 | // ArrayList mAllApplications = (ArrayList) RefInvoke.getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mAllApplications"); 197 | // mAllApplications.remove(oldApplication); 198 | // 199 | // ApplicationInfo appinfo_In_LoadedApk = (ApplicationInfo) RefInvoke.getFieldOjbect("android.app.LoadedApk", loadedApkInfo, "mApplicationInfo"); 200 | // ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo) RefInvoke.getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "appInfo"); 201 | // 202 | // RefInvoke.setFieldOjbect("android.content.pm.ApplicationInfo", "sourceDir", appinfo_In_LoadedApk, apkFileName); 203 | // RefInvoke.setFieldOjbect("android.app.LoadedApk", "mResDir", loadedApkInfo, apkFileName); 204 | // RefInvoke.setFieldOjbect("android.app.LoadedApk", "mResources", loadedApkInfo, null); 205 | // 206 | // appinfo_In_LoadedApk.className = appName; 207 | // appinfo_In_AppBindData.className = appName; 208 | // 209 | // Application app = (Application) RefInvoke.invokeMethod("android.app.LoadedApk", "makeApplication", loadedApkInfo, new Class[] {boolean.class, Instrumentation.class}, new Object[] {false, null}); 210 | // ArrayMap mProviderMap = (ArrayMap) RefInvoke.getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mProviderMap"); 211 | // Iterator it = mProviderMap.values().iterator(); 212 | // while (it.hasNext()) { 213 | // Object providerClientRecord = it.next(); 214 | // Object provider = RefInvoke.getFieldOjbect("android.app.ActivityThread$ProviderClientRecord", providerClientRecord, "mLocalProvider"); 215 | // if(provider != null) { 216 | // RefInvoke.setFieldOjbect("android.content.ContentProvider", "mContext", provider, app); 217 | // } 218 | // } 219 | // 220 | // app.onCreate(); 221 | // } 222 | // 223 | // private void createApplication() { 224 | // try { 225 | // Class clsActThread = Class.forName("android.app.ActivityThread"); 226 | // Method currentActivityThread = clsActThread.getDeclaredMethod("currentActivityThread", new Class[0]); 227 | // currentActivityThread.setAccessible(true); 228 | // Object activityThread = currentActivityThread.invoke(null, new Object[0]); 229 | // Field mPackages = clsActThread.getDeclaredField("mPackages"); 230 | // mPackages.setAccessible(true); 231 | // Map packages = (Map) mPackages.get(activityThread); 232 | // WeakReference wr = (WeakReference) packages.get(getPackageName()); 233 | // Class clsLoadedApk = Class.forName("android.app.LoadedApk"); 234 | // Field mClassLoader = clsLoadedApk.getDeclaredField("mClassLoader"); 235 | // mClassLoader.setAccessible(true); 236 | // ClassLoader classLoader = (ClassLoader) mClassLoader.get(wr.get()); 237 | // Class clsApp = classLoader.loadClass("com.excelliance.open.LBApplication"); 238 | // clsApp.getDeclaredField("appContext").set(null, sApplication); 239 | // Application application = (Application) clsApp.newInstance(); 240 | // application.onCreate(); 241 | // } catch (ClassNotFoundException e) { 242 | // e.printStackTrace(); 243 | // } catch (NoSuchMethodException e) { 244 | // e.printStackTrace(); 245 | // } catch (InvocationTargetException e) { 246 | // e.printStackTrace(); 247 | // } catch (IllegalAccessException e) { 248 | // e.printStackTrace(); 249 | // } catch (NoSuchFieldException e) { 250 | // e.printStackTrace(); 251 | // } catch (InstantiationException e) { 252 | // e.printStackTrace(); 253 | // } 254 | // } 255 | 256 | private native void onAppCreate(Application app, Object obj, String application); 257 | private native Object onAppAttach(Application app, String application); 258 | 259 | // 以下是加载资源 260 | protected static AssetManager mAssetManager;//资源管理器 261 | protected Resources mResources;//资源 262 | protected Resources.Theme mTheme;//主题 263 | 264 | // protected void loadResources(String dexPath) { 265 | // try { 266 | // AssetManager assetManager = AssetManager.class.newInstance(); 267 | // Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); 268 | // addAssetPath.invoke(assetManager, dexPath); 269 | // mAssetManager = assetManager; 270 | // } catch (Exception e) { 271 | // e.printStackTrace(); 272 | // } 273 | // Resources superRes = super.getResources(); 274 | // superRes.getDisplayMetrics(); 275 | // superRes.getConfiguration(); 276 | // mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),superRes.getConfiguration()); 277 | // mTheme = mResources.newTheme(); 278 | // mTheme.setTo(super.getTheme()); 279 | // } 280 | 281 | 282 | @Override 283 | public AssetManager getAssets() { 284 | AssetManager assetManager = mAssetManager == null ? super.getAssets() : mAssetManager; 285 | return assetManager; 286 | } 287 | 288 | @Override 289 | public Resources getResources() { 290 | if(mAssetManager != null && mResources == null) { 291 | Resources superRes = super.getResources(); 292 | mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); 293 | } 294 | 295 | return mResources == null ? super.getResources() : mResources; 296 | } 297 | 298 | @Override 299 | public Resources.Theme getTheme() { 300 | if(mResources != null && mTheme == null) { 301 | mTheme = mResources.newTheme(); 302 | mTheme.setTo(super.getTheme()); 303 | } 304 | 305 | return mTheme == null ? super.getTheme() : mTheme; 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/app/src/main/res/mipmap-xhdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ReinforceApk 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | -------------------------------------------------------------------------------- /app/src/test/java/com/jd/apploader/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.jd.apploader; 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 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 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-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /reinforce.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/reinforce.apk -------------------------------------------------------------------------------- /reinforceapk/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /reinforceapk/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | } 6 | 7 | sourceCompatibility = "1.7" 8 | targetCompatibility = "1.7" 9 | 10 | 11 | jar { 12 | String someString = '' 13 | configurations.runtime.each {someString = someString + " lib//"+it.name} 14 | manifest { 15 | attributes 'Main-Class': 'com.max.reinforce.Main' 16 | // attributes 'Class-Path': someString 17 | } 18 | } -------------------------------------------------------------------------------- /reinforceapk/libs/dom4j-1.6.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/reinforceapk/libs/dom4j-1.6.1.jar -------------------------------------------------------------------------------- /reinforceapk/libs/snakeyaml-1.12.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/reinforceapk/libs/snakeyaml-1.12.jar -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/Main.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce; 2 | 3 | import com.max.reinforce.bean.ManifestInfo; 4 | import com.max.reinforce.shell.ShellPack; 5 | import com.max.reinforce.util.Apktool; 6 | import com.max.reinforce.util.FileUtils; 7 | import com.max.reinforce.util.Utils; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | public class Main { 13 | 14 | public static void main(String... args) throws Exception { 15 | 16 | // unpack game apk 17 | System.out.println("------unpack game apk-----"); 18 | Apktool.unpackApk(Utils.GAME_APK_NAME); 19 | 20 | // read game apk manifest info 21 | System.out.println("------read game apk manifest info-----"); 22 | ManifestInfo gameInfo = ManifestInfo.loadManifest(new File(Utils.GAME_APK_UNPACK_PATH)); 23 | // System.out.println(gameInfo.toString()); 24 | 25 | // unpack shell apk 26 | System.out.println("------unpack shell apk-----"); 27 | ShellPack shellPack = new ShellPack(); 28 | shellPack.unpackShellApk(Utils.SHELL_APK_NAME); 29 | 30 | // change shell manifest info 31 | System.out.println("------change shell manifest info-----"); 32 | shellPack.rewriteManifest(gameInfo, Utils.SHELL_APK_UNPACK_PATH); 33 | 34 | // change shell launcher icon 35 | System.out.println("------change shell launcher icon-----"); 36 | shellPack.copyLauncherIcon(gameInfo.iconResName); 37 | 38 | // change shell app name 39 | System.out.println("------change shell app name-----"); 40 | shellPack.changeAppName(gameInfo.appResName); 41 | 42 | // change shell app version name and version code 43 | System.out.println("------change shell app version name and version code-----"); 44 | shellPack.changeVersion(gameInfo.versionCode, gameInfo.versionName); 45 | 46 | // encrypt game apk and copy to shell apk assets directory 47 | System.out.println("------encrypt game apk and copy to shell apk assets directory-----"); 48 | encryptGameApk(); 49 | 50 | // read channel list 51 | 52 | // change channel id in shell apks 53 | 54 | // repack shell apk 55 | System.out.println("------repack shell apk-----"); 56 | shellPack.repackShell(); 57 | 58 | // encrypt game apk and write encrypted apk to shell dex file 59 | // System.out.println("------encrypt game apk and write encrypted apk to shell dex file-----"); 60 | // shellPack.copyGameApkToDex(); 61 | 62 | // sign shell apk 63 | System.out.println("------sign shell apk-----"); 64 | shellPack.signShellApk(gameInfo.packageName); 65 | } 66 | 67 | private static void encryptGameApk() throws IOException { 68 | File apkFile = new File(Utils.GAME_APK_NAME); 69 | byte[] apkFileBytes = encrypt(FileUtils.readFileBytes(apkFile)); 70 | 71 | FileUtils.writeBytes2File(Utils.GAME_APK_ENCRYPT_PATH, apkFileBytes); 72 | } 73 | 74 | private static byte[] encrypt(byte[] data) { 75 | for(int i = 0; i < data.length; i++) { 76 | data[i] = (byte) (0xa1 ^ data[i]); 77 | } 78 | return data; 79 | } 80 | 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/bean/ManifestInfo.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.bean; 2 | 3 | import org.dom4j.Attribute; 4 | import org.dom4j.Document; 5 | import org.dom4j.Element; 6 | import org.dom4j.io.SAXReader; 7 | import org.yaml.snakeyaml.Yaml; 8 | 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.io.IOException; 13 | import java.util.Iterator; 14 | 15 | /** 16 | * Created by Administrator on 2016/12/22. 17 | */ 18 | 19 | public class ManifestInfo { 20 | 21 | public String versionCode; 22 | public String versionName; 23 | public String applicationName; 24 | public String packageName; 25 | public String iconResName; 26 | public String appResName; 27 | public StringBuilder features; 28 | public StringBuilder content; 29 | 30 | 31 | 32 | public static ManifestInfo loadManifest(File file) throws Exception { 33 | ManifestInfo info = new ManifestInfo(); 34 | 35 | info.parseVersion(new File(file, "apktool.yml")); 36 | 37 | File manifestFile = new File(file, "AndroidManifest.xml"); 38 | if(!manifestFile.exists()) { 39 | throw new IOException("AndroidManifest.xml is not exists"); 40 | } 41 | 42 | info.parse(manifestFile); 43 | 44 | return info; 45 | } 46 | 47 | private void parseVersion(File file) throws FileNotFoundException { 48 | Yaml yaml = new Yaml(); 49 | MetaInfo metaInfo = yaml.loadAs(new FileInputStream(file), MetaInfo.class); 50 | versionCode = metaInfo.versionInfo.versionCode; 51 | versionName = metaInfo.versionInfo.versionName; 52 | 53 | System.out.println("versionCode: " + versionCode + ", versionName: " + versionName); 54 | } 55 | 56 | private void parse(File file) throws Exception { 57 | SAXReader reader = new SAXReader(); 58 | Document document = reader.read(file); 59 | Element root = document.getRootElement(); 60 | listNodes(root); 61 | } 62 | 63 | private void listNodes(Element node) throws Exception { 64 | String nodeName = node.getName(); 65 | if("manifest".equals(nodeName)) { 66 | packageName = readAttributeValue(node, "package"); 67 | if(packageName == null) { 68 | throw new Exception("parse AndroidManifest.xml failed. package name is null"); 69 | } 70 | } else if("application".equals(nodeName)) { 71 | iconResName = readAttributeValue(node, "icon"); 72 | appResName = readAttributeValue(node, "label"); 73 | applicationName = readAttributeValue(node, "name"); 74 | } else if("uses-feature".equals(nodeName) 75 | || "supports-screens".equals(nodeName) 76 | || "uses-permission".equals(nodeName)){ 77 | if(features == null) { 78 | features = new StringBuilder(); 79 | } 80 | 81 | String xml = node.asXML(); 82 | xml = xml.replace("xmlns:android=\"http://schemas.android.com/apk/res/android\" ", ""); 83 | features.append(xml).append("\n"); 84 | } else if("activity".equals(nodeName) 85 | || "service".equals(nodeName) 86 | || "receiver".equals(nodeName) 87 | || "provider".equals(nodeName) 88 | || "meta-data".equals(nodeName)) { 89 | if(content == null) { 90 | content = new StringBuilder(); 91 | } 92 | 93 | String xml = node.asXML(); 94 | xml = xml.replace("xmlns:android=\"http://schemas.android.com/apk/res/android\" ", ""); 95 | content.append(xml).append("\n"); 96 | } 97 | 98 | Iterator iterator = node.elementIterator(); 99 | while (iterator.hasNext()) { 100 | listNodes(iterator.next()); 101 | } 102 | } 103 | 104 | 105 | private String readAttributeValue(Element node, String name) { 106 | Attribute attribute = node.attribute(name); 107 | if(attribute != null) { 108 | return attribute.getValue(); 109 | } else { 110 | return null; 111 | } 112 | } 113 | 114 | @Override 115 | public String toString() { 116 | StringBuilder sb = new StringBuilder(); 117 | sb.append("versionCode: ").append(versionCode).append("\n"); 118 | sb.append("versionName: ").append(versionName).append("\n"); 119 | sb.append("applicationName: ").append(applicationName).append("\n"); 120 | sb.append("packageName: ").append(packageName).append("\n"); 121 | sb.append("iconResName: ").append(iconResName).append("\n"); 122 | sb.append("appResName: ").append(appResName).append("\n"); 123 | // sb.append("features: ").append(features).append("\n"); 124 | // sb.append("content: ").append(content); 125 | return sb.toString(); 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/bean/MetaInfo.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.bean; 2 | 3 | import java.util.Collection; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by Administrator on 2016/12/26. 8 | */ 9 | 10 | public class MetaInfo { 11 | public String version; 12 | public String apkFileName; 13 | public boolean isFrameworkApk; 14 | public UsesFramework usesFramework; 15 | public Map sdkInfo; 16 | public PackageInfo packageInfo; 17 | public VersionInfo versionInfo; 18 | public boolean compressionType; 19 | public boolean sharedLibrary; 20 | public Map unknownFiles; 21 | public Collection doNotCompress; 22 | } 23 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/bean/PackageInfo.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.bean; 2 | 3 | /** 4 | * Created by Administrator on 2016/12/26. 5 | */ 6 | 7 | public class PackageInfo { 8 | public String forcedPackageId; 9 | public String renameManifestPackage; 10 | } 11 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/bean/UsesFramework.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2016/12/26. 7 | */ 8 | 9 | public class UsesFramework { 10 | public List ids; 11 | public String tag; 12 | } 13 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/bean/VersionInfo.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.bean; 2 | 3 | /** 4 | * Created by Administrator on 2016/12/26. 5 | */ 6 | 7 | public class VersionInfo { 8 | public String versionCode; 9 | public String versionName; 10 | } 11 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/shell/ShellPack.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.shell; 2 | 3 | import com.max.reinforce.bean.ManifestInfo; 4 | import com.max.reinforce.util.Apktool; 5 | import com.max.reinforce.util.FileUtils; 6 | import com.max.reinforce.util.Utils; 7 | 8 | import java.io.BufferedInputStream; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileNotFoundException; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.security.MessageDigest; 16 | import java.security.NoSuchAlgorithmException; 17 | import java.util.List; 18 | import java.util.zip.Adler32; 19 | import java.util.zip.ZipEntry; 20 | import java.util.zip.ZipInputStream; 21 | import java.util.zip.ZipOutputStream; 22 | 23 | import static com.max.reinforce.util.Utils.encrypt; 24 | import static java.awt.SystemColor.info; 25 | 26 | 27 | /** 28 | * Created by Administrator on 2016/12/23. 29 | */ 30 | 31 | public class ShellPack { 32 | 33 | private String keystoreFile; 34 | private String keystorePass; 35 | private String keyAlias; 36 | 37 | public void unpackShellApk(String apkPath) throws Exception { 38 | Apktool.unpackApk(apkPath); 39 | } 40 | 41 | /** 42 | * replace package name 43 | * add application info such as android component, meta data and so on 44 | * @param gameInfo 45 | * @param dir 46 | */ 47 | public void rewriteManifest(ManifestInfo gameInfo, String dir) throws Exception { 48 | String filePath = dir + File.separator + "AndroidManifest.xml"; 49 | 50 | String shellManifest = FileUtils.readFile(filePath); 51 | if(shellManifest == null || shellManifest.isEmpty()) { 52 | throw new Exception("read shell manifest failed, read from file is empty"); 53 | } 54 | 55 | StringBuilder sb = new StringBuilder(); 56 | // replace package name 57 | String regex = "(package=\".*?\")"; 58 | String replace = "package=\"" + gameInfo.packageName + "\""; 59 | shellManifest = shellManifest.replaceAll(regex, replace); 60 | 61 | String[]split = shellManifest.split(""); 62 | int startIndex = split[0].length(); 63 | int endIndex = shellManifest.indexOf(split[1]); 64 | String applicationStr = shellManifest.substring(startIndex, endIndex); 65 | String content = gameInfo.content.toString().replace("@style/lttransparent", "@android:style/Theme.Translucent.NoTitleBar.Fullscreen"); 66 | if(gameInfo.applicationName != null && !gameInfo.applicationName.isEmpty()) { 67 | split[1] = split[1].replace("null", gameInfo.applicationName); 68 | } 69 | 70 | sb.append(split[0]); 71 | sb.append(gameInfo.features); 72 | sb.append(applicationStr); 73 | sb.append(content); 74 | sb.append(split[1]); 75 | 76 | FileUtils.writeFile(filePath, sb.toString()); 77 | } 78 | 79 | public void copyLauncherIcon(String gameIconRes) throws Exception { 80 | String iconName = gameIconRes.substring(gameIconRes.indexOf("/") + 1) + "."; 81 | List drawableDirs = FileUtils.getSubFiles(Utils.GAME_APK_UNPACK_PATH + "/res", "drawable"); 82 | if(drawableDirs == null || drawableDirs.size() == 0) { 83 | throw new Exception("game apk drawable dir is null"); 84 | } 85 | 86 | for(File file : drawableDirs) { 87 | List iconFiles = FileUtils.getSubFiles(file.getAbsolutePath(), iconName); 88 | if(iconFiles != null && iconFiles.size() > 0) { 89 | for(File icFile : iconFiles) { 90 | String name = icFile.getName(); 91 | String fileName = name.substring(0, name.indexOf(".") + 1); 92 | if(fileName.equals(iconName)) { 93 | String suffix = name.replace(iconName, "."); 94 | String destName = Utils.SHELL_LAUCHER_ICON_PATH + suffix; 95 | FileUtils.copyFile(icFile.getAbsolutePath(), destName); 96 | return; 97 | } 98 | } 99 | 100 | } 101 | } 102 | } 103 | 104 | public void changeAppName(String gameAppNameRes) throws Exception { 105 | String appResName = gameAppNameRes.substring(gameAppNameRes.indexOf("/") + 1); 106 | String appName = FileUtils.readStringRes(Utils.GAME_APK_STRING_RES_PATH, appResName); 107 | System.out.println("game apk app name: " + appName); 108 | if(appName == null || appName.isEmpty()) { 109 | throw new Exception("read game apk app name failed, app name is empty"); 110 | } 111 | 112 | String stringsResContent = FileUtils.readFile(Utils.SHELL_STRING_RES_PATH); 113 | if(stringsResContent == null || stringsResContent.isEmpty()) { 114 | throw new Exception("shell strings resource is empty"); 115 | } 116 | 117 | stringsResContent = stringsResContent.replace(Utils.SHELL_APP_NAME, appName); 118 | 119 | System.out.println("changeAppName new strings content: " + stringsResContent); 120 | FileUtils.writeFile(Utils.SHELL_STRING_RES_PATH, stringsResContent); 121 | } 122 | 123 | public void changeVersion(String gameVerCode, String gameVerName) throws Exception { 124 | String apktoolContent = FileUtils.readFile(Utils.SHELL_APKTOOL_YML_PATH); 125 | if(apktoolContent == null || apktoolContent.isEmpty()) { 126 | throw new Exception("read apktool.yml failed"); 127 | } 128 | 129 | String versionCodeStr = "versionCode: '"; 130 | int codeStartIndex = apktoolContent.indexOf(versionCodeStr); 131 | int codeEndIndex = apktoolContent.lastIndexOf("'"); 132 | String versionCode = apktoolContent.substring(codeStartIndex, codeEndIndex); 133 | System.out.println(versionCode); 134 | 135 | String versionNameStr = "versionName: "; 136 | int nameStartIndex = apktoolContent.indexOf(versionNameStr); 137 | String name = apktoolContent.substring(nameStartIndex); 138 | apktoolContent = apktoolContent.replace(versionCode, versionCodeStr + gameVerCode); 139 | apktoolContent = apktoolContent.replace(name, versionNameStr + gameVerName); 140 | 141 | FileUtils.writeFile(Utils.SHELL_APKTOOL_YML_PATH, apktoolContent); 142 | } 143 | 144 | public void repackShell() throws Exception { 145 | Apktool.repackApk(Utils.SHELL_APK_UNPACK_PATH); 146 | } 147 | 148 | private void buildSignKey(String packageName) throws Exception { 149 | String signFileName = "sign." + packageName + ".keystore"; 150 | keystoreFile = Utils.OUTPUT_DIR + packageName + File.separator + signFileName; 151 | File file = new File(keystoreFile); 152 | File parent = file.getParentFile(); 153 | if(!parent.exists()) { 154 | parent.mkdirs(); 155 | } 156 | 157 | keystorePass = encrypt(packageName + System.currentTimeMillis()); 158 | String[] splits = packageName.split("\\."); 159 | int index = (int) (Math.random() * splits.length); 160 | index = index >= splits.length ? index - 1 : index; 161 | keyAlias = splits[index]; 162 | 163 | // if(file.exists()) { 164 | // buildSignProperty(packageName); 165 | // return; 166 | // } 167 | 168 | System.out.println("keyAlias: " + keyAlias + ", password: " + keystorePass); 169 | 170 | int keyAliasLen = keyAlias.length(); 171 | int storepassLen = keystorePass.length(); 172 | String cn = keyAlias.substring(0, (int) (Math.random() * keyAliasLen)); 173 | cn = cn.length() == 0 ? keyAlias : cn; 174 | index++; 175 | String ou = splits[index < splits.length ? index : 0]; 176 | String o = packageName.substring(packageName.lastIndexOf(".") + 1); 177 | int start = (int) (Math.random() * (storepassLen - 5)); 178 | int end = (int) (Math.random() * storepassLen); 179 | String l; 180 | if(start < end) { 181 | l = keystorePass.substring(start, end); 182 | } else if(start > end){ 183 | l = keystorePass.substring(end, start); 184 | } else { 185 | start = start == 0 ? 5 : start; 186 | l = keystorePass.substring(0, start); 187 | } 188 | String st = cn + ou; 189 | String c = o + l; 190 | 191 | String info = String.format("CN=%s,OU=%s,O=%s,L=%s,ST=%s,C=%s", cn, ou, o, l, st, c); 192 | String cmd = String.format("keytool -genkey -alias %s -keyalg RSA -validity 20000 -keystore %s -storepass %s -keypass %s -dname %s", new Object[] { keyAlias, keystoreFile, keystorePass, keystorePass, info }); 193 | Utils.execmd(cmd); 194 | 195 | // buildSignProperty(packageName); 196 | } 197 | 198 | private void buildSignProperty(String packageName) throws IOException { 199 | String propertyPath = Utils.OUTPUT_DIR + packageName + File.separator + "signkey.property"; 200 | File file = new File(propertyPath); 201 | if(file.exists()) { 202 | return; 203 | } 204 | 205 | StringBuilder sb = new StringBuilder(); 206 | sb.append("key.store.pass=").append(keystorePass).append("\n"); 207 | sb.append("key.alias=").append(keyAlias).append("\n"); 208 | sb.append("key.alias.pass=").append(keystorePass); 209 | FileUtils.writeFile(propertyPath, sb.toString()); 210 | } 211 | 212 | public void signShellApk(String packageName) throws Exception { 213 | File outputsDir = new File(Utils.OUTPUT_DIR + packageName); 214 | FileUtils.deleteFile(outputsDir); 215 | outputsDir.mkdirs(); 216 | 217 | buildSignKey(packageName); 218 | 219 | File file = new File(outputsDir, Utils.OUTPUT_SIGNED_APK_NAME); 220 | // if(file.exists()) { 221 | // file.delete(); 222 | // } 223 | StringBuilder sb = new StringBuilder(); 224 | sb.append("jarsigner -verbose -keystore "); 225 | sb.append(keystoreFile).append(" "); 226 | sb.append("-storepass ").append(keystorePass).append(" "); 227 | sb.append("-keypass ").append(keystorePass).append(" "); 228 | sb.append("-sigfile CERT -digestalg SHA1 -sigalg MD5withRSA "); 229 | sb.append("-signedjar ").append(file.getAbsolutePath()).append(" "); 230 | sb.append("shell/dist/shell.apk "); 231 | sb.append(keyAlias); 232 | String cmd = sb.toString(); 233 | Utils.execmd(cmd); 234 | 235 | FileUtils.deleteFile(new File(keystoreFile)); 236 | } 237 | 238 | public void copyGameApkToDex() throws Exception { 239 | File apkFile = new File(Utils.REPACK_SHELL_APK_PATH); 240 | byte[] apkFileBytes = Utils.encrypt(FileUtils.readFileBytes(apkFile)); 241 | System.out.println("read reinforce apk file byte, length: " + apkFileBytes.length); 242 | byte[] dexFileBytes = readDexFile(); 243 | System.out.println("read shell apk file byte, length: " + dexFileBytes.length); 244 | int apkFileLen = apkFileBytes.length; 245 | int dexFileLen = dexFileBytes.length; 246 | int totalLength = apkFileLen + dexFileLen + 4; 247 | System.out.println("new dex file length: " + totalLength); 248 | byte[] newDexBytes = new byte[totalLength]; 249 | // copy dex file 250 | System.out.println("copy shell dex file bytes to new byte array"); 251 | System.arraycopy(dexFileBytes, 0, newDexBytes, 0, dexFileLen); 252 | 253 | // copy apk file 254 | System.out.println("copy reinforce apk file bytes to new byte array"); 255 | System.arraycopy(apkFileBytes, 0, newDexBytes, dexFileLen, apkFileLen); 256 | 257 | // set apk file len 258 | System.out.println("write apk file length to byte array"); 259 | System.arraycopy(Utils.intToByte(apkFileLen), 0, newDexBytes, totalLength - 4, 4); 260 | 261 | System.out.println("fix new dex file size head"); 262 | fixFileSizeHead(newDexBytes); 263 | 264 | System.out.println("fix new dex file sha1 head"); 265 | fixSHA1Head(newDexBytes); 266 | 267 | System.out.println("fix new dex file check sum head"); 268 | fixCheckSumHead(newDexBytes); 269 | 270 | System.out.println("write new dex file to shell apk"); 271 | writeDexBytesToFile(newDexBytes); 272 | } 273 | 274 | private byte[] readDexFile() throws IOException { 275 | ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream(); 276 | ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(Utils.SHELL_APK_NAME))); 277 | ZipEntry zipEntry = zipInputStream.getNextEntry(); 278 | while (zipEntry != null) { 279 | if("classes.dex".equals(zipEntry.getName())) { 280 | byte[] buffer = new byte[1024]; 281 | int len = 0; 282 | while ((len = zipInputStream.read(buffer)) > 0) { 283 | dexByteArrayOutputStream.write(buffer, 0, len); 284 | } 285 | 286 | zipInputStream.closeEntry(); 287 | break; 288 | } 289 | 290 | zipInputStream.closeEntry(); 291 | zipEntry = zipInputStream.getNextEntry(); 292 | } 293 | zipInputStream.close(); 294 | byte[] dexBuffer = dexByteArrayOutputStream.toByteArray(); 295 | dexByteArrayOutputStream.close(); 296 | return dexBuffer; 297 | } 298 | 299 | private void fixFileSizeHead(byte[] dexBytes) { 300 | byte[] fileLenBytes = Utils.intToByte(dexBytes.length); 301 | byte[] trans = new byte[4]; 302 | for(int i = 0; i < 4; i++) { 303 | trans[i] = fileLenBytes[3 - i]; 304 | } 305 | 306 | System.arraycopy(trans, 0, dexBytes, 32, 4); //size head position is 32 307 | } 308 | 309 | private void fixSHA1Head(byte[] dexBytes) throws NoSuchAlgorithmException { 310 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 311 | md.update(dexBytes, 32, dexBytes.length - 32); //from 32 position to end 312 | byte[] newDgt = md.digest(); 313 | System.arraycopy(newDgt, 0, dexBytes, 12, 20); // sha1 head position is 12 314 | } 315 | 316 | private void fixCheckSumHead(byte[] dexBytes) { 317 | Adler32 adler = new Adler32(); 318 | adler.update(dexBytes, 12, dexBytes.length - 12); // check sum from position 12 319 | long value = adler.getValue(); 320 | int va = (int) value; 321 | byte[] vaBytes = Utils.intToByte(va); 322 | byte[] trans = new byte[4]; 323 | for(int i = 0; i < 4; i++) { 324 | trans[i] = vaBytes[3 - i]; 325 | } 326 | 327 | System.arraycopy(trans, 0, dexBytes, 8, 4); // check sum position is 8 328 | } 329 | 330 | private void writeDexBytesToFile(byte[] dexBytes) throws Exception { 331 | String tempApk = "shell/dist/temp.apk"; 332 | ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(Utils.REPACK_SHELL_APK_PATH))); 333 | ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(tempApk)); 334 | ZipEntry zipEntry = zipInputStream.getNextEntry(); 335 | while (zipEntry != null) { 336 | if("classes.dex".equals(zipEntry.getName())) { 337 | zipEntry = zipInputStream.getNextEntry(); 338 | zipInputStream.closeEntry(); 339 | continue; 340 | } 341 | 342 | ZipEntry entry = new ZipEntry(zipEntry.getName()); 343 | zipOutputStream.putNextEntry(entry); 344 | byte[] buffer = new byte[1024]; 345 | int len = 0; 346 | while ((len = zipInputStream.read(buffer)) > 0) { 347 | zipOutputStream.write(buffer, 0, len); 348 | } 349 | 350 | zipInputStream.closeEntry(); 351 | zipEntry = zipInputStream.getNextEntry(); 352 | } 353 | ZipEntry entry = new ZipEntry("classes.dex"); 354 | zipOutputStream.putNextEntry(entry); 355 | zipOutputStream.write(dexBytes, 0, dexBytes.length); 356 | zipOutputStream.closeEntry(); 357 | zipOutputStream.close(); 358 | zipInputStream.close(); 359 | 360 | FileUtils.copyFile(tempApk, Utils.REPACK_SHELL_APK_PATH); 361 | } 362 | 363 | } 364 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/util/Apktool.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.util; 2 | 3 | /** 4 | * Created by Administrator on 2016/12/26. 5 | */ 6 | 7 | public class Apktool { 8 | 9 | public static final String APKTOOL_JAR_PATH = "apktool/apktool_2.1.1.jar"; 10 | 11 | public static void unpackApk(String apkName) throws Exception { 12 | StringBuilder sb = new StringBuilder(); 13 | sb.append("java -jar ").append(APKTOOL_JAR_PATH); 14 | sb.append(" -f d ").append(apkName); 15 | Utils.execmd(sb.toString()); 16 | } 17 | 18 | public static void repackApk(String apkPath) throws Exception { 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append("java -jar ").append(APKTOOL_JAR_PATH); 21 | sb.append(" -f b ").append(apkPath); 22 | Utils.execmd(sb.toString()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/util/Base64.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.util; 2 | 3 | public final class Base64 { 4 | 5 | static private final int BASELENGTH = 128; 6 | static private final int LOOKUPLENGTH = 64; 7 | static private final int TWENTYFOURBITGROUP = 24; 8 | static private final int EIGHTBIT = 8; 9 | static private final int SIXTEENBIT = 16; 10 | static private final int FOURBYTE = 4; 11 | static private final int SIGN = -128; 12 | static private final char PAD = '='; 13 | static private final boolean fDebug = false; 14 | static final private byte[] base64Alphabet = new byte[BASELENGTH]; 15 | static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; 16 | 17 | static { 18 | for (int i = 0; i < BASELENGTH; ++i) { 19 | base64Alphabet[i] = -1; 20 | } 21 | for (int i = 'Z'; i >= 'A'; i--) { 22 | base64Alphabet[i] = (byte) (i - 'A'); 23 | } 24 | for (int i = 'z'; i >= 'a'; i--) { 25 | base64Alphabet[i] = (byte) (i - 'a' + 26); 26 | } 27 | 28 | for (int i = '9'; i >= '0'; i--) { 29 | base64Alphabet[i] = (byte) (i - '0' + 52); 30 | } 31 | 32 | base64Alphabet['+'] = 62; 33 | base64Alphabet['/'] = 63; 34 | 35 | for (int i = 0; i <= 25; i++) { 36 | lookUpBase64Alphabet[i] = (char) ('A' + i); 37 | } 38 | 39 | for (int i = 26, j = 0; i <= 51; i++, j++) { 40 | lookUpBase64Alphabet[i] = (char) ('a' + j); 41 | } 42 | 43 | for (int i = 52, j = 0; i <= 61; i++, j++) { 44 | lookUpBase64Alphabet[i] = (char) ('0' + j); 45 | } 46 | lookUpBase64Alphabet[62] = (char) '+'; 47 | lookUpBase64Alphabet[63] = (char) '/'; 48 | 49 | } 50 | 51 | private static boolean isWhiteSpace(char octect) { 52 | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); 53 | } 54 | 55 | private static boolean isPad(char octect) { 56 | return (octect == PAD); 57 | } 58 | 59 | private static boolean isData(char octect) { 60 | return (octect < BASELENGTH && base64Alphabet[octect] != -1); 61 | } 62 | 63 | /** 64 | * Encodes hex octects into Base64 65 | * 66 | * @param binaryData Array containing binaryData 67 | * @return Encoded Base64 array 68 | */ 69 | public static String encode(byte[] binaryData) { 70 | 71 | if (binaryData == null) { 72 | return null; 73 | } 74 | 75 | int lengthDataBits = binaryData.length * EIGHTBIT; 76 | if (lengthDataBits == 0) { 77 | return ""; 78 | } 79 | 80 | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 81 | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 82 | int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; 83 | char encodedData[] = null; 84 | 85 | encodedData = new char[numberQuartet * 4]; 86 | 87 | byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 88 | 89 | int encodedIndex = 0; 90 | int dataIndex = 0; 91 | if (fDebug) { 92 | System.out.println("number of triplets = " + numberTriplets); 93 | } 94 | 95 | for (int i = 0; i < numberTriplets; i++) { 96 | b1 = binaryData[dataIndex++]; 97 | b2 = binaryData[dataIndex++]; 98 | b3 = binaryData[dataIndex++]; 99 | 100 | if (fDebug) { 101 | System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); 102 | } 103 | 104 | l = (byte) (b2 & 0x0f); 105 | k = (byte) (b1 & 0x03); 106 | 107 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 108 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 109 | byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); 110 | 111 | if (fDebug) { 112 | System.out.println("val2 = " + val2); 113 | System.out.println("k4 = " + (k << 4)); 114 | System.out.println("vak = " + (val2 | (k << 4))); 115 | } 116 | 117 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 118 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 119 | encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; 120 | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; 121 | } 122 | 123 | // form integral number of 6-bit groups 124 | if (fewerThan24bits == EIGHTBIT) { 125 | b1 = binaryData[dataIndex]; 126 | k = (byte) (b1 & 0x03); 127 | if (fDebug) { 128 | System.out.println("b1=" + b1); 129 | System.out.println("b1<<2 = " + (b1 >> 2)); 130 | } 131 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 132 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 133 | encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; 134 | encodedData[encodedIndex++] = PAD; 135 | encodedData[encodedIndex++] = PAD; 136 | } else if (fewerThan24bits == SIXTEENBIT) { 137 | b1 = binaryData[dataIndex]; 138 | b2 = binaryData[dataIndex + 1]; 139 | l = (byte) (b2 & 0x0f); 140 | k = (byte) (b1 & 0x03); 141 | 142 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 143 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 144 | 145 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 146 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 147 | encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; 148 | encodedData[encodedIndex++] = PAD; 149 | } 150 | 151 | return new String(encodedData); 152 | } 153 | 154 | /** 155 | * Decodes Base64 data into octects 156 | * 157 | * @param encoded string containing Base64 data 158 | * @return Array containind decoded data. 159 | */ 160 | public static byte[] decode(String encoded) { 161 | 162 | if (encoded == null) { 163 | return null; 164 | } 165 | 166 | char[] base64Data = encoded.toCharArray(); 167 | // remove white spaces 168 | int len = removeWhiteSpace(base64Data); 169 | 170 | if (len % FOURBYTE != 0) { 171 | return null;//should be divisible by four 172 | } 173 | 174 | int numberQuadruple = (len / FOURBYTE); 175 | 176 | if (numberQuadruple == 0) { 177 | return new byte[0]; 178 | } 179 | 180 | byte decodedData[] = null; 181 | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; 182 | char d1 = 0, d2 = 0, d3 = 0, d4 = 0; 183 | 184 | int i = 0; 185 | int encodedIndex = 0; 186 | int dataIndex = 0; 187 | decodedData = new byte[(numberQuadruple) * 3]; 188 | 189 | for (; i < numberQuadruple - 1; i++) { 190 | 191 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) 192 | || !isData((d3 = base64Data[dataIndex++])) 193 | || !isData((d4 = base64Data[dataIndex++]))) { 194 | return null; 195 | }//if found "no data" just return null 196 | 197 | b1 = base64Alphabet[d1]; 198 | b2 = base64Alphabet[d2]; 199 | b3 = base64Alphabet[d3]; 200 | b4 = base64Alphabet[d4]; 201 | 202 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 203 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 204 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 205 | } 206 | 207 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { 208 | return null;//if found "no data" just return null 209 | } 210 | 211 | b1 = base64Alphabet[d1]; 212 | b2 = base64Alphabet[d2]; 213 | 214 | d3 = base64Data[dataIndex++]; 215 | d4 = base64Data[dataIndex++]; 216 | if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters 217 | if (isPad(d3) && isPad(d4)) { 218 | if ((b2 & 0xf) != 0)//last 4 bits should be zero 219 | { 220 | return null; 221 | } 222 | byte[] tmp = new byte[i * 3 + 1]; 223 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 224 | tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 225 | return tmp; 226 | } else if (!isPad(d3) && isPad(d4)) { 227 | b3 = base64Alphabet[d3]; 228 | if ((b3 & 0x3) != 0)//last 2 bits should be zero 229 | { 230 | return null; 231 | } 232 | byte[] tmp = new byte[i * 3 + 2]; 233 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 234 | tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 235 | tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 236 | return tmp; 237 | } else { 238 | return null; 239 | } 240 | } else { //No PAD e.g 3cQl 241 | b3 = base64Alphabet[d3]; 242 | b4 = base64Alphabet[d4]; 243 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 244 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 245 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 246 | 247 | } 248 | 249 | return decodedData; 250 | } 251 | 252 | /** 253 | * remove WhiteSpace from MIME containing encoded Base64 data. 254 | * 255 | * @param data the byte array of base64 data (with WS) 256 | * @return the new length 257 | */ 258 | private static int removeWhiteSpace(char[] data) { 259 | if (data == null) { 260 | return 0; 261 | } 262 | 263 | // count characters that's not whitespace 264 | int newSize = 0; 265 | int len = data.length; 266 | for (int i = 0; i < len; i++) { 267 | if (!isWhiteSpace(data[i])) { 268 | data[newSize++] = data[i]; 269 | } 270 | } 271 | return newSize; 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.util; 2 | 3 | import org.dom4j.Attribute; 4 | import org.dom4j.Document; 5 | import org.dom4j.DocumentException; 6 | import org.dom4j.Element; 7 | import org.dom4j.io.SAXReader; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.BufferedWriter; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.io.InputStreamReader; 17 | import java.io.OutputStreamWriter; 18 | import java.util.ArrayList; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by Administrator on 2016/12/23. 24 | */ 25 | 26 | public class FileUtils { 27 | 28 | public static String readFile(String filePath) throws Exception { 29 | File file = new File(filePath); 30 | if(!file.exists()) { 31 | throw new Exception("shell apk AndroidManifest.xml is not exists!"); 32 | } 33 | 34 | BufferedReader reader = null; 35 | StringBuilder builder = null; 36 | try { 37 | reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); 38 | int readLen; 39 | char[] buffer = new char[1024]; 40 | builder = new StringBuilder(); 41 | while ((readLen = reader.read(buffer)) > 0) { 42 | builder.append(new String(buffer, 0, readLen)); 43 | } 44 | } finally { 45 | if(reader != null) { 46 | reader.close(); 47 | } 48 | } 49 | 50 | return builder == null ? null : builder.toString(); 51 | } 52 | 53 | public static void writeFile(String filePath, String content) throws IOException { 54 | File file = new File(filePath); 55 | if(file.exists()) { 56 | file.delete(); 57 | } 58 | 59 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); 60 | writer.write(content); 61 | writer.close(); 62 | 63 | } 64 | 65 | public static List getSubFiles(String parent, String subName) throws Exception { 66 | File parentFile = new File(parent); 67 | if(!parentFile.exists()) { 68 | throw new Exception("getSubFile failed, parent file " + parent + " is not exists"); 69 | } 70 | 71 | ArrayList files = new ArrayList<>(); 72 | File[] subFiles = parentFile.listFiles(); 73 | for(File file : subFiles) { 74 | if(file.getName().contains(subName)) { 75 | files.add(file); 76 | } 77 | } 78 | 79 | return files; 80 | } 81 | 82 | public static void copyFile(String src, String dest) throws Exception { 83 | File srcFile = new File(src); 84 | if(!srcFile.exists()) { 85 | throw new Exception("copy file failed, source file " + src + " is not exists"); 86 | } 87 | 88 | File destFile = new File(dest); 89 | if(destFile.exists()) { 90 | destFile.delete(); 91 | } 92 | 93 | FileInputStream inputStream = null; 94 | FileOutputStream outputStream = null; 95 | 96 | try { 97 | 98 | inputStream = new FileInputStream(srcFile); 99 | outputStream= new FileOutputStream(destFile); 100 | 101 | int readBytes = 0; 102 | byte[] buffer = new byte[1024]; 103 | while ((readBytes = inputStream.read(buffer)) > 0) { 104 | outputStream.write(buffer, 0, readBytes); 105 | } 106 | } finally { 107 | if(inputStream != null) { 108 | inputStream.close(); 109 | } 110 | 111 | if(outputStream != null) { 112 | outputStream.close(); 113 | } 114 | } 115 | 116 | } 117 | 118 | public static String readStringRes(String path, String resName) throws DocumentException { 119 | SAXReader reader = new SAXReader(); 120 | Document document = reader.read(path); 121 | Element root = document.getRootElement(); 122 | Iterator iterator = root.elementIterator(); 123 | while (iterator.hasNext()) { 124 | Element node = iterator.next(); 125 | if(node.getName().equals("string")) { 126 | Attribute attribute = node.attribute("name"); 127 | if(resName.equals(attribute.getValue())) { 128 | return node.getTextTrim(); 129 | } 130 | } 131 | } 132 | 133 | return null; 134 | } 135 | 136 | public static void writeBytes2File(String fileName, byte[] bytes) throws IOException { 137 | File file = new File(fileName); 138 | File parent = file.getParentFile(); 139 | if(!parent.exists()) { 140 | parent.mkdirs(); 141 | } 142 | 143 | if(file.exists()) { 144 | file.delete(); 145 | } 146 | 147 | FileOutputStream fos = new FileOutputStream(file); 148 | fos.write(bytes); 149 | fos.flush(); 150 | fos.close(); 151 | } 152 | 153 | 154 | 155 | public static byte[] readFileBytes(File file) throws IOException { 156 | byte[] buffers = new byte[1024]; 157 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 158 | FileInputStream is = new FileInputStream(file); 159 | int i = 0; 160 | while ((i = is.read(buffers)) > 0) { 161 | baos.write(buffers, 0, i); 162 | } 163 | 164 | byte[] fileBytes = baos.toByteArray(); 165 | baos.close(); 166 | is.close(); 167 | 168 | return fileBytes; 169 | } 170 | 171 | public static void deleteFile(File file) { 172 | if(file.exists()) { 173 | if(file.isFile()) { 174 | file.delete(); 175 | } else if(file.isDirectory()){ 176 | File[] subFiles = file.listFiles(); 177 | for(File sub : subFiles) { 178 | deleteFile(sub); 179 | } 180 | 181 | file.delete(); 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/util/InputStreamRunnable.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.PrintStream; 8 | 9 | /** 10 | * Created by Administrator on 2016/12/26. 11 | */ 12 | 13 | public class InputStreamRunnable extends Thread { 14 | 15 | private BufferedReader mInStream = null; 16 | private PrintStream mOutStreadm = null; 17 | 18 | public InputStreamRunnable(InputStream in, PrintStream out) { 19 | mInStream = new BufferedReader(new InputStreamReader(in)); 20 | mOutStreadm = out; 21 | } 22 | 23 | @Override 24 | public void run() { 25 | String line = null; 26 | try { 27 | while ((line = mInStream.readLine()) != null) { 28 | mOutStreadm.println(line); 29 | Thread.sleep(1); 30 | } 31 | 32 | mInStream.close(); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /reinforceapk/src/main/java/com/max/reinforce/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.max.reinforce.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * Created by Administrator on 2016/12/23. 7 | */ 8 | 9 | public class Utils { 10 | 11 | public static final String GAME_APK_NAME = "reinforce.apk"; 12 | public static final String GAME_APK_UNPACK_PATH = "reinforce"; 13 | public static final String SHELL_APK_NAME = "shell.apk"; 14 | public static final String SHELL_APK_UNPACK_PATH = "shell"; 15 | public static final String SHELL_LAUCHER_ICON_PATH = "shell/res/mipmap-xhdpi-v4/icon"; 16 | public static final String SHELL_APP_NAME = "ReinforceApk"; 17 | public static final String SHELL_STRING_RES_PATH = "shell/res/values/strings.xml"; 18 | public static final String GAME_APK_STRING_RES_PATH = "reinforce/res/values/strings.xml"; 19 | public static final String SHELL_APKTOOL_YML_PATH = "shell/apktool.yml"; 20 | public static final String GAME_APK_ENCRYPT_PATH = "shell/assets/Ldal.bin"; 21 | public static final String OUTPUT_SIGNED_APK_NAME = "signed.apk"; 22 | public static final String OUTPUT_DIR = "outputs/"; 23 | public static final String REPACK_SHELL_APK_PATH = "shell/dist/shell.apk"; 24 | 25 | /** 26 | * 27 | * @param str 28 | * @return 29 | * @throws UnsupportedEncodingException 30 | */ 31 | public static String encrypt(String str) { 32 | String os; 33 | StringBuilder sb = null; 34 | try { 35 | os = Base64.encode(str.getBytes("utf-8")); 36 | sb = new StringBuilder(); 37 | for (int i = 0; i < os.length(); i++) { 38 | int c = os.charAt(i); 39 | sb.append((char) (c + 1)); 40 | } 41 | } catch (UnsupportedEncodingException e) { 42 | e.printStackTrace(); 43 | } 44 | return sb.toString(); 45 | } 46 | 47 | /** 48 | * 49 | * @param str 50 | * @return 51 | * @throws UnsupportedEncodingException 52 | */ 53 | public static String decrypt(String str) { 54 | StringBuilder sb = new StringBuilder(); 55 | for (int i = 0; i < str.length(); i++) { 56 | int c = str.charAt(i); 57 | sb.append((char) (c - 1)); 58 | } 59 | try { 60 | byte[] strBytes = Base64.decode(sb.toString()); 61 | if(strBytes == null) { 62 | return null; 63 | } 64 | return new String(strBytes,"utf-8"); 65 | } catch (UnsupportedEncodingException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | return null; 70 | } 71 | 72 | public static byte[] encrypt(byte[] data) { 73 | for(int i = 0; i < data.length; i++) { 74 | data[i] = (byte) (0xa1 ^ data[i]); 75 | } 76 | return data; 77 | } 78 | 79 | public static byte[] intToByte(int number) { 80 | byte[] b = new byte[4]; 81 | for(int i = 3; i >= 0; i--) { 82 | b[i] = (byte) (number % 256); 83 | number >>= 8; 84 | } 85 | 86 | return b; 87 | } 88 | 89 | public static void execmd(String cmd) throws Exception { 90 | System.out.println(cmd); 91 | Process p = Runtime.getRuntime().exec(cmd); 92 | InputStreamRunnable outPrinter = new InputStreamRunnable(p.getInputStream(), System.out); 93 | InputStreamRunnable errPrinter = new InputStreamRunnable(p.getErrorStream(), System.err); 94 | 95 | outPrinter.start(); 96 | errPrinter.start(); 97 | 98 | int ret = p.waitFor(); 99 | if(ret != 0) { 100 | throw new Exception("run cmd failed: " + cmd); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':apkdexproccessor', ':reinforceapk' 2 | -------------------------------------------------------------------------------- /shell.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilxie/ReinforceApp/1e864a437d03d69c06408022138d55177ff6318a/shell.apk --------------------------------------------------------------------------------