android apk 防止反編譯技術加殼技術(轉)

1、加殼技術原理 java

所謂apk的加殼技術和pc exe的加殼原理同樣,就是在程序的外面再包裹上另一段代碼,保護裏面的代碼不被非法修改或反編譯,在程序運行的時候優先取得程序的控制權作一些咱們本身想作的工做。 android

PC exe的加殼原理以下: shell

2、android apk加殼實現 app

  要想實現加殼須要解決的技術點以下: ide

1)怎麼第一時間執行咱們的加殼程序? this

首先根據上面的原理咱們在apk中要想優先取得程序的控制權做爲android apk的開發人員都知道Application會被系統第一時間調用而咱們的程序也會放在這裏執行。 加密

2)怎麼將咱們的加殼程序和原有的android apk文件合併到一塊兒? spa

咱們知道android apk最終會打包生成dex文件,咱們能夠將咱們的程序生成dex文件後,將咱們要進行加殼的apk和咱們dex文件合併成一個文件,而後修改dex文件頭中的checksumsignaturefile_size的信息,而且要附加加殼的apk的長度信息在dex文件中,以便咱們進行解殼保證原來apk的正常運行。加完殼後整個文件的結構以下: .net

3)怎麼將原來的apk正常的運行起來? code

按照(2)中的合併方式在當咱們的程序首先運行起來後,逆向讀取dex文件獲取原來的apk文件經過DexClassLoader動態加載。

具體實現以下:

1)修改原來apkAndroidMainfest.xml文件,假如原來apkAndroidMainfest.xml文件內容以下:

1.  <application  

2.      android:icon="@drawable/ic_launcher"  

3.      android:label="@string/app_name"  

4.      android:theme="@style/AppTheme" android:name="com.android.MyApplication" >  

5.  </application>

修改後的內容以下:

1.  <application  

2.      android:icon="@drawable/ic_launcher"  

3.      android:label="@string/app_name"  

4.      android:theme="@style/AppTheme" android:name="com.android.shellApplication" >  

5.  <meta-data android:name="APPLICATION_CLASS_NAME" android:value="com.android.MyApplication"/>

6.  </application> 

com.android.shellApplication這個就是咱們的程序的的application的名稱,而

7.  <meta-data android:name="APPLICATION_CLASS_NAME" android:value="com.android.MyApplication"/>

是原來的apkapplication名稱。

2)合併文件代碼實現以下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

public class ShellTool {

  /**

   * @param args

   */

  public static void main(String[] args) {

         // TODO Auto-generated method stub

         try {

                File payloadSrcFile = new File("payload.apk");//咱們要加殼的apk文件

                File unShellDexFile = new File("classes.dex");//咱們的程序生成的dex文件

                byte[] payloadArray = encrpt(readFileBytes(payloadSrcFile));

                byte[] unShellDexArray = readFileBytes(unShellDexFile);

                int payloadLen = payloadArray.length;

                int unShellDexLen = unShellDexArray.length;

                int totalLen = payloadLen + unShellDexLen +4;

                byte[] newdex = new byte[totalLen];

                //添加咱們程序的dex

                System.arraycopy(unShellDexArray, 0, newdex, 0, unShellDexLen);

                //添加要加殼的apk文件

                System.arraycopy(payloadArray, 0, newdex, unShellDexLen,

                              payloadLen);

                //添加apk文件長度

                System.arraycopy(intToByte(payloadLen), 0, newdex, totalLen-4, 4);

                        //修改DEX file size文件頭

                fixFileSizeHeader(newdex);

                //修改DEX SHA1 文件頭

                fixSHA1Header(newdex);

                //修改DEX CheckSum文件頭

                fixCheckSumHeader(newdex);

  

  

                String str = "outdir/classes.dex";

                File file = new File(str);

                if (!file.exists()) {

                       file.createNewFile();

                }

                 

                FileOutputStream localFileOutputStream = new FileOutputStream(str);

                localFileOutputStream.write(newdex);

                localFileOutputStream.flush();

                localFileOutputStream.close();

  

  

         } catch (Exception e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

         }

  }

   

  //直接返回數據,讀者能夠添加本身加密方法

  private static byte[] encrpt(byte[] srcdata){

         return srcdata;

  }

  

  

  private static void fixCheckSumHeader(byte[] dexBytes) {

         Adler32 adler = new Adler32();

         adler.update(dexBytes, 12, dexBytes.length - 12);

         long value = adler.getValue();

         int va = (int) value;

         byte[] newcs = intToByte(va);

         byte[] recs = new byte[4];

         for (int i = 0; i < 4; i++) {

                recs[i] = newcs[newcs.length - 1 - i];

                System.out.println(Integer.toHexString(newcs[i]));

         }

         System.arraycopy(recs, 0, dexBytes, 8, 4);

         System.out.println(Long.toHexString(value));

         System.out.println();

  }

  

  

