注册

完了,安卓项目代码被误删了......

写在前面


这是一个朋友的经历记录了下来。朋友开发完了一个公司的app,过了一段时间,在清理电脑空间的时候把该app的项目目录给删了,突然公司针对该app提出了新的需求,这不完了?幸好有之前打包好的apk,所以可以通过逆向去弥补.....


Apk文件结构


apk的本质是压缩包,apk解压后会生成下列所示文件夹




  • Assets:存放的是不会被编译处理的文件。
  • Lib:存放的是一些so库,native库文件
  • META-INF:存放的是签名信息,用来保证apk的完整性和系统安全。防止被重新修改打包。
  • res:存放的资源文件,图片、字符串、颜色信息等
  • AndroidManifest.xml:是Android程序的配置文件,权限和配置信息
  • Classes.dex:Android平台下的字节码文件。
  • Resources.arcs:编译后的二进制资源文件,用来记录资源文件和资源ID的关系

逆向


这里用了逆向神器——jdax。支持命令行和图形化界面,地址如下:


github.com/skylot/jadx…


下载好之后,直接解压后打开exe,将apk文件拖入进去就可以,图形化界面,更方便搜索查看,可以看到下列文件夹



先看资源文件,asset存放的是静态资源文件,一般不会被压缩,但是会占用更多的安装包空间,res文件是由Android目录下的res进行压缩得到的,所以里面的文件直接解压打开会乱码,在这个工具里打开是正常的。



话不多说直接找回我的代码,找到我写的一个类,拷贝回去,补齐里面缺失的资源文件和一些新增的接口,跟着自己之前开发的流程,一步一步的找回去,发现其中局部变量在编译的时候都被进行了优化,以便缩小体积



找到我写的最核心的代码,发现被混淆了,我在代码里没有进行代码混淆配置,还是被一些工具给我进行了混淆,只能凭借着记忆去还原了。



终于进行了不到一天多的时间,把所有的代码还原了,然后自测通过。


代码混淆


现在其实也可以看到自己的程序是非常危险的,任何人拿到我的apk进行一个逆向就可以看到大概的逻辑。所以要在Android中进行代码混淆的配置。


项目中如果含有多个module时,在主app中设置了混淆其他module都会混淆,在build.gradle中配置下列代码 proguardFiles getDefaultProguardFile


android {
...
buildTypes {
release {
minifyEnabled true // 开启代码混淆
zipAlignEnabled true // 开启Zip压缩优化
shrinkResources true // 移除未被使用的资源
//混淆文件列表,混淆规则配置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
...
}

这里代表的是混淆文件,我们在项目里找到proguard-rules.pro,这里就是混淆规则,规定了哪些代码进行混淆,哪些不进行混淆。混淆规则一般有以下几点:



  • 混淆规则,等级、预校验、混淆算法等
  • 第三方库
  • 自定义类、控件
  • 本地的R类
  • 泛型 注解 枚举类等

示例配置如下:



#压缩等级,一般选择中间级别5
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
#保持下面的类不被混淆(没有用到的可以删除掉,比如没有用到service则可以把service行删除)
-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.preference.Preference
-keep public class * extends android.support.v4.app.FragmentActivity
-keep public class * extends android.support.** { *;}
#如果引用了v4或者v7包
-dontwarn android.support.*
#忽略警告(开始应该注释掉,让他报错误解决,最后再打开,警告要尽量少)
-ignorewarnings
#####################记录生成的日志数据,gradle build时在本项目根目录输出################
#混淆时是否记录日志
-verbose
#apk 包内所有class 的内部结构
-dump class_files.txt
#为混淆的类和成员
-printseeds seeds.txt
#列粗从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
#####################记录生成的日志数据,gradle build时在本项目根目录输出结束################

#本地的R类不要被混淆,不然就找不到相应的资源
-keep class **.R$*{ public static final int *; }

#保持内部类,异常类
-keepattributes Exceptions, InnerClasses
#保持泛型、注解、源代码之类的不被混淆
-keepattributes Signature, Deprecated, SourceFile
-keepattributes LineNumberTable, *Annotation*, EnclosingMethod

#保持自定义控件不被混淆(没有就不需要)
-keepclasseswithmembers class * extends android.app.Activity{
public void *(android.view.View);
}
-keepclasseswithmembers class * extends android.supprot.v4.app.Fragment{
public void *(android.view.View);
}
#保持 Parcelable 不被混淆(没有就不需要)
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆(没有就不需要)
-keepnames class * implements java.io.Serializable

-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

再次打包,然后打开apk后就会发现包名类名变量名都变得很奇怪。




这样代码混淆就完成了。


作者:银空飞羽
来源:juejin.cn/post/7360903734853730356

0 个评论

要回复文章请先登录注册