自娛自樂 -- 自寫apk進(jìn)行smali分析

0x01 前言

演示APK: 自寫的一個(gè)簡單CrackMe
測試平臺: Win7 64
反編譯工具: APK改之理3.5

懵懵懂懂的第一次接觸apk調(diào)試课锌,有太多不懂與自我理解的偏差假丧,還望大家指正

為了不對上千行的代碼產(chǎn)生恐懼挚瘟,決定新人還是自寫小代碼進(jìn)行分析

先看下AndroidManifest.xml风钻,因?yàn)槭亲詫懖竦疲a不多

<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.a3st.demo">
    <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name="com.a3st.demo.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data android:name="android.support.VERSION" android:value="26.1.0"/>
        <meta-data android:name="android.arch.lifecycle.VERSION" android:value="27.0.0-SNAPSHOT"/>
    </application>
</manifest>

從中可以看出:

  1. 只有一個(gè)主活動.MainActivity
  2. 包名為com.a3st.demo

先貼上此文章需分析的MainActivity的smali源碼

.class public Lcom/a3st/demo/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"

# interfaces
.implements Landroid/view/View$OnClickListener;

# instance fields
.field private btnRegister:Landroid/widget/Button;

.field private editPassword:Landroid/widget/EditText;

.field private editUsername:Landroid/widget/EditText;


 
# direct methods
.method public constructor <init>()V
    .locals 0

    .prologue
    .line 12
    invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V

    return-void
.end method