  public static byte[] intToByte(int number) {

         byte[] b = new byte[4];

         for (int i = 3; i >= 0; i--) {

                b[i] = (byte) (number % 256);

                number >>= 8;

         }

         return b;

  }

  

  

  private static void fixSHA1Header(byte[] dexBytes)

                throws NoSuchAlgorithmException {

         MessageDigest md = MessageDigest.getInstance("SHA-1");

         md.update(dexBytes, 32, dexBytes.length - 32);

         byte[] newdt = md.digest();

         System.arraycopy(newdt, 0, dexBytes, 12, 20);

         String hexstr = "";

         for (int i = 0; i < newdt.length; i++) {

                hexstr += Integer.toString((newdt[i] & 0xff) + 0x100, 16)

                              .substring(1);

         }

         System.out.println(hexstr);

  }

  

  

  private static void fixFileSizeHeader(byte[] dexBytes) {

  

  

         byte[] newfs = intToByte(dexBytes.length);

         System.out.println(Integer.toHexString(dexBytes.length));

         byte[] refs = new byte[4];

         for (int i = 0; i < 4; i++) {

                refs[i] = newfs[newfs.length - 1 - i];

                System.out.println(Integer.toHexString(newfs[i]));

         }

         System.arraycopy(refs, 0, dexBytes, 32, 4);

  }

  

  

  private static byte[] readFileBytes(File file) throws IOException {

         byte[] arrayOfByte = new byte[1024];

         ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();

         FileInputStream fis = new FileInputStream(file);

         while (true) {

                int i = fis.read(arrayOfByte);

                if (i != -1) {

                       localByteArrayOutputStream.write(arrayOfByte, 0, i);

                } else {

                       return localByteArrayOutputStream.toByteArray();

                }

         }

  }

  

  

}

3)在咱們的程序中加載運行原來的apk文件,代碼以下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

public class shellApplication extends Application {

  

  

  private static final String appkey = "APPLICATION_CLASS_NAME";

  private String apkFileName;

  private String odexPath;

  private String libPath;

  

  

