Android 防止逆向

软件逆向分析的出现必然会出现防止逆向分析的操作,这里介绍五种防御方式:

①代码混淆技术

②针对不同的逆向工具的保护技术(如IDE、JD_GUI等)

③增加逆向难度(java代码Native化)

④动态加载技术

⑤代码验证技术

代码混淆

代码混淆也称花指令,是将计算机程序的代码转化为一种功能上的等价,但是难于阅读和理解的形式的行为,代码混淆可以用于程序编译而成的中间代码,执行代码混淆的程序被称作代码混淆器,

将代码中的各种元素,例如变量、函数、类的名字改成毫无意义的名字,比如改成单个字母,或是简短的无意义的字母组合,甚至改成”_“这样的符号,使得阅读的人无法根据名字猜测其用途,重写代码中的部分逻辑,将其变成功能上的等价,但是更难以理解的形式,比如讲for循环改成while循环,将循环改成递归,精简中间变量,打乱代码格式等。

ProGuard简介

是一个压缩、优化和混淆java字节码的免费工具,它可以删除无用的类、字段、方法和属性,可以删除没用的注释,最大限度的优化字节码文件,它还可以使得简短的无意义的名称来重命名已经存在的类、字段、方法和属性:

①删除不可见的字符、注释等无用代码,创建紧凑的代码文档,为了更快的网络传输,快速装载和更小的内存占用。

②重命名,使得创建的程序和程序库很难使得反向工程

③能删除来自原文件的没有调用的代码

④充分利用java6的快速加载的优点来提前检测和返回java6中存在的类文件

参数

-include{filename}   从给定的文件中读取配置参数

-basedirectory{basedirectory}   指定基础目录为以后相对应的档案名称

-injars{class_path}    指定要处理的应用程序jar、war、ear和目录

-outjars{class_path} 指定处理完要输出的jar、war、ear和目录名称

-libraryjars{class_path}  指定要处理的应用程序jar、war、ear和目录所需要的程序库文件

-dontskipnibpubliclibraryclasses 指定不去忽略非公共的类库

保留选项

-keep {Modifier} {类成员}    保护指定的类文件和类成员

-keepclassmembers {类文件}{类成员}    保护指定类的成员,如果此类收到保护,它们会保护的更好

-keepclasswithmembers{}   保护指定的类和类成员,但条件是所有指定的类和类成员要存在

-keepnames {类名称}  保护指定的类和类成员的名称

-keepclassmembername{类名称}   保护指定的类的成员名称

-keepclasswithmembernames{类名称}   保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)

-printseeds{文件名称}   列出类和类的成员-keep选项的清单,标准输出给定的文件

压缩

-dontshrink  不压缩输入的类文件

优化

-dontoptimize   不优化输入的类文件

-assumenosideeffects{类文件} 优化时假设指定的方法,没有任何副作用

-allowaccessmodification   优化时允许访问并修改有修饰符的类和类的成员

混淆

-dontobfuscate  不混淆输入的类文件

-printmapping{文件名}

-applymapping{文件名}    重用映射增加混淆

-obfuscationdictionary{文件名}   使用给定文件的关键字作为要混淆方法的名称

-overloadaggressively 混淆时应用侵入式重载

-useuniqueclassmembernames  确定统一的混淆类的成员名称来增加混淆

-flattenpackagehierarchy{文件名} 重新包装所有重命名的包并放在给定的单一包中

-dontusemixedcaseclassnames   混淆时不会产生形形色色的类名

-renamesourcefileattribute{string} 设置原文件中给定的字符串常量

混淆带来的问题

虽然混淆对我们的代码反逆向起到比较良好的作用,但是过度的混淆也会带来很多调试的困难,如

①混淆错误,用到第三方jar的时候,必须告诉ProGuard不要检查,否则ProGuard会报错

②运行错误,当code不能混淆的时候,我们必须要正确配置,否则程序会运行出错,这种问题很多

③调试定位比较痛苦,打印的错误信息中错误堆栈是混淆后的代码,开发者自己也看不懂,这个时候需要自己存一份map,来记录对应的混淆映射关系。

DEX保护

