关注应用安全--反逆向实战

转载:http://www.apkbus.com/forum.php?mod=viewthread&tid=240707

大家好,4月25日刚刚过去的安卓巴士上海座谈会可真是高手云集啊。观看了座谈会之后我对360专家说的“Android没有秘密--应用逆向与保护”这个话题印象比较深刻。本期专题将围绕这个话题进行一些探讨。


盗版猖獗被反编译成为常态?谁偷了我的代码!


对于反编译这个话题,安卓开发的程序员们应该是不会陌生的。可以说基本的反编译是一个Android工程师的基础技能之一。网上的反编译教程非常多,做起来也很容易。


正是因为反编译这么简单,如果不加保护,我们的劳动成果就会被轻易盗取。

市面上比较常用的反编译工具有:dex2jar,jd-gui,apktool,IDA等等。

这里我简单的说一下dex2jar这个常用反编译工具的使用。
在下载到了dex2jarjd-gui这两个工具之后。

1.将要反编译的APK后缀名改为.rar或 .zip,并解压
-------------------------------------------------------------
2.得到其中的classes.dex文件(它就是java文件编译再通过dx工具打包而成的),将获取到的classes.dex放到之前解压出来的工具dex2jar-0.0.9.15 文件夹内
-------------------------------------------------------------
3.在命令行下定位到dex2jar.bat所在目录,输入dex2jar.bat   classes.dex。

效果如下:


在该目录下会生成一个classes_dex2jar.jar的文件,然后打开工具jd-gui文件夹里的jd-gui.exe,之后用该工具打开之前生成的classes_dex2jar.jar文件,便可以看到源码了,效果如下:


被混淆过的效果图(类文件名称以及里面的方法名称都会以a,b,c....之类的样式命名):


没有经过处理或者只是简单的混淆过的APP其代码的反编译的比较容易的。你的代码经过上面那三步已经暴露出来了。

在下面提供的更多的途径来给各位学习反编译。


更多反编译的教程:

-------------------------------------------------------------
[size=21.3333339691162px]
apktool反编译工具使用教程:


-------------------------------------------------------------

反编译与防止反编译:


-------------------------------------------------------------

黑马Android视频教程——119_应用程序的反编译:




怎样防止应用被破解?

在知道了这么容易就可以破解我苦心经营的APP时,我的心是崩溃的。这个时候我要听专家的,我还认真的记录了下来,看看专家怎么说。


从上图我们可以看到,现在的防止反编译的手段已经发展到了资本主义了。

下面一一列举了各种对抗反编译的手段,希望对大家有所帮助。

(一)基础手段--混淆代码


代码混淆技术基本原理是使反编译工具反编译出来的代码人难以阅读,从而达到防止被逆向破解的目的。简单的理解就是把原来的类名、方法名、字段名、参数名、变量名等,用无意义的字符序列来替换。变成类似abc这样的无命名规则的字符,增加阅读难度。

步骤:
-------------------------------------------------------------
1.找到或者创建一个proguard-project.txt文件
-------------------------------------------------------------
2.在proguard-project.txt添加混淆的申明

a) 申明外包jar包(申明的外面jar不会被混淆)
例如:-libraryjars libs/abc.jar

b) 将你不需要混淆的部分申明进来(因为有些类经过混淆会导致程序编译不通过)
如系统组件和API的类:
-keep public class * extends android.app.Fragment  
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**

c) -dontwarn 缺省proguard 会检查每一个引用是否正确,但是第三方库里面往往有些不会用到的类,没有正确引用。如果不配置的话,系统就会报错。
例如:-dontwarn android.support.**

d) -keepclassmembers 指定的类成员被保留。
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}

e) -keepclasseswithmembers 指定的类和类成员被保留,假如指定的类成员存在的话。
例如:
-keepclasseswithmembers class * { 
public <init>(android.content.Context, android.util.AttributeSet);
}


-------------------------------------------------------------

