AndroidStudio-3.2.1(二十八)反编译与混淆

本文介绍了使用Android Studio将项目打包成APK后的相关操作。包括使用反编译工具apktool查看源码,手动签名APK的方法及遇到的问题,代码混淆降低反编译风险的操作,还总结了APK文件拷贝、对齐和签名文件等方面的问题及解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用androidstuio将android项目打包成apk后,可以使用解压软件直接打开。但是这里的文件除了assets文件夹和图片资源外,都是编译后的文件了,无法直接查看布局(xml)和代码(java)文件,打开是字节流。因此需要使用反编译工具apktool。
在这里插入图片描述

apktool的使用

1、到官网上下载两个文件apktool.bat和apktool.jar(下载后去掉版本号),然后拷贝到C:\Windows文件夹下。
在这里插入图片描述
2、apktool主要提供两个命令d(反编译)和b(构建)。打开cmd窗口(windows平台),cd到apk所在的文件夹下,然后执行如下命令:

apktool d testapp.apk
apktool b app-release -o new.apk

3、打开反编译后的文件夹,可以看到apk的源码文件,需要说明的是smali文件,这是源码中java文件反编译产生的一种语言,可以称之为Android字节码的反汇编语言。有自己的语法,基本上可阅读。(下图是在sublime中打开的,如果想彩色显示,需要给sublime安装插件sublime-smali
在这里插入图片描述
ps:还可以使用smali2java工具,它基于apktool v1.5.0生成的smali文件,依赖smali文件中的代码行数(.line关键字)和变量别名(.local关键字)等信息,最大程度还原java代码。还原出的java代码将具有原始的变量命名,代码的顺序也与原始的java代码保持一致。但是,本工具也具有**局限性**,仅适用于带有行数和变量别名信息的smali文件(java编译器的编译选项可以在生成的字节码中剔除这些信息)。

在这里插入图片描述
4、反编译后,可以对源码做一些不可描述的事情,然后再次使用apktool工具进行重新构建。

手动签名

1、apktool重新构建后的apk没有签名,因此是无法安装的。可以尝试把apk拖到genymotion里,安装看看。
2、签名用到工具APK-Signer(下载),提供了图形化界面。
在这里插入图片描述
3、依次选择签名文件、apk文件,点击sign即可。
注意:已经签名过的apk是无法二次签名的。如何辨别已经签过名呢,用解压打开apk,看到META-INF文件夹里除了MANIFEST.MF有其它文件,就说明已经签名了。
所以,去掉签名的办法就是,删掉META-INF文件夹里除了MANIFEST.MF的其它文件。
4、点击sign后,貌似报了个错:jar:-tsa -tsacert
在这里插入图片描述
我又使用android自带的jarsigner命令签名了一次,貌似也报了同样的错:

jarsigner -keystore F:\ANDROIDPRACTICE\signer.keystore -signedjar apk-signed.apk snew.apk sa
在这里插入图片描述

正当不知所以然时,解压打开apk发现已经存在签名文件了,拖到genymotion上果然能够安装了 -_-

代码混淆

为了降低(不是杜绝)反编译带来的风险,需要在打包apk时,进行代码混淆。
1、as里的代码混淆很方便,在build.gradle中开启即可:minifyEnabled 设为true

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

2、混淆的配置文件是proguard-rules.pro。可以什么都不改,即按as的默认配置来混淆。
3、对打包后的apk进行反编译。可以看到有些文件或类名称被简化为abc等字母,但是大部分还是原样。因为为了保证apk能正常运行,有些代码是不能混淆的,比如R文件中的所有静态字段id。
在这里插入图片描述
4、混淆后可查看日志(路径:app\build\outputs\mapping\release)

# 未混淆的类和成员    /seeds.txt
# 列出从 apk 中删除的代码   /unused.txt
# 混淆前后的映射   /mapping.txt

5、可见即使混淆了代码,也并不能完全阻止apk被反编译以及代码的泄露。
最终极的办法是将核心代码用C/C++实现,然后使用android ndk编程的方式进行集成。

问题总结

1、apk文件拖拽到genymotion时,一直处于File transfer in process,事实上我这写东西时,它还在一直滚动进度条,不管他的话能自己玩上一天。
在这里插入图片描述
所以,我采用了别的方法拷贝apk,就是将apk文件放到了本机iis服务器下,给iis的mime类型添加:.apk application/vnd.android
然后用虚拟机的浏览器进行下载…
在这里插入图片描述
2、关于apk对齐(zipalign):可提高与Android系统交互的效率。
当apk签名报错后,查看资料知道apksigner.jar进行签名前必须对app进行对齐操作,才能进行签名操作。使用命令或界面工具都可以。

zipalign -v 4 src.apk dst.apk

尽管在签名前先对app进行了对齐操作,但是并不能保证每次都能成功;因为对齐操作会出现对齐失败的情况。对于这种失败的情况,通过多次实验得出,只需要针对 对齐失败的apk 进行第二次对齐,就基本能对齐成功,最后再对app进行签名操作。

3、关于几种签名文件
4、最后附一份常用的混淆配置文件:根据自己项目的具体情况修改。

#--------------------------1.实体类---------------------------------
# 如果使用了Gson之类的工具要使被它解析的JavaBean类即实体类不被混淆。(这里填写自己项目中存放bean对象的具体路径)

#--------------------------2.第三方包-------------------------------
#Gson
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.gson.* { *;}
-dontwarn com.google.gson.**

#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }

#-------------------------3.与js互相调用的类------------------------


#-------------------------4.反射相关的类和方法----------------------


#-------------------------5.基本不用动区域--------------------------
#指定代码的压缩级别
-optimizationpasses 5

#包明不混合大小写
-dontusemixedcaseclassnames

#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

#混淆时是否记录日志
-verbose

#优化  不优化输入的类文件
-dontoptimize

#预校验
-dontpreverify

# 保留sdk系统自带的一些内容 【例如:-keepattributes *Annotation* 会保留Activity的被@override注释的onCreate、onDestroy方法等】
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号,保持源文件以及行号
-keepattributes SourceFile,LineNumberTable

#-----------------------------6.默认保留区-----------------------
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclassmembers public class * extends android.view.View {
 public <init>(android.content.Context);
 public <init>(android.content.Context, android.util.AttributeSet);
 public <init>(android.content.Context, android.util.AttributeSet, int);
 public void set*(***);
}

#保持 Serializable 不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {
    public <init>(android.content.Context,android.util.AttributeSet);
}
# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {
    public <init>(android.content.Context,android.util.AttributeSet,int);
}
# 保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}

# 保持枚举 enum 类不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

# 不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。
-keepclassmembers class **.R$* {
    public static <fields>;
}

#如果引用了v4或者v7包
-dontwarn android.support.**

# 保持哪些类不被混淆
#-keep public class * extends android.app.Appliction
#-keep public class * extends android.app.Activity
#-keep public class * extends android.app.Fragment
#-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.preference.Preference

-keep class com.zhy.http.okhttp.**{*;}
-keep class com.wiwide.util.** {*;}

# ============忽略警告,否则打包可能会不成功=============
-ignorewarnings

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值