现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,我来分享下以下几点:
防破解技术主要有四种实现方式:
1.代码混淆(ProGuard)技术
2.签名比对技术
3.NDK .so 动态库技术
4.动态加载技术
5.第三方平台加密以及检测漏洞
这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。
主要优点有:
1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。
2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。
所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。
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格式转化
-- --
-- --. -.
然后再用加密工具将生成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的动态库