3.以上工作完成,混淆工作就完成了一大半了,最后需要做的就是在project.properties文件中加上你的混淆文件申明了,如下:
   proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt


-------------------------------------------------------------

4.最后一步,打签名包测试

(二)签名自校验

    简单的理解,签名就是标明一个APP是不是官方正版发行的标记。发现一个APP跟你的一样却无法覆盖安装,就是签名不一致的缘故。也可以理解为你的APP已经被破解并重新打包了。

    那么如何获取到APK文件的公钥信息呢?因为Android系统安装程序肯定会获取APK信息进行比对,所以我们可以通过Android源码获得一些思路和帮助。

    源码中有一个隐藏的类用于APK包的解析。这个类叫PackageParser,路径为frameworks\base\core\java\android\content\pm\PackageParser.java。当我们需要获取APK包的相关信息时,可以直接使用这个类,下面代码就是一个例子函数:

代码:
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
private PackageInfo parsePackage(String archiveFilePath, int flags){
         
   PackageParser packageParser = new PackageParser(archiveFilePath);
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
         final File sourceFile = new File(archiveFilePath);
         PackageParser.Package pkg = packageParser.parsePackage(
                 sourceFile, archiveFilePath, metrics, 0 );
         if (pkg == null ) {
             return null ;
         }
         
         packageParser.collectCertificates(pkg, 0 );
         
         return PackageParser.generatePackageInfo(pkg, null , flags, 0 , 0 );
}

    其中参数archiveFilePath指定APK文件路径;flags需设置PackageManager.GET_SIGNATURES位,以保证返回证书签名信息。

    具体如何通过PackageParser获取签名信息在此处不做详述,具体代码请参考PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于如何在Android应用开发中使用隐藏的类及方法,可以参看我的这篇文章: 《Android应用开发中如何使用隐藏API》 。

    紧接着,我们就可以通过packageInfo.signatures来访问到APK的签名信息。还需要说明的是 Android中Signature和Java中Certificate的对应关系。它们的关系如下面代码所示:

代码:
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
pkg.mSignatures = new Signature[certs.length];
for ( int i= 0 ; i<N; i++) {
     pkg.mSignatures = new Signature(
     certs.getEncoded());
}

    也就是说signature = new Signature(certificate.getEncoded()); certificate证书中包含了公钥和证书的其他基本信息。公钥不同,证书肯定互不相同。我们可以通过certificate的getPublicKey方法获取公钥信息。所以比对签名证书本质上就是比对公钥信息。

    OK,获取到APK签名证书之后,就剩下比对了。这个简单,功能函数如下所示:

代码:
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
private boolean IsSignaturesSame(Signature[] s1, Signature[] s2) {
         if (s1 == null ) {
             return false ;
         }
         if (s2 == null ) {
             return false ;
         }
         HashSet<Signature> set1 = new HashSet<Signature>();
         for (Signature sig : s1) {
             set1.add(sig);
         }
         HashSet<Signature> set2 = new HashSet<Signature>();
         for (Signature sig : s2) {
             set2.add(sig);
         }
         // Make sure s2 contains all signatures in s1.
         if (set1.equals(set2)) {
             return true ;
         }
         return false ;
}


在程序运行时,自我进行签名比对。比对样本可以存放在APK包内,也可存放于云端。缺点是程序被破解时,自检测功能同样可能遭到破坏,使其失效。


(三)
源程序使用C层编写


将核心代码使用C/C++编写然后编译成为.so文件,这种方式的代码保护性是比Java代码提升了不少。使用工具反编译之后的是汇编语言,不过对于熟悉汇编语言的高手来说破解也是很可能的。

对于如何编译成so文件大家可以参考下面的文档:




在了解了比较常用的技术之后我们来看看专家推荐的比较高新的对抗技术有哪些