DEX文件是Android 应用程序的逻辑所在处,所以DEX文件的安全至关重要,我们可以对ProGuard进行代码混淆,代码混淆只是增加了逆向的阅读难度,却不能真正的解决防止逆向的问题,黑客还是可以通过动态注入的方式,将一些自定义的逻辑注入到我们的DEX文件中进行重编译。

DEX优化与混淆处理

DEX优化与混淆处理的目的就是为了对抗一些常见的逆向工具,使得在逆向DEX文件的时候产生崩溃与无法理解的信息,当然,也有些处理会让应用程序更加紧凑,使得程序运行更快的效果。

什么是壳

加壳,其实是一个形象的称呼,即给应用程序加一层保护,如同坚韧的外壳一样,加壳的全称应该是可执行程序资源压缩,是保护文件的一种常用的手段,加壳过后的程序可以直接运行,但是不能查看源代码,去壳的过程,我们一般又称为脱壳。

so文件保护

上面提到的Dex文件的加壳,虽然能够简单的实现我们的目的,但是这种加壳方式是用java方式实现的,被反编译的风险仍然很大,为了克服这个缺点,很容易就会想到我们是否能够将核心业务逻辑代码放到加密定的.jar文件或.apk中,在需要调用时用Native C/C++代码进行解密,同时完成对解密后的文件的完整性的校验,

这不能够完全满足我们的需求,因为使用C/C++来完成也会存在反汇编的风险,故此,对so文件进行加壳也就势在必行了,对so文件加壳主要解决两个问题:对ELF文件加壳,对Android系统中的so文件分加载,调用机制做处理。

防止二次打包

二次打包,又称为重打包,一般是在使用逆向工具APKTool等工具逆向修改后,进行APK文件重新生成的过程,被重新打包的apk应用文件,因为与之前的应用程序高度相似,市面上称为山寨货盗版APP。

在android系统操作系统中apk的唯一识别码是靠包名和签名来做鉴别的,包名和签名是绑定在一起的,一旦apk被反编译后签名自动消失,apk签名需要签名文件,签名文件是md5值基本上是无法伪造成一致的,Android要求安装到手机上的apk文件必须有签名,而理论上开发者的签名他人是无法得到的(有密码),所以比较容易想到的就是执行签名校验,验证本程序的签名是否为合法程序。

目前市面上的很多应用商店也是通过开发者提供的包名与签名做正版判断,所以我们需要对自己的程序apk防止二次打包,也就是在自己的应用程序内部加入代码验证自我的签名与包名是否被篡改,如果被篡改了,那么肯定是被二次打包了。

private static final String SIGNATRUE_MD5 = "";//定义正版的签名md5值
String getMd5 = getSignatrueMd5(this);
//和apk当前的签名文件相比较,判断是否是原始的文件
if(!SIGNATRUE_MD5.equals(getMd5)){
    System.exit(0);//签名不正确,强行推退出
}
//获取当前apk的md5
 public static String getSignatrueMd5(Context context){
        String backString = "";

        try {
            PackageInfo mPackageinfo = context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_SIGNATURES);
            byte[] arrayOfByte = mPackageinfo.signatures[0].toByteArray();
            backString = DigestUtil.md5(arrayOfByte);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return backString;
    }

 

这种保护的方式虽然可行,但是如果面对的是专业打包党的话,这种方式意义不大,因为在逆向后,我们在Smali代码中搜索签名方法中使用到的相关方法关键字,就能够快速定位到签名文件判断的相关操作处。修改文件后,再次重新打包,就会避开我们的验证方法。

ndk技术底层获取签名和验证

在java代码中做验证很容易被逆向者修改,所以很多人想到,将判断逻辑放置入C/C++中去实现,通过Context、Activity、PackageManager、PackageInfo四个对象中的一个作为参数参入底层,在底层获取签名信息并验证,因为获取和验证的方法都封闭在更安全的so库里面,所以能够在一定意义上起到保护的作用,

但是C/C++编译出来的so文件在逆向中确实比较困难,但是却不是不可攻破的难题,通过java层的hook技术护着IDA PRO等反编译工具修改一样可以把这种保护完美破解,相对于前两种,此种保护的意义和价值就更大了。

 

 

发布了15 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qinggancha/article/details/103246991