Android apk如何加固防止被破解(防止逆向编译)
2017-02-24 09:20
453 查看
现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,我来分享下以下几点:
防破解技术主要有四种实现方式:
1.代码混淆(ProGuard)技术
2.签名比对技术
3.NDK .so 动态库技术
4.动态加载技术
5.第三方平台加密以及检测漏洞
这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。
第一种: 代码混淆技术(ProGuard) 该技术主要是进行代码混淆,降低代码逆向编译后的可读性,但该技术无法防止加壳技术进行加壳(加入吸费、广告、病毒等代码),而且只要是细心的人,依然可以对代码依然可以对代码进行逆向分析,所以该技术并没有从根本解决破解问题,只是增加了破解难度。
第二种: 签名比对技术 该技术主要防止加壳技术进行加壳,但代码逆向分析风险依然存在。而且该技术并不能根本解决被加壳问题,如果破解者将签名比对代码注释掉,再编译回来,该技术就被破解了。
第三种: NDK .so动态库技术,该技术实现是将重要核心代码全部放在C文件中,利用NDK技术,将核心代码编译成.so动态库,再用JNI进行调用。该技术虽然能将核心代码保护起来,但被加壳风险依然存在。
第四种: 动态加载技术,该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。
第五种: 第三方平台使用
主要讲解第四种方法,该技术可以有效的防止逆向分析、被破解、被加壳等问题,动态加载技术分为以下几步:
将核心代码编译成dex文件的Jar包
对jar包进行加密处理
在程序主入口利用NDK进行解密
再利用ClassLoader将jar包进行动态加载
利用反射技术将ClassLoader 设置成系统的ClassLoader。
主要优点有:
1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。
2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。
所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。
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
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
jar用SDK\platform-tools\下的dx命令进行dex格式转化
2
1
2
然后再用加密工具将生成jar文件进行加密处理
最后通过代码动态加载:
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
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
处理完成,如果在Application中做特别处理也是可行的。之前就有人分析了爱加密的加密方式,不过这里不做阐述,有兴趣可以一起讨论。
下篇文章中我们来讲讲如何 逆向apk的动态库
防破解技术主要有四种实现方式:
1.代码混淆(ProGuard)技术
2.签名比对技术
3.NDK .so 动态库技术
4.动态加载技术
5.第三方平台加密以及检测漏洞
这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。
第一种: 代码混淆技术(ProGuard) 该技术主要是进行代码混淆,降低代码逆向编译后的可读性,但该技术无法防止加壳技术进行加壳(加入吸费、广告、病毒等代码),而且只要是细心的人,依然可以对代码依然可以对代码进行逆向分析,所以该技术并没有从根本解决破解问题,只是增加了破解难度。
第二种: 签名比对技术 该技术主要防止加壳技术进行加壳,但代码逆向分析风险依然存在。而且该技术并不能根本解决被加壳问题,如果破解者将签名比对代码注释掉,再编译回来,该技术就被破解了。
第三种: NDK .so动态库技术,该技术实现是将重要核心代码全部放在C文件中,利用NDK技术,将核心代码编译成.so动态库,再用JNI进行调用。该技术虽然能将核心代码保护起来,但被加壳风险依然存在。
第四种: 动态加载技术,该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。
第五种: 第三方平台使用
主要讲解第四种方法,该技术可以有效的防止逆向分析、被破解、被加壳等问题,动态加载技术分为以下几步:
将核心代码编译成dex文件的Jar包
对jar包进行加密处理
在程序主入口利用NDK进行解密
再利用ClassLoader将jar包进行动态加载
利用反射技术将ClassLoader 设置成系统的ClassLoader。
主要优点有:
1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。
2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。
所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。
// 1.Jar包加密加密解密文件// public static boolean enOrDecryptFile(byte[] paramArrayOfByte, String sourceFilePath, String destFilePath,int mode){ File sourceFile = new File(sourceFilePath); File destFile = new File(destFilePath); CipherOutputStream cout = null; FileInputStream in = null; FileOutputStream out = null; if (sourceFile.exists() && sourceFile.isFile()) { if (!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } try { destFile.createNewFile(); in = new FileInputStream(sourceFile); out = new FileOutputStream(destFile); // 获取密钥// init(); SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES"); Cipher cipher; cipher = Cipher.getInstance("AES"); cipher.init(mode, secretKeySpec); cout = new CipherOutputStream(out, cipher); byte[] cache = new byte[CACHE_SIZE]; int nRead = 0; while ((nRead = in.read(cache)) != -1) { cout.write(cache, 0, nRead); cout.flush(); } }catch (IOException e) { e.printStackTrace(); return false; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return false ; } catch (NoSuchPaddingException e) { e.printStackTrace(); return false ; }catch (InvalidKeyException e) { e.printStackTrace(); return false; }finally{ if(cout != null){ try { cout.close(); } catch (IOException e) { e.printStackTrace(); } } if(out != null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(in != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } return false; }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
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
jar用SDK\platform-tools\下的dx命令进行dex格式转化
dx --dex --output=生成的目标文件的地址(绝对路径) 需要转化的jar文件(绝对路径) 例如:dx --dex --output=H:\classdex.jar H:\dujinyang-KARL.jar1
2
1
2
然后再用加密工具将生成jar文件进行加密处理
最后通过代码动态加载:
File file = new File("/data/data/" + base.getPackageName() + "/.cache/"); if (!file.exists()) { file.mkdirs(); } try { Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } Util.copyJarFile(this); Object currentActivityThread = RefInvoke.invokeStaticMethod( "android.app.ActivityThread", "currentActivityThread", new Class[] {}, new Object[] {}); String packageName = getPackageName(); HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect( "android.app.ActivityThread", currentActivityThread, "mPackages"); WeakReference wr = (WeakReference) mPackages.get(packageName); MyClassLoader dLoader = new MyClassLoader("/data/data/" + base.getPackageName() + "/.cache/classdex.jar", "/data/data/" + base.getPackageName() + "/.cache", "/data/data/" + base.getPackageName() + "/.cache/", base.getClassLoader()); try { Class<?> class1 = dLoader.loadClass("com.example.test.TestActivity"); Log.i("b364","----------->class1: "+class1); } catch (ClassNotFoundException e){ Log.i("b364","----------->class not found Exception!"); e.printStackTrace(); } Log.i("b364","------>PackageInfo: "+wr.get()); // 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);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
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
处理完成,如果在Application中做特别处理也是可行的。之前就有人分析了爱加密的加密方式,不过这里不做阐述,有兴趣可以一起讨论。
下篇文章中我们来讲讲如何 逆向apk的动态库
相关文章推荐
- Android apk如何加固防止被破解(防止逆向编译)
- Android apk如何加固防止被破解(防止逆向编译)
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译(转)
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- Android如何防止apk程序被反编译
- android中如何防止apk被反编译
- Android如何防止apk程序被反编译
- [转]Android如何防止apk程序被反编译