(四)DEX文件隐藏(加壳技术


壳技术原理

所谓apk的加壳技术和pc exe的加壳原理一样,就是在程序的外面再包裹上另外一段代码,保护里面的代码不被非法修改或反编译,在程序运行的时候优先取得程序的控制权做一些我们自己想做的工作。

加壳作用:

       加壳的程序可以有效阻止对程序的反汇编分析,以达到它不可告人的目的。这种技术也常用来保护软件版权,防止被软件破解。

大家可以参考下面的文章:





(五)利用反编译工具漏洞

一、对抗JD-GUI原理

通常在对apk进行反编译的时候用到的最多的两个工具就是apk-tool和dex2jar。利用这两个工具将apk首先反编译成classes.dex然后再将classes.dex反编译成jar文件或者将apk直接反编译成jar文件;得到jar文件以后就可以利用JD-GUI将得到的jar文件打开就可以直接查看apk的java源码了。我们花了那么大心思写的程序就这么容易被别人拿到源码是不是很不甘心,现在我就告诉你对抗JD-GUI查看源码的方法。我们在用JD-GUI查看源码时有时有些函数的根本看不到直接提示error错误,我们就利用这点来保护我们的apk。原来JD-GUI在将经过混淆处理的jar里面的class字节码文件转成java文件时,遇到函数中根本走不到的分支的特殊实现时就会提示函数error。这时我们只要查看这些提示error的文件或者函数对应的源码是有什么语句引起的,将这些语句加到我们的源码中就可以防止利用JD-GUI去查看我们的apk源码了。


二、原理实现

(1)假如我们的apk onCreate的函数实现如下:

[Java] 纯文本查看 复制代码
?
1
2
3
4
<font style= "color:rgb(51, 51, 51)" ><font face= "微软雅黑" ><font style= "font-size:16px" >[url=home.php?mod=space&uid= 389554 ] @Override [/url]   
protected   void   onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main); }</font></font></font>

(2)将我们的apk经过混淆处理后经过签名导出我们的apk,我们用dex2jar工具将我们的apk转换成jar文件


(3)用JD-GUI打开我们的jar文件就可以看到我们的apk onCreate函数的源码了。如下:



(4)这时我们在apk onCreate函数里面加上不可能的特殊分支语句,代码如下:

[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<font style= "color:rgb(51, 51, 51)" ><font face= "微软雅黑" ><font style= "font-size:16px" > @Override
protected   void   onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switch ( )
{
case   :
JSONObject jsoObj;
String date= null ;
String second= null ;
try {
jsoObj= new   JSONObject();
date=jsoObj.getString( "date" );
second=jsoObj.getString( "second" );
}
catch (JSONException e)
{ e.printStackTrace(); } test.settime(date,second);
break ;
} }</font></font></font>


[Java] 纯文本查看 复制代码
?
1
2
3
4
<font style= "color:rgb(51, 51, 51)" ><font face= "微软雅黑" ><font style= "font-size:16px" > class   test
{
public   static   void   settime(String a,String b){}
}</font></font></font>

(5)我们用(2)中同样的方法将apk转成jar文件,然后用JD-GUI打开会看到提示error错误。如下:


根据上面的讲述相信大家对对抗JD-GUI的方法有了一定的了解,我只是举了其中的一个方法,之所以说是特殊的分支语句是因为不是所有的分支语句都可以让JD-GUI提示error。


(六)运行时修改Dalvik指令 
     
我们知道apk生成后所有的java生成的class文件都被dx命令整合成了一个classes.dex文件,当apk运行时dalvik虚拟机加载classes.dex文件并且用dexopt命令进行进一步的优化成odex文件。我们的方法就是在这个过程中修改dalvik指令来达到我们的目的。



大家可以参考下面的文章:




快捷的APK反逆向解决方案


在了解上面这么多的反逆向方法之后,我们要保护自己的APP要付出的时间和技术成本看起来还是很高的,这时候如果有一些产品或者工具可以帮我们完成这些工作。那么这方面的成本就低很多了,而目前市面上的确有不少这样的服务。


360加固宝


阿里聚安全


爱加密


梆梆加固


百度云加固


腾讯云加固



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值