你们都知道,目前大多数的Android 是用Java语言写的,即便如今Google很是力荐kotlin,可是还有目前不少的项目仍是使用Java编写,毕竟一个语言的替换是须要时间。所以,Java代码容易被反编译也是总所周知的,所以本身的防止被反编译仍是须要重视的。java
主要从四个方面来介绍本文:android
1.Proguard混淆算法
2.对抗反编译工具sql
3.对抗安卓模拟器bash
4.对抗apk重打包app
Proguard 基础ide
Proguard 是一个混淆代码的开源项目,Proguard主要的做用是混淆,固然他还有着对字节码进行缩减体积、优化等功能,我主要关注的是混淆。工具
概念大数据
下面两张图片分别是混淆了和没有混淆的图片(网上找的图):优化
这样能够看出来,假如混淆和没有假如混淆的区别之大。使用混淆以后的类名就彻底变了,天然假如混淆后,针对反编译仍是有效果。
基本语法:
-include {filename} 从给定的文件中读取配置参数
-basedirectory {directoryname} 指定基础目录为之后相对的档案名称
-injars {class_path} 指定要处理的应用程序jar,war,ear和目录
-outjars {class_path} 指定处理完后要输出的jar,war,ear和目录的名称
-libraryjars {classpath} 指定要处理的应用程序jar,war,ear和目录所须要的程序库文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。
保留选项
-keep {Modifier} {class_specification} 保护指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} 保护指定类的成员,若是此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是全部指定的类和类成员是要存在。
-keepnames {class_specification} 保护指定的类和类的成员的名称(若是他们不会压缩步骤中删除)
-keepclassmembernames {class_specification} 保护指定的类的成员的名称(若是他们不会压缩步骤中删除)
-keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,若是全部指定的类成员出席(在压缩步骤以后)
-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件
压缩
-dontshrink 不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}
优化
-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何反作用
-allowaccessmodification 优化时容许访问并修改有修饰符的类和类的成员
混淆
-dontobfuscate 不混淆输入的类文件
-printmapping {filename}
-applymapping {filename} 重用映射增长混淆
-obfuscationdictionary {filename} 使用给定文件中的关键字做为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 肯定统一的混淆类的成员名称来增长混淆
-flattenpackagehierarchy {package_name} 从新包装全部重命名的包并放在给定的单一包中
-repackageclass {package_name} 从新包装全部重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,...} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and
InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量
复制代码
实际代码:
-ignorewarnings # 忽略警告,避免打包时某些警告出现
-optimizationpasses 5 # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar
-dontpreverify # 混淆时是否作预校验
-verbose # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
-libraryjars libs/treecore.jar
-dontwarn android.support.v4.** #缺省proguard 会检查每个引用是否正确,可是第三方库里面每每有些不会用到的类,没有正确引用。若是不配置的话,系统就会报错。
-dontwarn android.os.**
-keep class android.support.v4.** { *; } # 保持哪些类不被混淆
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
-keep class android.os.**{*;}
-keep interface android.support.v4.app.** { *; }
-keep public class * extends android.support.v4.**
-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.support.v4.widget
-keep public class * extends com.sqlcrypt.database
-keep public class * extends com.sqlcrypt.database.sqlite
-keep public class * extends com.treecore.**
-keep public class * extends de.greenrobot.dao.**
-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
native <methods>;
}
-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);
}
-keepclassmembers enum * { # 保持枚举 enum 类不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
public static final android.os.Parcelable$Creator *;
}
-keep class MyClass; # 保持本身定义的类不被混淆
复制代码
**注意: ** 在Android中有一部分是不可以被混淆的,混淆了以后就会出现异常:
防止反编译方法
1 . Proguard混淆不只仅能够混淆代码,还能反编译工具失效或者奔溃
2 . 使用如今国内的APK加固方法,就我所知目前你想要在360市场和腾讯的市场上发布应用,都要必需要使用他们对应的市场的加固方式:360加固和乐固加固
咱们经常使用的反编译工具备哪些呢?
咱们经过上面的两种方法可让这些反编译工具反编译出来不易阅读甚至让反编译工具失效或者。
因为前面已经提到过混淆的方法就不在赘述,使用国内的APK加固方法就更加的简单了,到指定的官网下载工具加固便可,文档描述很详细。
防止模拟器逆向分析
缘由:通常被处于逆向分析状态是在Android模拟器中运行的,因此咱们只须要在代码中判断咱们当前的APK是否运行在模拟器中便可。
检测是不是模拟器 通常有一下几种方式:
下面我用代码来演示一下:
检查IDS
/**
* 检查IDS
*
* @param context
* @return
*/
public static boolean chechDeviceIDS(Context context) {
@SuppressLint("ServiceCast")
TelephonyManager telecomManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
@SuppressLint("MissingPermission")
String deviceId = telecomManager.getDeviceId();
if (deviceId.equalsIgnoreCase(DEVICE_ID)) {
Log.e(TAG, "chechDeviceIDS==" + DEVICE_ID);
return true;
}
return false;
}
复制代码
检查模拟器特有文件
/**
* 检查模拟器特有的文件
*
* @param context
* @return
*/
public static boolean chechDeviceFile(Context context) {
for (int i = 0; i < DEVICE_FILE.length; i++) {
String file_name = DEVICE_FILE[i];
File qemu_file = new File(file_name);
if (qemu_file.exists()) {
Log.e(TAG, "chechDeviceFile==" + true);
return true;
}
}
return false;
}
复制代码
检查模拟器特有号码
/**
* 检查特有电话号码
*
* @param context
* @return
*/
public static boolean chechDevicePhone(Context context) {
@SuppressLint("ServiceCast")
TelephonyManager telecomManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
@SuppressLint("MissingPermission")
String phoneNumber = telecomManager.getLine1Number();
for (String phone : DEVICE_PHONE) {
if (phone.equalsIgnoreCase(phoneNumber)) {
Log.e(TAG, "chechDevicePhone==" + phoneNumber);
return true;
}
}
return false;
}
复制代码
检查模拟器是否含有这些设备
/**
* 检查特是否含有设备
*
* @param context
* @return
*/
public static boolean chechDeviceBuild(Context context) {
String board = Build.BOARD;
String bootloader = Build.BOOTLOADER;
String brand = Build.BRAND;
String device = Build.DEVICE;
String hardware = Build.HARDWARE;
String model = Build.MODEL;
String product = Build.PRODUCT;
if (board.equalsIgnoreCase("unknown") || bootloader.equalsIgnoreCase("unknown")
|| brand.equalsIgnoreCase("generic") || model.equalsIgnoreCase("sdk")
|| product.equalsIgnoreCase("goldfish")) {
Log.e(TAG, "chechDeviceBuild==" + "find emulatorBuild");
return true;
}
return false;
}
复制代码
运行结果:
咱们能够看到打印结果是都显示是模拟器,提醒一点获取这些信息的时候别忘记添加权限:
经过上面咱们能够判断是不是模拟器,那么这时咱们就能够经过判断来杀死APP或者杀死APP所在的进程。
防止二次打包
若是程序处于破解状态,那么咱们的APK确定是要运行在真机或者模拟器上,必需要从新签名,那么此时的签名和原来的签名必然不一致,咱们就能够在程序的入口判断咱们的签名,来以此判断二次打包。
代码以下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "getSignature=="+getSignature("demo.lt.com.repacking"));
}
private int getSignature(String packageName) {
PackageManager packageManager = this.getPackageManager();
PackageInfo info = null;
int sig = 0;
try {
info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
Signature[] signatures = info.signatures;
sig = signatures[0].hashCode();
} catch (Exception e) {
sig = 0;
e.printStackTrace();
}
return sig;
}
}
复制代码
获取到签名hashCode是惟一值:
所以咱们只须要再增长代码便可判断二次打包:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "getSignature==" + getSignature("demo.lt.com.repacking"));
if (getSignature("demo.lt.com.repacking") != -567503403) {
Log.e(TAG, "被从新打包了");
}
}
private int getSignature(String packageName) {
PackageManager packageManager = this.getPackageManager();
PackageInfo info = null;
int sig = 0;
try {
info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
Signature[] signatures = info.signatures;
sig = signatures[0].hashCode();
} catch (Exception e) {
sig = 0;
e.printStackTrace();
}
return sig;
}
}
复制代码
这里只是打印了个Log,实际代码中能够结束进程或者杀死APP。
以上就是今天的Android 防御的知识点,并非要求你有多么精通Android防御,而是咱们做为一个Android开发者必需要知道这些知识点,我相信对你确定是有用的。
原创不易,若是以为写得好,扫码关注一下点个赞,是我最大的动力。
关注我,必定会有意想不到的东西等你:Android、Java、大数据等视频资源、书籍等着你来拿。 天天专一分享Android、JAVA干货