android对app代码混淆
接到新任务。现有项⽬的代码混淆。在此之前混淆了⼀些理解,但还不够具体和全⾯,我知道有些东西混起来相当棘⼿。
但幸运的是,现在这个项⽬是不是太复杂(对于这有些混乱)。提前完成~~这是总结。
第⼀部分
介绍下操作流程(eclipse):
1、打开混淆器:到项⽬根⽂件夹下的project.properties⽂件,将“#fig=${sdk.dir}/tools/proguard/proguard-
<:”这⾏前的“#”删除就可以;
2、改动混淆配置⽂件:到项⽬根⽂件夹下的⽂件。改动当中代码,这部分是最关键;
3、保存相关⽂件供以后出错时使⽤:主要有导出的apk⽂件、项⽬根⽂件夹下的proguard⽂件夹下的⽂件(基本的是)和项⽬源代码;
4、项⽬执⾏过程出错处理:依据错误信息和第3步中保存的mapping定位错误位置。
知道这些之后。我们对其进⾏展开。打开eclipse然后新建⼀个项⽬,默认会创建和project.properties。编写我们的代码。然后将的“#fig=${sdk.dir}/tools/:”这⾏前的“#”删除,最后导出就可以实现对代码的混淆,即使我们没有去编写中的内容。
以下是我的測试代码:
public class MainActivity extends Activity {
private String mName;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
mName = "ttdevs";
getString(mName);
setName(mName);
showDialog();
// testError();
}
public String getString(String name) {
return "hello " + name;
}
public void setName(String name) {
System.out.println("I'm " + name);
}
private void showDialog() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
ScoreAlertDialog.showDialog(MainActivity.this);
}
}, 2000);
}
public static class ScoreAlertDialog {
public static void showDialog(final Activity activity) {
if (activity.isFinishing()) {
return;
}
try {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("alert_title");
builder.setNegativeButton("cancel", null);
builder.setPositiveButton("submit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
Toast.makeText(activity, "Welcome", Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
builder.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void testError() {
try {
int error = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
打包,反编译,最后我们得到例如以下的代码:
分析上⾯的代码我们会发现,⾃⼰定义的⽅法名都被替换成⽆特殊意义的短字母,⽽activity的onCreat
e()⽅法却没变;最后⼀个testError()⽅法因为我们没有调⽤也被剔除掉了。这些就是默认的混淆处理策略。看到这⾥,感觉混淆还是⼩case的哈~~
继续往下,我们将注销的testError()打开,打包执⾏这个时候会报错。错误信息例如以下:
java.lang.ArithmeticException: divide by zero
devs.proguard.MainActivity.b(Unknown Source)
devs.Create(Unknown Source)
at android.app.Activity.performCreate(Activity.java:4531)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2150)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2229)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1261)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4945)
at flect.Method.invokeNative(Native Method)
at flect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
因为这个样例⽐較简单,⾮常easy看出来是何地⽅出了问题。只是还是能够⽤来说明我们想表达的问题:怎样还原混淆后的代码的错误信息。为了达到这个⽬的。我们须要三个⽂件:android-sdk-windows\tools\proguard\bin\retrace.bat、和上⾯的错误信息
()。然后运⾏以下的命令(window系统):
retrace.
从上图中能够⾮常清楚的看到错误⽇志中的b()⽅法为我们实际代码中的setName()⽅法。
这⾥须要注意的是每次导出apk都会在项⽬中⽂件夹下的proguard⽂件夹下⽣成⼀个相应的mapping⽂件,所以对于每⼀个apk我们都须要保存与之相应的mapping⽂件。⾄此整个混淆的流程介绍完成。
參考:
eclipse开发手机app官⽅⽂档:
官⽅⽂档的翻译:(本想⾃⼰去翻⼀个。结果发现⾮常久曾经农民伯伯已经翻译,在此直接引⽤并感谢之)
第⼆部分
第⼀部分讲了怎样操作,參照官⽅⽂档,基本都会掌握。
剩下的也是最难的就是⽂件的编写。对于这部分,两种处理策略:⾃⼰编写和使⽤别⼈写好的。
先说怎样使⽤别⼈写好的,我们引⽤的第三⽅库不管开源还是闭源如有特殊情况我们都能够在他的User Guide中到混淆代码的配置,如我们引⽤了⼤名⿍⿍的,我们能够在中到例如以下的代码:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * t.BroadcastReceiver
-keep public class * t.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(t.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(t.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
有了这部分代码我们就能够直接copy插⼊我们的项⽬中就可以。这样的⽅式还是copy式的。那以下我们举个⼩样例看看怎样⾃⼰写代码控制是否混淆。还是⽤第⼀部分的样例。我们在这个项⽬的⽂件⾥(之前为空)增加例如以下⼏⾏(
中“#”代表凝视):
# -keep public devs.proguard.** { *; }
# -keepclasseswithmembers public devs.proguard.** { *; }
-keep public devs.proguard.MainActivity {
java.lang.String getString(java.lang.String);
}
然后我们在导出apk然后反编译。得到例如以下代码:
和之前的对照。我们发现当中的getString⽅法没有被混淆。
没错。上⾯的意思就是保持MainActivity的getString()⽅法不要被混淆。
⼤家也能够试试上述混淆代码中被凝视的两⾏各⾃是什么效果。
说到这⾥已经開始涉及ProGuard的核⼼部分了,剩下的就是研读。掌握的他的语法并使⽤之。
本想⼀个完整的ProGuard的翻译⽂档,可是了N久没有发现⼀个。并且连零零散散的翻译也⾮常的少,近期时间⾮常紧。加之能⼒有限,想翻译⼀下经常使⽤的⼏个命令也是⾮常困,所以细读的想法仅仅能临时往后推了。这⾥先简介下keep命令:
在你的代码中指定作为切⼊点⽽被保留的类或者类的成员(属性和⽅法)。⽐如,为了保持⼀个应⽤,你能够指定主类和他的main⽅法。为了处理⼀个库,你须要具体说明他的public訪问的元素。
和。
Class Specification中会告诉你怎样表⽰构造⽅法。属性和⽅法,"*" 与“**”的差别等等。⽐⽅"*"表⽰匹配不论什么的类名可是不包含包的分隔符。⽽"**"则是匹配不论什么的类名⽽且包含随意数量的包分隔符。因此上⾯我们凝视掉的代码意思例如以下:第⼀⾏:保持
// TODO 细节还有⾮常多。⽐⽅-libraryjars、-dontwarn、-keepattributes等等。这些待续吧
參考:
ProGuard 5.0:()
版权声明:本⽂博主原创⽂章。博客,未经同意不得转载。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论