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>
從中可以看出:
- 只有一個(gè)主活動.MainActivity
- 包名為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分成三段:
- Lcom/a3st/demo/MainActivity 方法所在的類
- setContentView(I) 方法名稱及參數(shù)
- 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的樣子
修改方法有二種:
- 更改跳轉(zhuǎn)語句的流程
- 修改關(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é)果如下