首页
社区
课程
招聘
[原创]我的第二个Android CrackMe算法分析 (smali)
发表于: 2015-5-7 03:22 8938

[原创]我的第二个Android CrackMe算法分析 (smali)

2015-5-7 03:22
8938
上次在其他论坛找了几个入门级别的Android CrackMe,这个是第二个,后面还会继续分析剩下的几个。

运行截图:

首先使用apktool将apk进行反编译,看了下程序清单文件,程序启动后显示运行EX05_01类

到反编译好的smali文件中,打开EX05_01.smali

为了学习和熟悉smali语法,我把EX05_01.smali 和 它的一个匿名类EX05_01$1.smali从头到尾都做了注释,注释如下:

EX05_01.smali的注释
//当前类
.class public Lirdc/ex05_01/EX05_01;

//当前类的父类
.super Landroid/app/Activity;

//当前类所在的源码文件
.source "EX05_01.java"

//当前类的普通数据成员
# instance fields

//有一个私有数据成员,名为mEditText01,类型为EditText对象引用
.field private mEditText01:Landroid/widget/EditText;

//有一个私有数据成员,名为mTextView01,类型为TextView对象引用
.field private mTextView01:Landroid/widget/TextView;


//当前类的直接方法
# direct methods
//无参构造
.method public constructor <init>()V
    //该方法寄存器变量个数0
    .locals 0

    //该方法代码开始
    .prologue
    .line 10

    //调用父类构造
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    return-void
.end method


//当前类的静态方法,看样子像是编译器自动生成的
//为了保证匿名类或内部类访问外部累的私有成员
//一个参数,EX05_01类的对象引用,返回值为TextView对象引用
//返回值为TextView对象引用
.method static synthetic access$0(Lirdc/ex05_01/EX05_01;)Landroid/widget/TextView;
    //该方法寄存器变量个数1
    .locals 1

    //该方法代码开始
    .prologue
    .line 12

    //获取普通数据成员到v0, p0为this指针(参数传递进来的)
    //数据成员名为mTextView01,类型为TextView对象引用
    iget-object v0, p0, Lirdc/ex05_01/EX05_01;->mTextView01:Landroid/widget/TextView;

    //返回获取的对象引用
    return-object v0
.end method


//当前类的普通方法
# virtual methods

//有一个公有方法,名为onCreate,有一个参数,类型为Bundle对象引用,无返回值
.method public onCreate(Landroid/os/Bundle;)V
    //该方法寄存器变量个数为2
    .locals 2

    //该方法第一个参数p1变量名为savedInstanceState,类型为Bundle对象引用
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    //该方法代码开始
    .prologue
    .line 18

    //调用父类Activity的onCreate方法,参数为Bundle对象引用,p0为this指针,无返回值
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 19
    
    //寄存器赋值 v0 = 0x7f030000
    const/high16 v0, 0x7f030000

    //调用EX05_01类的setContentView方法,参数为int,无返回值,p0为this指针
    invoke-virtual {p0, v0}, Lirdc/ex05_01/EX05_01;->setContentView(I)V

    .line 20

    //寄存器赋值 v0 = 0x7f050000
    const/high16 v0, 0x7f050000

    //调用EX05_01类的findViewById方法,参数为int,返回值为View对象引用
    invoke-virtual {p0, v0}, Lirdc/ex05_01/EX05_01;->findViewById(I)Landroid/view/View;

    //获取返回值到v0
    move-result-object v0

    //类型转换成TextView对象引用
    //v0 = (TextView)v0
    check-cast v0, Landroid/widget/TextView;

    //设置普通数据成员,名为mTextView01,类型为TextView对象引用
    //mTextView01 = v0
    iput-object v0, p0, Lirdc/ex05_01/EX05_01;->mTextView01:Landroid/widget/TextView;

    .line 21

    //寄存器赋值  v0 = 0x7f050002
    const v0, 0x7f050002

    //调用EX05_01类的findViewById方法,参数为int,返回值为View对象引用
    invoke-virtual {p0, v0}, Lirdc/ex05_01/EX05_01;->findViewById(I)Landroid/view/View;

    //获取返回值到v0
    move-result-object v0

    //类型转换成EditText对象引用
    //v0 = (EditText)v0
    check-cast v0, Landroid/widget/EditText;

    //设置普通数据成员,名为mEditText01,类型为EditText对象引用
    //mEditText01 = v0
    iput-object v0, p0, Lirdc/ex05_01/EX05_01;->mEditText01:Landroid/widget/EditText;

    .line 22

    //获取普通数据成员,名为mEditText01,类型为EditText对象引用
    //v0 = mEditText01
    iget-object v0, p0, Lirdc/ex05_01/EX05_01;->mEditText01:Landroid/widget/EditText;

    //new 匿名类
    new-instance v1, Lirdc/ex05_01/EX05_01$1;

    //匿名类构造,参数为外部类(EX05_01)this指针,无返回值
    //编译器自动生成的,为了保证匿名类可以访问外部类的私有成员
    invoke-direct {v1, p0}, Lirdc/ex05_01/EX05_01$1;-><init>(Lirdc/ex05_01/EX05_01;)V

    //调用EditText类的setOnKeyListener方法,参数为View$OnKeyListener对象引用,无返回值
    //v0为this指针,v1为参数
    //v0 = mEditText01
    invoke-virtual {v0, v1}, Landroid/widget/EditText;->setOnKeyListener(Landroid/view/View$OnKeyListener;)V

    .line 44

    //函数退出,无返回值
    return-void
