经过前面对各种反编译工具apktool,dx2jar,jd-gui等工具的介绍,本章节我们结合一个实际的案例,向大家讲解如何分析Android程序。
一、分析步骤
1.使用dex2jar和jd-gui工具分析Java反编译源码;
2.使用apktools,反编译Smail文件。由于Smail语法单独阅读比较困难,我们可以结合Java反编译的源码进行分析;
3.根据相关的特征和线索,修改Smail源码,使用apktools重新打包;
4.使用jarsigner重新签名apk,安装并验证修改是否正确,重复步骤3;
二 、案例简介
这里我们以最简单的用户登录为案例,校验用户输入用户名和密码通过,则Toast显示Login Success!,否则Login Faild!(运行如下图):

三、分析实践
1.使用dex2jar和jd-gui工具分析Java反编译登录页面源码NextActivity(相关工具的使用,查看《安全和逆向》系列博客相关文章):

2.使用apktools(相关工具的使用,查看《安全和逆向》系列博客相关文章),反编译Smail主要Smail文件(如下图):

3.分析由Java源码可知,相关的Smail文件为NextActivity.smail和NextActivity$1.smail文件(相关Smail语法,查看《安全和逆向》系列博客相关文章),详细如下:
NextActivity.smail文件:
一、分析步骤
1.使用dex2jar和jd-gui工具分析Java反编译源码;
2.使用apktools,反编译Smail文件。由于Smail语法单独阅读比较困难,我们可以结合Java反编译的源码进行分析;
3.根据相关的特征和线索,修改Smail源码,使用apktools重新打包;
4.使用jarsigner重新签名apk,安装并验证修改是否正确,重复步骤3;
二 、案例简介
这里我们以最简单的用户登录为案例,校验用户输入用户名和密码通过,则Toast显示Login Success!,否则Login Faild!(运行如下图):
三、分析实践
1.使用dex2jar和jd-gui工具分析Java反编译登录页面源码NextActivity(相关工具的使用,查看《安全和逆向》系列博客相关文章):
2.使用apktools(相关工具的使用,查看《安全和逆向》系列博客相关文章),反编译Smail主要Smail文件(如下图):
3.分析由Java源码可知,相关的Smail文件为NextActivity.smail和NextActivity$1.smail文件(相关Smail语法,查看《安全和逆向》系列博客相关文章),详细如下:
NextActivity.smail文件:
.class public Lcom/qunar/hotel/NextActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "NextActivity.java"
# instance fields
.field private mLogin:Landroid/widget/Button;
.field private mPassword:Landroid/widget/EditText;
.field private mUser:Landroid/widget/EditText;
# direct methods
.method public constructor <init>()V
.locals 0
... ...
return-object v0
.end method
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 2
.param p1, "aSavedInstanceState" # Landroid/os/Bundle;
.prologue
.line 23
invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
.line 24
sget v0, Lcom/qunar/hotel/R$layout;->activity_next:I
invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->setContentView(I)V
.line 26
sget v0, Lcom/qunar/hotel/R$id;->user:I
invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/EditText;
iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mUser:Landroid/widget/EditText;
.line 27
sget v0, Lcom/qunar/hotel/R$id;->password:I
invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/EditText;
iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mPassword:Landroid/widget/EditText;
.line 28
sget v0, Lcom/qunar/hotel/R$id;->login:I
invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mLogin:Landroid/widget/Button;
.line 30
iget-object v0, p0, Lcom/qunar/hotel/NextActivity;->mLogin:Landroid/widget/Button;
new-instance v1, Lcom/qunar/hotel/NextActivity$1;
invoke-direct {v1, p0}, Lcom/qunar/hotel/NextActivity$1;-><init>(Lcom/qunar/hotel/NextActivity;)V
invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 40
return-void
.end method
NextActivity#1.smail文件: .class Lcom/qunar/hotel/NextActivity$1;
.super Ljava/lang/Object;
.source "NextActivity.java"
# interfaces
.implements Landroid/view/View$OnClickListener;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/qunar/hotel/NextActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/qunar/hotel/NextActivity;
# direct methods
.method constructor <init>(Lcom/qunar/hotel/NextActivity;)V
.locals 0
.param p1, "this$0" # Lcom/qunar/hotel/NextActivity;
.prologue
.line 30
iput-object p1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 4
.param p1, "aView" # Landroid/view/View;
.prologue
const/4 v3, 0x0
//判断用户名和密码的正确性
.line 33
iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
# getter for: Lcom/qunar/hotel/NextActivity;->mUser:Landroid/widget/EditText;
invoke-static {v0}, Lcom/qunar/hotel/NextActivity;->access$000(Lcom/qunar/hotel/NextActivity;)Landroid/widget/EditText;
move-result-object v0
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
const-string v1, "user"
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
//如果equals方法返回true
if-eqz v0, :cond_0
iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
# getter for: Lcom/qunar/hotel/NextActivity;->mPassword:Landroid/widget/EditText;
invoke-static {v0}, Lcom/qunar/hotel/NextActivity;->access$100(Lcom/qunar/hotel/NextActivity;)Landroid/widget/EditText;
move-result-object v0
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
const-string v1, "123456"
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
//如果equals方法返回true
if-eqz v0, :cond_0
//登录成功弹出Login Scuess Tost提示
.line 34
iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
invoke-virtual {v0}, Lcom/qunar/hotel/NextActivity;->getApplication()Landroid/app/Application;
move-result-object v0
iget-object v1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
invoke-virtual {v1}, Lcom/qunar/hotel/NextActivity;->getResources()Landroid/content/res/Resources;
move-result-object v1
sget v2, Lcom/qunar/hotel/R$string;->login_success:I
invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1, v3}, 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 38
:goto_0
return-void
//登录失败弹出Login Faild Tost提示
.line 36
:cond_0
iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
invoke-virtual {v0}, Lcom/qunar/hotel/NextActivity;->getApplication()Landroid/app/Application;
move-result-object v0
iget-object v1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
invoke-virtual {v1}, Lcom/qunar/hotel/NextActivity;->getResources()Landroid/content/res/Resources;
move-result-object v1
sget v2, Lcom/qunar/hotel/R$string;->login_faild:I
invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1, v3}, 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
4.分析相关Smail和Java文件,通过相关login_success,Toast,equals等关键字,阅读出基本的代码逻辑。该案例在Java源码中已经清晰得出用户名和密码为user,123456,这里我们演示如何通过分析修改smail文件“破译”。阅读关键代码如下,我们可以将if(mUser.getText().toString().equals("user"))语句修改为if("user".equals("user")),同理if("12345".equals("123456")),即invoke-virtual {v0, v1}修改为invoke-virtual {v1, v1}即可“绕过”用户名和密码验证。实际开发情况会比较复杂,这里我们仅仅简单修改用于演示分析过程; //mUser.getText()
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
//mUser.getText().toString()
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
const-string v1, "user"
//if(mUser.getText().toString.equals("user"))
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
//if(mUser.getText().toString.equals("user") == true)
if-eqz v0, :cond_0
5.重新打包并签名apk(相关工具的使用,查看《安全和逆向》系列博客相关文章),安装后验证如下图,成功“绕过”用户名和密码验证;
新技术,新未来!欢迎大家关注
“1024工场”微信服务号
,时刻关注我们的最新的技术讯息!
(甭客气!尽情的扫描或者长按!)