  protected void attachBaseContext(Context base) {

         super.attachBaseContext(base);

         try {

                File odex = this.getDir("payload_odex", MODE_PRIVATE);

                File libs = this.getDir("payload_lib", MODE_PRIVATE);

                odexPath = odex.getAbsolutePath();

                libPath = libs.getAbsolutePath();

                apkFileName = odex.getAbsolutePath() + "/payload.apk";

                File dexFile = new File(apkFileName);

                if (!dexFile.exists())

                       dexFile.createNewFile();

                // 讀取程序classes.dex文件

                byte[] dexdata = this.readDexFileFromApk();

                // 分離出解殼後的apk文件已用於動態加載

                this.splitPayLoadFromDex(dexdata);

                // 配置動態加載環境

                Object currentActivityThread = RefInvoke.invokeStaticMethod(

                              "android.app.ActivityThread", "currentActivityThread",

                              new Class[] {}, new Object[] {});

                String packageName = this.getPackageName();

                HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(

                              "android.app.ActivityThread", currentActivityThread,

                              "mPackages");

                WeakReference wr = (WeakReference) mPackages.get(packageName);

                DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,

                              libPath, (ClassLoader) RefInvoke.getFieldOjbect(

                                            "android.app.LoadedApk", wr.get(), "mClassLoader"));

                RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",

                              wr.get(), dLoader);

  

  

         } catch (Exception e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

         }

  }

  

  

  public void onCreate() {

         {

  

  

                // 若是源應用配置有Appliction對象,則替換爲源應用Applicaiton,以便不影響源程序邏輯。

                String appClassName = null;

                try {

                       ApplicationInfo ai = this.getPackageManager()

                                     .getApplicationInfo(this.getPackageName(),

                                                   PackageManager.GET_META_DATA);

                       Bundle bundle = ai.metaData;

                       if (bundle != null

                                     && bundle.containsKey("APPLICATION_CLASS_NAME")) {

                              appClassName = bundle.getString("APPLICATION_CLASS_NAME");

                       } else {

                              return;

                       }

                } catch (NameNotFoundException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

                }

  

  

                Object currentActivityThread = RefInvoke.invokeStaticMethod(

                              "android.app.ActivityThread", "currentActivityThread",

                              new Class[] {}, new Object[] {});

                Object mBoundApplication = RefInvoke.getFieldOjbect(

                              "android.app.ActivityThread", currentActivityThread,

                              "mBoundApplication");

                Object loadedApkInfo = RefInvoke.getFieldOjbect(

                              "android.app.ActivityThread$AppBindData",

                              mBoundApplication, "info");

                RefInvoke.setFieldOjbect("android.app.LoadedApk", "mApplication",

                              loadedApkInfo, null);

                Object oldApplication = RefInvoke.getFieldOjbect(

                              "android.app.ActivityThread", currentActivityThread,

                              "mInitialApplication");

                ArrayList<Application> mAllApplications = (ArrayList<Application>) RefInvoke

                              .getFieldOjbect("android.app.ActivityThread",

                                            currentActivityThread, "mAllApplications");

                mAllApplications.remove(oldApplication);

                ApplicationInfo appinfo_In_LoadedApk = (ApplicationInfo) RefInvoke

                              .getFieldOjbect("android.app.LoadedApk", loadedApkInfo,

                                            "mApplicationInfo");

                ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo) RefInvoke

                              .getFieldOjbect("android.app.ActivityThread$AppBindData",

                                            mBoundApplication, "appInfo");

                appinfo_In_LoadedApk.className = appClassName;

                appinfo_In_AppBindData.className = appClassName;

                Application app = (Application) RefInvoke.invokeMethod(

                              "android.app.LoadedApk", "makeApplication", loadedApkInfo,

                              new Class[] { boolean.class, Instrumentation.class },

                              new Object[] { false, null });

                RefInvoke.setFieldOjbect("android.app.ActivityThread",

                              "mInitialApplication", currentActivityThread, app);

  

  

                HashMap mProviderMap = (HashMap) RefInvoke.getFieldOjbect(

                              "android.app.ActivityThread", currentActivityThread,

                              "mProviderMap");

                Iterator it = mProviderMap.values().iterator();

                while (it.hasNext()) {

                       Object providerClientRecord = it.next();

                       Object localProvider = RefInvoke.getFieldOjbect(

                                     "android.app.ActivityThread$ProviderClientRecord",

                                     providerClientRecord, "mLocalProvider");

                       RefInvoke.setFieldOjbect("android.content.ContentProvider",

                                     "mContext", localProvider, app);

                }

                app.onCreate();

         }

  }

  

  

  private void splitPayLoadFromDex(byte[] data) throws IOException {

         byte[] apkdata = decrypt(data);

         int ablen = apkdata.length;

         byte[] dexlen = new byte[4];

         System.arraycopy(apkdata, ablen - 4, dexlen, 0, 4);

         ByteArrayInputStream bais = new ByteArrayInputStream(dexlen);

         DataInputStream in = new DataInputStream(bais);

         int readInt = in.readInt();

         System.out.println(Integer.toHexString(readInt));

         byte[] newdex = new byte[readInt];

         System.arraycopy(apkdata, ablen - 4 - readInt, newdex, 0, readInt);

         File file = new File(apkFileName);

         try {

                FileOutputStream localFileOutputStream = new FileOutputStream(file);

                localFileOutputStream.write(newdex);

                localFileOutputStream.close();

  

  

         } catch (IOException localIOException) {

                throw new RuntimeException(localIOException);

         }

  

  

         ZipInputStream localZipInputStream = new ZipInputStream(

                       new BufferedInputStream(new FileInputStream(file)));

         while (true) {

                ZipEntry localZipEntry = localZipInputStream.getNextEntry();

                if (localZipEntry == null) {

                       localZipInputStream.close();

                       break;

                }

                String name = localZipEntry.getName();

                if (name.startsWith("lib/") && name.endsWith(".so")) {

                       File storeFile = new File(libPath + "/"

                                     + name.substring(name.lastIndexOf('/')));

                       storeFile.createNewFile();

                       FileOutputStream fos = new FileOutputStream(storeFile);

                       byte[] arrayOfByte = new byte[1024];

                       while (true) {

                              int i = localZipInputStream.read(arrayOfByte);

                              if (i == -1)

                                     break;

                              fos.write(arrayOfByte, 0, i);

                       }

                       fos.flush();

                       fos.close();

                }

                localZipInputStream.closeEntry();

         }

         localZipInputStream.close();

  

  

  }

  

  

  private byte[] readDexFileFromApk() throws IOException {

         ByteArrayOutputStream dexByteArrayOutputStream = new ByteArrayOutputStream();

         ZipInputStream localZipInputStream = new ZipInputStream(

                       new BufferedInputStream(new FileInputStream(

                                     this.getApplicationInfo().sourceDir)));

         while (true) {

                ZipEntry localZipEntry = localZipInputStream.getNextEntry();

                if (localZipEntry == null) {

                       localZipInputStream.close();

                       break;

                }

                if (localZipEntry.getName().equals("classes.dex")) {

                       byte[] arrayOfByte = new byte[1024];

                       while (true) {

                              int i = localZipInputStream.read(arrayOfByte);

                              if (i == -1)

                                     break;

                              dexByteArrayOutputStream.write(arrayOfByte, 0, i);

                       }

                }

                localZipInputStream.closeEntry();

         }

         localZipInputStream.close();

         return dexByteArrayOutputStream.toByteArray();

  }

  

  

  // //直接返回數據,讀者能夠添加本身解密方法

  private byte[] decrypt(byte[] data) {

         return data;

  }

相關文章
相關標籤/搜索