.end method


EX05_01$1.smali的注释
//当前类
.class Lirdc/ex05_01/EX05_01$1;

//当前类的父类
.super Ljava/lang/Object;

//当前类所在的源码文件
.source "EX05_01.java"

//接口注释
# interfaces
.implements Landroid/view/View$OnKeyListener;

//注释
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lirdc/ex05_01/EX05_01;->onCreate(Landroid/os/Bundle;)V
.end annotation

//匿名类   name = null
.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation


//编译器自动添加了一个数据成员为外部类的this指针
//外部类 ==> EX05_01
# instance fields
.field final synthetic this$0:Lirdc/ex05_01/EX05_01;


//该类的直接方法(构造或私有方法)
# direct methods

//编译器自动生成的构造函数
.method constructor <init>(Lirdc/ex05_01/EX05_01;)V
    .locals 0

    .prologue
    .line 1

    //保存外部类的this指针
    iput-object p1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    .line 22

    //调用父类构造
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method


//当前类的普通成员方法
# virtual methods

//有一个公有的成员方法,名为onKey,返回值为boolean
//该方法第一个参数为View的对象引用
//第二个参数为int
//第三个参数为KeyEvent的对象引用
.method public onKey(Landroid/view/View;ILandroid/view/KeyEvent;)Z
    //该方法寄存器个数4
    .locals 4

    //该方法第一个参数p1的变量名为arg0,类型为View的对象引用
    .param p1, "arg0"    # Landroid/view/View;
    //该方法第二个参数p2的变量名为arg1,类型为int
    .param p2, "arg1"    # I
    //该方法第三个参数p3的变量名为arg3,类型为KeyEvent的对象引用
    .param p3, "arg2"    # Landroid/view/KeyEvent;

    //该方法代码开始
    .prologue

    //寄存器赋值 v3 = 1
    const/4 v3, 0x1

    .line 28

    //寄存器赋值 v0 = "gogo"
    const-string v0, "gogo"

    .line 30

    //寄存器v0的变量名为str,类型为String对象引用
    .local v0, "str":Ljava/lang/String;

    //寄存器赋值v1 = "11"
    const-string v1, "11"

    //调用String类的equals成员方法,参数为Object对象引用,返回值为boolean
    //v0 == this指针
    //v1 == 参数
    invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    //获取返回值到寄存器v1
    move-result v1

[COLOR="Red"]    
    //条件判断,当v1 == 0时,跳转到cond_0标号处
    if-eqz v1, :cond_0

    //此处改成  if-nez v1, :cond_0   即可成功
