突破用户名和口令的验证
1、编写一个验证app给下一位同学。app功能如下:如果用户名和口令输入正确则显示“恭喜你通过验证!”,否则显示“验证失败!”
2、在获得上一位同学编写的app后,争取能够突破用户和口令的验证,让app显示“恭喜你通过验证!”
我的代码是比较两个输入是否相等,是否都是xswsx
破解
一、分析代码
收到文件,首先用apktool查看文件解包:
输入命令
apktool d app-debug.apk -o ./decode -f
打开smali目录,查看java的smali语句
\decode\smali\com\example\myapplication
目录下查看的smali文件,应该只有MainActivity$1是编辑过的,直接进入查看
头文件:
接口:(一个监听事件)
注释:
上面这三部分是类似于框架的android studio 新建activity时的文件头
接下来是声明字段,可以看到有两个EditText
接下来的Virtual method就是方法的具体内容了,我们来分析一下
tips:跳转语句基础
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转中文:
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转中文:
这是用户名和密码都正确的结果,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转中文:
这是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转中文:
这是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文件
输入命令:
keytool -genkeypair -keyalg RSA -validity 100 -keystore rsa.keystore -alias mykeypair
意思是生成一个使用RSA,有效期100天的rsa.keystore文件,mykeypair用以索引证书链
自定义密钥库口令,随意填写或直接多次回车跳到最后确定选Y结束,最后可以再次回车