Android逆向学习#2

突破用户名和口令的验证

1、编写一个验证app给下一位同学。app功能如下:如果用户名和口令输入正确则显示“恭喜你通过验证!”,否则显示“验证失败!”
2、在获得上一位同学编写的app后,争取能够突破用户和口令的验证,让app显示“恭喜你通过验证!”

Android逆向学习#2
我的代码是比较两个输入是否相等,是否都是xswsx

破解

一、分析代码

收到文件,首先用apktool查看文件解包:
输入命令

apktool d app-debug.apk -o ./decode -f

Android逆向学习#2
打开smali目录,查看java的smali语句

\decode\smali\com\example\myapplication

Android逆向学习#2
目录下查看的smali文件,应该只有MainActivity$1是编辑过的,直接进入查看

头文件:
Android逆向学习#2
接口:(一个监听事件)
Android逆向学习#2
注释:
Android逆向学习#2
上面这三部分是类似于框架的android studio 新建activity时的文件头
接下来是声明字段,可以看到有两个EditText
Android逆向学习#2
接下来的Virtual method就是方法的具体内容了,我们来分析一下

tips:跳转语句基础
Android逆向学习#2

line23

.line 23
    iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->val$editText:Landroid/widget/EditText;
    invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    move-result-object v0
    invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    move-result-object v0

很简单,声明一个EditText,并将getText的值给v0

line24

.line 24
    .local v0, "user":Ljava/lang/String;
    iget-object v1, p0, Lcom/example/myapplication/MainActivity$1;->val$editText1:Landroid/widget/EditText;
    invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    move-result-object v1
    invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;
    move-result-object v1

和line23一样,将输入的值赋给v1

line25

.line 25
    .local v1, "pwd":Ljava/lang/String;
    const-string v2, "admin"
    invoke-virtual {v0, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    const-string v3, "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef\uff01"
    const-string v4, ""
    const/4 v5, 0x1
    if-eqz v2, :cond_2
  • unicode转中文:
    Android逆向学习#2

line25这里的pwd是一个string字符串,现在没有被初始化
equals的调用,用来判断V0(输入的值) V2(赋值为admin)是否相等,第三行最后的Z代表类别为Boolean真假
如果相等返回1,不相等返回0,所以最后有个 if-eqz v2, :cond_2,v0和v2不相等(账号错误)的话则跳转到cond_2
这段代码的意思就是判断用户名输入是否为admin,若不是admin,跳转到cond_2

line26

.line 26
    const-string v2, "password"
    invoke-virtual {v1, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    if-eqz v2, :cond_0

line26这里v2被设为password,比较v1(输入)和v2是否相等
和line25同理,如果v1和v2不相等(密码错误)则前往cond_0,如果为真,则执行line27

line27

.line 27
    iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    const-string v3, "\u606d\u559c\u4f60\u767b\u5f55\u6210\u529f\uff01"
    invoke-static {v2, v3, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v2
    invoke-virtual {v2}, Landroid/widget/Toast;->show()V
    goto :goto_0
  • unicode转中文:Android逆向学习#2

这是用户名和密码都正确的结果,v3被置为输出正确的提示,invoke一个makeText函数输出v3的内容,然后goto_0(结束)

line29-30——cond_0

.line 29
    :cond_0
    invoke-virtual {v1, v4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    if-eqz v2, :cond_1

这是cond_0的内容,调用equal判断v1是否为空(line25里v4被置为空)
如果判断结果等于0(密码不为空)则跳转到cond_1,否则执行line30的报错提示

.line 30
    iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    const-string v3, "\u5bc6\u7801\u4e0d\u53ef\u4e3a\u7a7a\uff01"
    invoke-static {v2, v3, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v2
    invoke-virtual {v2}, Landroid/widget/Toast;->show()V
    goto :goto_0
  • unicode转中文:
    Android逆向学习#2

这是cond_0的结果,即输出“密码不可为空”后退出。

line33——cond_1

.line 33
    :cond_1
    iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    invoke-static {v2, v3, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v2
    invoke-virtual {v2}, Landroid/widget/Toast;->show()V
    goto :goto_0

cond_1的内容是输出v3的值,因为初始值是“用户名或密码错误”,所以直接输出v3的值即可

line36-37——cond_2

.line 36
    :cond_2
    invoke-virtual {v0, v4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    if-eqz v2, :cond_3

判断用户名v0是否为空,跳转来自line25的判断,原理同cond_0
如果判断结果等于0(用户名不为空)则跳转到cond_1,否则执行line37的报错提示

.line 37
    iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    const-string v3, "\u7528\u6237\u540d\u4e0d\u53ef\u4e3a\u7a7a\uff01"
    invoke-static {v2, v3, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v2
    invoke-virtual {v2}, Landroid/widget/Toast;->show()V
    goto :goto_0
  • unicode转中文:
    Android逆向学习#2
    这是cond_2的结果,即输出用户名不可为空后退出。

line40——cond_3

.line 40
    :cond_3
    iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    invoke-static {v2, v3, v5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v2
    invoke-virtual {v2}, Landroid/widget/Toast;->show()V

line42

.line 42
    :goto_0
    return-void

结束

总结

代码分析完毕,大概思路:

判断用户名和密码是否为admin和password

  • 若正确,更改v3的值并输出正确破解提示
  • 若错误,判断输入是否为空
    – 若为空,输出为空的报错
    – 若非空,则输出原来的v3值(错误提示)

二、更改

思路有很多,因为代码的逻辑有点奇怪,是先判断是否正确再判断是否为空,所以可以把前面的用户名和密码比对字符串都置为空也能实现;又或者,把用户名输错时跳cond_2和密码输错时跳cond_0都设置成永真1,不跳转,那么执行完line27的正确语句后正常结束也能实现。
这里我们尝试永真

    .line 25
    .local v1, "pwd":Ljava/lang/String;
    const-string v2, "admin"
    invoke-virtual {v0, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    const-string v3, "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef\uff01"
    const-string v4, ""
    const/4 v5, 0x1
    if-ne v2,v2, :cond_2

    .line 26
    const-string v2, "password"
    invoke-virtual {v1, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v2
    if-ne v2,v2, :cond_0

将这两处的跳转更改为和自己做对比即可,记得改前先备份,方便回溯
接下来在cmd中用apktool打包,使用命令

apktool b ./decode -o fake.apk -f

意思是选定decode打包编译成fake.apk文件
Android逆向学习#2
输入命令:

keytool -genkeypair -keyalg RSA -validity 100 -keystore rsa.keystore -alias mykeypair

意思是生成一个使用RSA,有效期100天的rsa.keystore文件,mykeypair用以索引证书链
自定义密钥库口令,随意填写或直接多次回车跳到最后确定选Y结束,最后可以再次回车

上一篇:JAVA运行报错 [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;


下一篇:ssh 报错hibernate java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to XXX