[/COLOR]

    .line 31

    //获取外部类的this指针保存到v1寄存器
    iget-object v1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    # getter for: Lirdc/ex05_01/EX05_01;->mTextView01:Landroid/widget/TextView;

    //调用EX05_01类的access$0静态方法,参数为EX05_01对象引用,返回值为TextView对象引用
    //v1 == 参数,静态方法无需this指针
    invoke-static {v1}, Lirdc/ex05_01/EX05_01;->access$0(Lirdc/ex05_01/EX05_01;)Landroid/widget/TextView;

    //获取返回值到v1寄存器
    move-result-object v1

    //调用TextView类的setText方法,参数为CharSequence对象引用,无返回值
    //v1 == this指针
    //v0 == 参数
    invoke-virtual {v1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 32

    //获取外部类的this指针到寄存器v1
    iget-object v1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    //寄存器赋值v2 = "right++"
    const-string v2, "right++"

    //调用Toast的makeText静态方法,返回值为Toast对象引用
    //第一个参数为Context对象引用	v1
    //第二个参数为CharSequence对象引用 v2
    //第三个参数为int v3
    invoke-static {v1, v2, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    //获取返回值到寄存器v1
    move-result-object v1

    //调用Toast类的show方法,无返回值
    //v1 == this指针
    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    .line 40

    //标号,用于goto到此标号
    :goto_0

    //获取外部类this指针到寄存器v1
    iget-object v1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    # getter for: Lirdc/ex05_01/EX05_01;->mTextView01:Landroid/widget/TextView;

    //调用EX05_01类的access$0静态方法,参数为EX05_01对象引用,返回值为TextView对象引用
    //v1 == 参数,静态方法无需this指针
    invoke-static {v1}, Lirdc/ex05_01/EX05_01;->access$0(Lirdc/ex05_01/EX05_01;)Landroid/widget/TextView;

    //获取返回值到v1寄存器
    move-result-object v1

    //寄存器赋值 v2 = 7
    const/4 v2, 0x7

    //调用Linkify类的addLinks静态方法,返回值为boolean
    //第一个参数为TextView对象引用
    //第二个参数为int
    invoke-static {v1, v2}, Landroid/text/util/Linkify;->addLinks(Landroid/widget/TextView;I)Z

    .line 41

    //寄存器赋值v1 = 0
    const/4 v1, 0x0

    //函数退出,返回值为v1
    return v1

    .line 35

    //标号,用于goto到此标号
    :cond_0

    //获取外部类this指针到寄存器v1
    iget-object v1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    # getter for: Lirdc/ex05_01/EX05_01;->mTextView01:Landroid/widget/TextView;

    //调用EX05_01类的access$0静态方法,参数为EX05_01对象引用,返回值为TextView对象引用
    //v1 == 参数,静态方法无需this指针
    invoke-static {v1}, Lirdc/ex05_01/EX05_01;->access$0(Lirdc/ex05_01/EX05_01;)Landroid/widget/TextView;

    //获取返回值到v1寄存器
    move-result-object v1

    //调用TextView类的setText方法,参数为CharSequence对象引用,无返回值
    //v1 == this指针
    //v0 == 参数
    invoke-virtual {v1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 36

    //获取外部类this指针到寄存器v1
    iget-object v1, p0, Lirdc/ex05_01/EX05_01$1;->this$0:Lirdc/ex05_01/EX05_01;

    //寄存器赋值 v2 = "error--"
    const-string v2, "error--"

    //调用Toast的makeText静态方法,返回值为Toast对象引用
    //第一个参数为Context对象引用	v1
    //第二个参数为CharSequence对象引用 v2
    //第三个参数为int v3
    invoke-static {v1, v2, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    //获取返回值到v1寄存器
    move-result-object v1

    //调用Toast类的show方法,无返回值
    //v1 == this指针
    invoke-virtual {v1}, Landroid/widget/Toast;->show()V

    //无条件跳转到goto_0标号处
    goto :goto_0
.end method


通过对smali代码的阅读,模拟还原了下这个CrackMe的算法C代码:
#include <string.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    if (strcmp("11", "gogo") == 0)
    {
        puts("ok");
    }
    else
    {
        puts("error");
    }

    return 0;
}


通过这个CrackMe的算法可以看到,不管输入任何值,最终都是错误,程序中使用的是两个固定的字符串做比较,所以只能通过修改smali中的条件判断达到爆破的目的(修改位置已在注释中加亮)。

附一张注册成功截图:


由于刚开始学习,如果有写的不对的地方,希望大家可以告诉我一下,谢谢。附件中打包了apk和注释的.smali文件。

CrackMe.apk.rar
smali.rar

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 459
活跃值: (398)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
不错,不错
2015-5-7 08:42
0
雪    币: 16645
活跃值: (1950)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
又看到 牛人了。
2015-5-7 08:59
0
雪    币: 506
活跃值: (156)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
4
学习了。
2015-5-7 09:07
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
5
继续学习。
2015-5-8 15:16
0
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不错!支持一下!
2015-5-16 14:40
0
游客
登录 | 注册 方可回帖
返回