简单程序破解
对于简单的字符串类型的校验,客户端的校验破解起来时比较简单的。
java层代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class MainActivity extends Activity {
private Button btn_login; private EditText username; private EditText password; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_login = (Button) findViewById(R.id.btn_Login); username = (EditText) findViewById(R.id.username); password = (EditText) findViewById(R.id.password); btn_login.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(username.getText().toString().equals("wker") && password.getText().toString().equals("wfc")) { Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show(); }else { Toast.makeText(MainActivity.this, "false", Toast.LENGTH_SHORT).show(); } } }); } }
|
没什么特别的只是单纯的进行了一个字符串的校验,校验完毕就弹出一个toast。
逆向分析
我们先用逆向的工具加载APK,Android Killer就够了,我们得到这个样子的一个文件视图:
可以看到,在我们的MainActivity中分出了两个smali文件,一个是我们的内部类,其实我们也就知道了,也就是我们在点击响应事件中的那个内部类,所以我们就直接分析就好了。
1 2 3
| .class Lcom/pj/crack_one/MainActivity$1; .super Ljava/lang/Object; .source "MainActivity.java"
|
这个就是简单的声明了一下类的一些信息,名称啊,父类啊之类的。
1 2
| .implements Landroid/view/View$OnClickListener;
|
实现的接口。
1 2 3 4 5 6 7 8 9
| .annotation system Ldalvik/annotation/EnclosingMethod; value = Lcom/pj/crack_one/MainActivity;->onCreate(Landroid/os/Bundle;)V .end annotation
.annotation system Ldalvik/annotation/InnerClass; accessFlags = 0x0 name = null .end annotation
|
这个貌似是一个注解,具体是什么意思暂时不了解,不影响。
1 2
| .field final synthetic this$0:Lcom/pj/crack_one/MainActivity;
|
这个就是一个实例对象,也就是外部类自身。
1 2 3 4 5 6 7 8 9 10 11 12 13
| .method constructor <init>(Lcom/pj/crack_one/MainActivity;)V .locals 0
.prologue .line 1 iput-object p1, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
.line 25 invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void .end method
|
这个就是构造方法,可以看到除了初始的那个无参构造方法,他在前面添加了一个赋值操作,将p1寄存器的值赋值为实例对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| .method public onClick(Landroid/view/View;)V .locals 3 .param p1, "v"
.prologue const/4 v2, 0x0
.line 29 iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
invoke-static {v0}, Lcom/pj/crack_one/MainActivity;->access$0(Lcom/pj/crack_one/MainActivity;)Landroid/widget/EditText;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-interface {v0}, Landroid/text/Editable;->toString()Ljava/lang/String;
move-result-object v0
const-string v1, "wker"
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :cond_0
iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
invoke-static {v0}, Lcom/pj/crack_one/MainActivity;->access$1(Lcom/pj/crack_one/MainActivity;)Landroid/widget/EditText;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-interface {v0}, Landroid/text/Editable;->toString()Ljava/lang/String;
move-result-object v0
const-string v1, "wfc"
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :cond_0
.line 31 iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
const-string v1, "success"
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 36 :goto_0 return-void
.line 34 :cond_0 iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
const-string v1, "false"
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
goto :goto_0 .end method
|
这个就是我们关注的重点。
首先我们用到了3个寄存器
参数的一个名字,传进来一个View对象
1 2
| .prologue const/4 v2, 0x0
|
代码开始,并且将v2寄存器赋值为0x0
1
| iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
|
这个就是将v0赋值为我们p0指向的this,其实也就是外部类的对象。
1 2 3
| invoke-static {v0}, Lcom/pj/crack_one/MainActivity;->access$0(Lcom/pj/crack_one/MainActivity;)Landroid/widget/EditText;
move-result-object v0
|
这个用到了access这个方法,这个方法其实就是在内部类调用外部类私有成员的时候自动生成的。
1 2 3 4 5 6 7 8 9
| .method static synthetic access$0(Lcom/pj/crack_one/MainActivity;)Landroid/widget/EditText; .locals 1
.prologue .line 14 iget-object v0, p0, Lcom/pj/crack_one/MainActivity;->username:Landroid/widget/EditText;
return-object v0 .end method
|
其实可以看出,也就是返回了username这个编辑框的对象。
1 2 3 4 5 6 7
| invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-interface {v0}, Landroid/text/Editable;->toString()Ljava/lang/String;
move-result-object v0
|
这个就是一样的东西,就是获取Text,然后给v0,然后获得toString,再给v0。
1 2 3 4 5
| const-string v1, "wker"
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
|
这个就是给v1赋值之后,将其与v0比较,然后将得到的结果给v0,也就是比较的返回值。
这个就是判断如果是0的话呢就跳转,也就是打印错误的。
下面判断密码的代码是基本一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .line 34 :cond_0 iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
const-string v1, "false"
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
goto :goto_0
|
可以看到如果跳到cond_0的话呢就是打印错误,所以最简单的方法就是,将两个if语句干掉,就不会跳转,而是直接一直往下执行,执行到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .line 31 iget-object v0, p0, Lcom/pj/crack_one/MainActivity$1;->this$0:Lcom/pj/crack_one/MainActivity;
const-string v1, "success"
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 36 :goto_0 return-void
|
也就执行打印成功,最后返回了。
最后编译,结果和我们预想的是一样的。