.method private static reg(Ljava/lang/String;)Ljava/lang/String;
    .locals 10
    .param p0, "_username"    # Ljava/lang/String;

    .prologue
    .line 31
    invoke-virtual {p0}, Ljava/lang/String;->toCharArray()[C

    move-result-object v4

    .line 32
    .local v4, "username":[C
    array-length v1, v4

    .line 33
    .local v1, "len":I
    const-wide/16 v2, 0x0

    .line 34
    .local v2, "result":J
    const/4 v0, 0x0

    .local v0, "i":I
    :goto_0
    if-ge v0, v1, :cond_1

    .line 35
    aget-char v5, v4, v0

    const/16 v6, 0x61

    if-lt v5, v6, :cond_0

    .line 36
    aget-char v5, v4, v0

    add-int/lit8 v5, v5, -0x20

    int-to-char v5, v5

    aput-char v5, v4, v0

    .line 38
    :cond_0
    aget-char v5, v4, v0

    int-to-long v6, v5

    add-long/2addr v2, v6

    .line 34
    add-int/lit8 v0, v0, 0x1

    goto :goto_0

    .line 40
    :cond_1
    const-wide/16 v6, 0x2

    mul-long/2addr v6, v2

    const-wide/16 v8, -0x1

    and-long v2, v6, v8

    .line 41
    invoke-static {v2, v3}, Ljava/lang/Long;->toHexString(J)Ljava/lang/String;

    move-result-object v5

    invoke-virtual {v5}, Ljava/lang/String;->toUpperCase()Ljava/lang/String;

    move-result-object v5

    return-object v5
.end method


# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 7
    .param p1, "v"    # Landroid/view/View;

    .prologue
    const/4 v6, 0x0

    .line 46
    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v4

    packed-switch v4, :pswitch_data_0

    .line 84
    :goto_0
    return-void

    .line 48
    :pswitch_0
    iget-object v4, p0, Lcom/a3st/demo/MainActivity;->editUsername:Landroid/widget/EditText;

    invoke-virtual {v4}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v3

    .line 49
    .local v3, "username":Ljava/lang/String;
    iget-object v4, p0, Lcom/a3st/demo/MainActivity;->editPassword:Landroid/widget/EditText;

    invoke-virtual {v4}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v1

    .line 50
    .local v1, "password":Ljava/lang/String;
    invoke-virtual {v3}, Ljava/lang/String;->length()I

    move-result v4

    const/4 v5, 0x4

    if-lt v4, v5, :cond_0

    invoke-virtual {v3}, Ljava/lang/String;->length()I

    move-result v4

    const/16 v5, 0xc

    if-le v4, v5, :cond_1

    .line 51
    :cond_0
    const-string v4, "\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a \u6216 \u8d85\u8fc7\u6700\u5927\u957f\u5ea6"

    invoke-static {p0, v4, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v4

    invoke-virtual {v4}, Landroid/widget/Toast;->show()V

    goto :goto_0

    .line 54
    :cond_1
    invoke-static {v3}, Lcom/a3st/demo/MainActivity;->reg(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v2

    .line 55
    .local v2, "result":Ljava/lang/String;
    invoke-virtual {v2, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v4

    if-eqz v4, :cond_2

    .line 56
    new-instance v0, Landroid/app/AlertDialog$Builder;

    invoke-direct {v0, p0}, Landroid/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    .line 57
    .local v0, "msg":Landroid/app/AlertDialog$Builder;
    const-string v4, "\u4fe1\u606f\u6846:"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 58
    const-string v4, "\u6ce8\u518c\u6210\u529f!"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 59
    invoke-virtual {v0, v6}, Landroid/app/AlertDialog$Builder;->setCancelable(Z)Landroid/app/AlertDialog$Builder;

    .line 60
    const-string v4, "OK"

    new-instance v5, Lcom/a3st/demo/MainActivity$1;

    invoke-direct {v5, p0}, Lcom/a3st/demo/MainActivity$1;-><init>(Lcom/a3st/demo/MainActivity;)V

    invoke-virtual {v0, v4, v5}, Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    .line 66
    invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;->show()Landroid/app/AlertDialog;

    goto :goto_0

    .line 68
    .end local v0    # "msg":Landroid/app/AlertDialog$Builder;
    :cond_2
    new-instance v0, Landroid/app/AlertDialog$Builder;

    invoke-direct {v0, p0}, Landroid/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    .line 69
    .restart local v0    # "msg":Landroid/app/AlertDialog$Builder;
    const-string v4, "\u4fe1\u606f\u6846:"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 70
    const-string v4, "\u6ce8\u518c\u5931\u8d25!"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 71
    invoke-virtual {v0, v6}, Landroid/app/AlertDialog$Builder;->setCancelable(Z)Landroid/app/AlertDialog$Builder;

    .line 72
    const-string v4, "OK"

    new-instance v5, Lcom/a3st/demo/MainActivity$2;

    invoke-direct {v5, p0}, Lcom/a3st/demo/MainActivity$2;-><init>(Lcom/a3st/demo/MainActivity;)V

    invoke-virtual {v0, v4, v5}, Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    .line 78
    invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;->show()Landroid/app/AlertDialog;

    goto :goto_0

    .line 46
    :pswitch_data_0
    .packed-switch 0x7f070021
        :pswitch_0
    .end packed-switch
.end method

.method protected onCreate(Landroid/os/Bundle;)V
    .locals 1
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    .line 20
    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    .line 21
    const v0, 0x7f09001b

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->setContentView(I)V

    .line 23
    const v0, 0x7f070021

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/Button;

    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->btnRegister:Landroid/widget/Button;

    .line 24
    iget-object v0, p0, Lcom/a3st/demo/MainActivity;->btnRegister:Landroid/widget/Button;

    invoke-virtual {v0, p0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 26
    const v0, 0x7f07002f

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->editUsername:Landroid/widget/EditText;

    .line 27
    const v0, 0x7f07002d

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->editPassword:Landroid/widget/EditText;

    .line 28
    return-void
.end method

0x02 包名與類

先來看看smali源碼的前幾行

// 類名為public MainActivity盗尸,包名為com.a3st.demo
.class public Lcom/a3st/demo/MainActivity;
// 此類的父類為AppCompatActivity
.super Landroid/support/v7/app/AppCompatActivity;
// 文件名稱
.source "MainActivity.java"

// 此類調(diào)用的所有接口: View.OnClickListener
// #號在smali中表示注釋
# interfaces
.implements Landroid/view/View$OnClickListener;

// 此類的成員屬性有三個(gè)(Java標(biāo)準(zhǔn)說法是字段麸祷,這里注明一下)
# instance fields
.field private btnRegister:Landroid/widget/Button;

.field private editPassword:Landroid/widget/EditText;

.field private editUsername:Landroid/widget/EditText;

整理得到:

package com.a3st.demo;
public MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button btnRegister;
    private EditText editPassword;
    private EditText editUsername;
}

0x03 構(gòu)造函數(shù)

下來就是方法了选脊, 看下這段:

// 注釋direct methods表示下列的方法都在本類中杭抠,直譯就是直接方法
# direct methods
// 可能是構(gòu)造函數(shù)。本人沒寫構(gòu)造函數(shù)恳啥,這個(gè)是編譯時(shí)自動生成的偏灿,所以我也不好解釋init是啥
.method public constructor <init>()V  // @1
    // 局部變量個(gè)數(shù)0
    .locals 0

    // 代碼塊開始
    .prologue
    // 下面代碼在Java源碼中的行數(shù): 第12行
    .line 12
    // 調(diào)用函數(shù): AppCompatActivity()
    invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V // @2

    // 返回 void
    return-void
.end method
@1: .method public constructor <init>()V

.method 表明這是一個(gè)方法
public 訪問權(quán)限為公共
constructor 函數(shù)名稱
constructor<init> 看到一些文章把init當(dāng)成函數(shù)名稱
() 表明此函數(shù)無參,有參的話钝的,括號內(nèi)顯示的是參數(shù)的數(shù)據(jù)類型
V 表示返回值翁垂。 V表示void

@2: invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V

invoke-direct 調(diào)用直接函數(shù)
{p0} 對應(yīng)Landroid/support/v7/app/AppCompatActivity
從上面得出源代碼: AppCompatActivity()

整理下:
從行號與Java源碼中的對比 + 其他文章來看,本人猜測為:
該類的不帶參數(shù)缺省的構(gòu)造方法

public {
    // 可能是因?yàn)閑xtends AppCompatActivity硝桩,會自動調(diào)用父類的構(gòu)造函數(shù)
    AppCompatActivity()
}

0x04 Android入口函數(shù)

注意: 以后的smali代碼沿猜,如果之前已解釋過,后面將不會再做解釋碗脊,除非特殊說明

//  protected void onCreate(Bundle savedInstanceState)
.method protected onCreate(Landroid/os/Bundle;)V
    // 局部變量總數(shù): 1啼肩。 它的變量名默認(rèn)為v0
    .locals 1
    // 參數(shù)變量名為p1, 參數(shù)名稱為savedInstanceState
    // 參數(shù)名稱后有個(gè)類據(jù)類型,但別忘了前面有個(gè)#,說明只是個(gè)注釋
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    .line 20
    // 調(diào)用父類的onCreate
    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    .line 21
    // 給v0賦值0x7f09ff1b
    const v0, 0x7f09001b  // @3

    // 調(diào)用方法
    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->setContentView(I)V

    .line 23
    const v0, 0x7f070021

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    // 把上條指令的返回值(對象)賦值給v0
    move-result-object v0

    // 把v0的數(shù)據(jù)類型強(qiáng)制轉(zhuǎn)換成Button
    check-cast v0, Landroid/widget/Button;

    // 把v0的值賦值給p0.btnRegister疟游,也就是this.btnRegister
    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->btnRegister:Landroid/widget/Button;

    .line 24
    // 把this.btnRegister的值賦值給v0
    iget-object v0, p0, Lcom/a3st/demo/MainActivity;->btnRegister:Landroid/widget/Button;

     // btnRegister.setOnClickListener(this)
    invoke-virtual {v0, p0}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 26
    const v0, 0x7f07002f

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->editUsername:Landroid/widget/EditText;

    .line 27
    const v0, 0x7f07002d

    invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/EditText;

    iput-object v0, p0, Lcom/a3st/demo/MainActivity;->editPassword:Landroid/widget/EditText;

    .line 28
    return-void
.end method
@3 const v0, 0x7f09001b

0x7f09001b是一個(gè)資源id呼畸,當(dāng)創(chuàng)建資源文件,創(chuàng)建控件id等時(shí)會自動生成
當(dāng)編譯成apk后颁虐,通過反編譯發(fā)現(xiàn)這些資源id存放在:
項(xiàng)目/app/src/main/res/values/public.xml
或 項(xiàng)目/app/src/main/java 目錄下的R$layout.smali文件中

如內(nèi)容: <public type="layout" name="layout_main" id="0x7f09001b" />
可以看出是layout.main.xml的資源id

整理下:
讓我感到頭暈的是:
invoke-virtual{p0, v0}
invoke-virtual{v0, p0}

個(gè)人理解, 舉例:
invoke-virtual {p0, v0}, Lcom/a3st/demo/MainActivity;->setContentView(I)V

我把大括號后的Lcom/a3st/demo/MainActivity;->setContentView(I)V分成三段:

  1. Lcom/a3st/demo/MainActivity 方法所在的類
  2. setContentView(I) 方法名稱及參數(shù)
  3. V 方法的返回類型

大括號的第一個(gè)參數(shù)p0表示實(shí)例對象蛮原,同時(shí)可以從第一段中進(jìn)行驗(yàn)證
如第一個(gè)參數(shù)為p0,而第一段為本類類名另绩,則100%為本類的實(shí)例對象this
如第一個(gè)參數(shù)為其它寄存器儒陨,而第一段也不是本類類名,則100%為其它類的實(shí)例對象

從大括號的第二個(gè)參數(shù)開始分別表示第二段中的各個(gè)參數(shù)笋籽,這里只有一個(gè)int型參數(shù)
得出源碼: p0.setContentView(v0);

@Override   // 此@Override在接下來分析onCreate函數(shù)時(shí)會講到
protected void onCreate(Bundle savedInstanceState) {
    int v0;
    super.onCreate(savedInstanceState);
    setContentView(0x7f09001b); // 布局id
    
    // 小提示: 上面空了一行蹦漠,從smali中看到上一行是line21,而此行代碼在line23...少了個(gè)22,表示空行
    this.btnRegister = (Button)findViewById(0x7f070021);
    this.btnRegister.setOnClickListener(this);
    
    // 下面的代碼差不多车海,不全寫了
    /* 
        另外說下笛园,這些還原的代碼并不是從源碼中直接抄來的,而是從smali中分析得來
        如: this.btnRegister = (Button)findViewById(0x7f070021);
        在源碼中是: btnRegister = findViewById(R.id.btn_register);
        源碼中并沒有進(jìn)行強(qiáng)制轉(zhuǎn)換侍芝,是編譯時(shí)自動轉(zhuǎn)成Button的
    */
}

0x05 按鈕事件

// virtual methods表示下面的所有方法都為重載方法
# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 7
    .param p1, "v"    # Landroid/view/View;

    .prologue
    const/4 v6, 0x0

    .line 46
    // 如0x04節(jié)所說研铆,第一個(gè)參數(shù)為實(shí)例對象,所以代碼為v.getId();
    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v4

    // switch開始
    // :pswitch_data_0 這是一個(gè)標(biāo)簽州叠,用于表示從此開到標(biāo)簽處為所有case的區(qū)域 棵红,而標(biāo)簽后為case分支流程表
    // 此指令意思: 在case分支流程表中查看是否有v4的值,如有則進(jìn)入case代碼塊咧栗,沒有則退出或進(jìn)入default代碼塊
    packed-switch v4, :pswitch_data_0

    // 如果defaule代碼塊中有代碼的話逆甜,在這里會顯示
    // default代碼塊寫在此處
    .line 84
    // 所有case分支的出口
    :goto_0
    return-void

    .line 48
    // 從下面的case分支流程表看出,這里是case register按鈕id的代碼塊
    :pswitch_0
    iget-object v4, p0, Lcom/a3st/demo/MainActivity;->editUsername:Landroid/widget/EditText;

    invoke-virtual {v4}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v3

    .line 49
    // 表明變量作用域致板。local到end local之間
    // 并明確v3的變量名稱為String username
    // 也就是String username = v3交煞,但它不是出現(xiàn)在第49行,而是在上一行(48行)代碼中斟或,這是smali中需注意的一點(diǎn)
    .local v3, "username":Ljava/lang/String;
    iget-object v4, p0, Lcom/a3st/demo/MainActivity;->editPassword:Landroid/widget/EditText;

    invoke-virtual {v4}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/Object;->toString()Ljava/lang/String;

    move-result-object v1

    .line 50
    .local v1, "password":Ljava/lang/String;
    invoke-virtual {v3}, Ljava/lang/String;->length()I

    move-result v4

    const/4 v5, 0x4

    // 如果v4<v5的話素征,則跳到cond_0標(biāo)簽處
    if-lt v4, v5, :cond_0

    invoke-virtual {v3}, Ljava/lang/String;->length()I

    move-result v4

    const/16 v5, 0xc

    // 如果v4<=v5的話,則跳到cond_1標(biāo)簽處
    if-le v4, v5, :cond_1

    .line 51
    // 從utf8編碼的字符串中可以看出這是失敗信息
    :cond_0
    const-string v4, "\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a \u6216 \u8d85\u8fc7\u6700\u5927\u957f\u5ea6"

    invoke-static {p0, v4, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v4

    invoke-virtual {v4}, Landroid/widget/Toast;->show()V

    // 跳到所有case分支的出口處
    goto :goto_0

    .line 54
    :cond_1
    // 因?yàn)槭莍nvoke-static缕粹,大括號內(nèi)的參數(shù)對應(yīng)方法中的參數(shù)
    // 得出源碼為: MainActivity.reg(username);
    invoke-static {v3}, Lcom/a3st/demo/MainActivity;->reg(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v2

    .line 55
    .local v2, "result":Ljava/lang/String;
    invoke-virtual {v2, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v4

    // v4等于0時(shí)稚茅,則跳到cond_2標(biāo)簽處
    if-eqz v4, :cond_2

    // 從utf8編碼的字符串看出這里為注冊成功
    .line 56
    new-instance v0, Landroid/app/AlertDialog$Builder;

    invoke-direct {v0, p0}, Landroid/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    .line 57
    .local v0, "msg":Landroid/app/AlertDialog$Builder;
    const-string v4, "\u4fe1\u606f\u6846:"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 58
    const-string v4, "\u6ce8\u518c\u6210\u529f!"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 59
    invoke-virtual {v0, v6}, Landroid/app/AlertDialog$Builder;->setCancelable(Z)Landroid/app/AlertDialog$Builder;

    .line 60
    const-string v4, "OK"

    new-instance v5, Lcom/a3st/demo/MainActivity$1;

    invoke-direct {v5, p0}, Lcom/a3st/demo/MainActivity$1;-><init>(Lcom/a3st/demo/MainActivity;)V

    invoke-virtual {v0, v4, v5}, Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    .line 66
    invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;->show()Landroid/app/AlertDialog;

    goto :goto_0

    .line 68
    .end local v0    # "msg":Landroid/app/AlertDialog$Builder;
    :cond_2
    new-instance v0, Landroid/app/AlertDialog$Builder;

    invoke-direct {v0, p0}, Landroid/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V

    .line 69
    .restart local v0    # "msg":Landroid/app/AlertDialog$Builder;
    const-string v4, "\u4fe1\u606f\u6846:"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 70
    const-string v4, "\u6ce8\u518c\u5931\u8d25!"

    invoke-virtual {v0, v4}, Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    .line 71
    invoke-virtual {v0, v6}, Landroid/app/AlertDialog$Builder;->setCancelable(Z)Landroid/app/AlertDialog$Builder;

    .line 72
    const-string v4, "OK"

    new-instance v5, Lcom/a3st/demo/MainActivity$2;

    invoke-direct {v5, p0}, Lcom/a3st/demo/MainActivity$2;-><init>(Lcom/a3st/demo/MainActivity;)V

    invoke-virtual {v0, v4, v5}, Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    .line 78
    invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;->show()Landroid/app/AlertDialog;

    goto :goto_0

    .line 46
    :pswitch_data_0
    // case分支流程表
    // 0x7f070021 表示遞增的初始值
    .packed-switch 0x7f070021
         // pswitch_0指的是0x7f070021(遞增的初始值)
         // 0x7f070021是一個(gè)按鈕id
        :pswitch_0
    .end packed-switch
.end method
@4 switch說明

switch格式:
// 在case分支流程表中查看是否有v4的值,如有則進(jìn)入case代碼塊平斩,沒有則退出或進(jìn)入default代碼塊
packed-switch v4, :pswitch_data_0
// defaule代碼塊
......
// 所有case分支出口
:goto_0
return-void
//各個(gè)case代碼塊
......
// case分支流程表
:pswitch_data_0
// 因?yàn)槭莗acked-switch亚享,所以有個(gè)遞增的初始值(0x7F070021)
.packed-switch 0x7f070021
// 各個(gè)case代碼塊位置
:pswitch_0
:pswitch_1
:pswitch_2
// switch結(jié)束
.end packed-switch

在smali中,有packed-switch和sparse-switch二種switch語法(其它的沒見到過)

packed-switch 表示緊湊的switch绘面,它的分支流程表以一個(gè)遞增初始值開始欺税,每個(gè)case分支位置漸進(jìn)遞增侈沪。常見的就是case 1, case 2, case 3...

sparse-switch 表示稀疏的switch,它的格式為(簡單寫下晚凿,與packed-switch一樣亭罪,只是名字變了):
sparse-switch v1, :sswitch_data_0
default: code
....
// 所有case分支出口
:goto_0
return-void
// 各個(gè)case代碼塊
:sswitch_0
...
// case分支流程表
.sparse-switch
0x5ec5cc94 -> :sswitch_0
0x5ec5cc96 -> :sswitch_1
0x5ec5cc98 -> :sswitch_2
0x5ec5cc99 -> :sswitch_3
0x5ec5ccb0 -> :sswitch_4
.end sparse-switch

可以看出,在分支流程表中歼秽,沒有了遞增初始值
與之取代的是各個(gè)case位置都指定了值应役,可以看出這此值并不是有序的,所以不能用packed-switch

這里就只逆?zhèn)€switch出來吧燥筷,其它與前面幾節(jié)差不多箩祥,重點(diǎn)還是講switch語句

@Override
public void onClick(View v) {
    switch(v.getId()) {
        case 0x7f070021:
            // 代碼
            String username = editUsername.getText().toString();
            ......
            break;
    }
}

0x06 算法函數(shù)

此apk的關(guān)鍵函數(shù)

// private static String reg(_username)
.method private static reg(Ljava/lang/String;)Ljava/lang/String;
    .locals 10
    .param p0, "_username"    # Ljava/lang/String;

    .prologue
    .line 31
    // char[] username = _username.toCharArray();
    // 返回值[C表示char[]
    invoke-virtual {p0}, Ljava/lang/String;->toCharArray()[C

    move-result-object v4

    .line 32
    .local v4, "username":[C
    // 取數(shù)組長度賦值給v1
    // 看到第33行中的第一條指令現(xiàn)在大家都知道怎么逆出源碼了吧:
    // int len = username.length;
    array-length v1, v4

    .line 33
    .local v1, "len":I
    // 把0在放到v2中,如超出放到v3中
    // winde可能就是把0擴(kuò)展long型,這時(shí)v2,v3都為0
    // long result = 0
    const-wide/16 v2, 0x0

    .line 34
    .local v2, "result":J
    // i = 0
    const/4 v0, 0x0

    .local v0, "i":I
    // 循環(huán)開始
    :goto_0
    // 當(dāng) i>= len 時(shí)肆氓,跳出循環(huán)
    if-ge v0, v1, :cond_1

    .line 35
    // 讀取數(shù)組元素: v5 = username[i]
    aget-char v5, v4, v0

    const/16 v6, 0x61

    // 如果 v5<'a''袍祖,則跳到cond_0標(biāo)簽處
    if-lt v5, v6, :cond_0

    .line 36
    aget-char v5, v4, v0

    // v5 -= 0x20
    add-int/lit8 v5, v5, -0x20

    // 將整形轉(zhuǎn)換成字符型
    int-to-char v5, v5

    // 把結(jié)果保存到username[i]中
    aput-char v5, v4, v0

    .line 38
    :cond_0
    aget-char v5, v4, v0

    // 轉(zhuǎn)換成long型
    int-to-long v6, v5

    // result += username[i]
    add-long/2addr v2, v6

    .line 34
    // i++
    add-int/lit8 v0, v0, 0x1

    // 繼續(xù)循環(huán)
    goto :goto_0

    .line 40
    :cond_1
    const-wide/16 v6, 0x2

    // v6 *= result
    mul-long/2addr v6, v2

    const-wide/16 v8, -0x1

    // result = v6 & 0xFFFFFFFF
    and-long v2, v6, v8

    .line 41
    // 注意,這里不是二個(gè)參數(shù)谢揪,而是一個(gè),因?yàn)槭莑ong型
    // 前面(const-wide/16 v2, 0x0)時(shí)有詳細(xì)說過
    // Long.toHexString(result);
    invoke-static {v2, v3}, Ljava/lang/Long;->toHexString(J)Ljava/lang/String;

    move-result-object v5

    // v5.toUpperCase();
    invoke-virtual {v5}, Ljava/lang/String;->toUpperCase()Ljava/lang/String;

    move-result-object v5

    // 返回一個(gè)字符串
    return-object v5
.end method

整理下:
此節(jié)我是琢行分析的蕉陋,逆出后與源碼對比下,完美

private static String reg(_username) {
    char[] username = _username.toCharArray();  // .line31
    int len = usernema.length;                  // .line32
    long result = 0;                            // .line33
    for(int i = 0; i < len; i++) {              // .line34
        if(username[i] >= 'a') {                // .line35
            username[i] -= 0x20;                // .line36
        }                                       // .line37拨扶,相當(dāng)于一個(gè)空行
        result += username[i];                  // .line38
    }                                           // .line39
    result = (2 * result) & 0xFFFFFFFF;         // .line40
    return Long.toHexString(result).toUpperCase();  // .line41
}

0x07 修改函數(shù)

既然使用CrackMe來進(jìn)行演示凳鬓,當(dāng)然要有個(gè)CrackMe的樣子
修改方法有二種:

  1. 更改跳轉(zhuǎn)語句的流程
  2. 修改關(guān)鍵函數(shù)reg的返回值

本人用第二種方法進(jìn)行修改:
在0x05中節(jié)可能看到取password與reg函數(shù)的返回值進(jìn)行比較
本人就把0x06節(jié)中的第.line41行所有代碼刪除,并修改返回值為字符串123:

.line 41
    const string v5, "\u0031\u0032\u0033"

    return-object v5

對修改后的smali進(jìn)行編譯屈雄,修改后的結(jié)果如下


圖1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末村视,一起剝皮案震驚了整個(gè)濱河市官套,隨后出現(xiàn)的幾起案子酒奶,更是在濱河造成了極大的恐慌,老刑警劉巖奶赔,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惋嚎,死亡現(xiàn)場離奇詭異,居然都是意外死亡站刑,警方通過查閱死者的電腦和手機(jī)另伍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绞旅,“玉大人摆尝,你說我怎么就攤上這事∫虮” “怎么了堕汞?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長晃琳。 經(jīng)常有香客問我讯检,道長琐鲁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任人灼,我火速辦了婚禮围段,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘投放。我一直安慰自己奈泪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布灸芳。 她就那樣靜靜地躺著段磨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耗绿。 梳的紋絲不亂的頭發(fā)上苹支,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機(jī)與錄音误阻,去河邊找鬼债蜜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛究反,可吹牛的內(nèi)容都是我干的寻定。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼精耐,長吁一口氣:“原來是場噩夢啊……” “哼狼速!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卦停,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤向胡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后惊完,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僵芹,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年小槐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拇派。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凿跳,死狀恐怖件豌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情控嗜,我是刑警寧澤茧彤,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站躬审,受9級特大地震影響棘街,放射性物質(zhì)發(fā)生泄漏蟆盐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一遭殉、第九天 我趴在偏房一處隱蔽的房頂上張望石挂。 院中可真熱鬧,春花似錦险污、人聲如沸痹愚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拯腮。三九已至,卻和暖如春蚁飒,著一層夾襖步出監(jiān)牢的瞬間动壤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工淮逻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琼懊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓爬早,卻偏偏與公主長得像哼丈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子筛严,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容