smali 語言語法

Androidkiller 能夠反編譯Android的apk,生成一種.smali代碼。(這理解好像不對)java

網上找了一篇smali的語法手冊,能夠方便查找,文章名《Smali文件語法參考》android

手冊地址:http://blog.csdn.net/litton_van/article/details/7843490數組

網上有一篇smali的語法講解(java與smali對照講解,推薦+贊),地址:http://blog.csdn.net/hp910315/article/details/51823236函數

下面是網上找的一篇關於smali的語法的簡單介紹:工具

文章來源:http://www.brogrammer.cn/android/smali/ui

1.smali

apk文件經過apktool反編譯出來的都有一個smali文件夾,裏面都是以.smali結尾的文件。
smali語言是Davlik的寄存器語言,語法上和彙編語言類似,Dalvik VM與JVM的最大的區別之一就是Dalvik VM是基於寄存器的。基於寄存器的意思是,在smali裏的全部操做都必須通過寄存器來進行。this

2.基本數據類型

B—byte
C—char
D—double
F—float
I—int
S—short
V—void
J—long
Z—booleanspa

注意J、Z兩個不是對應類型的首字母;
在dalvik字節碼中,寄存器都是32位的,可以支持任何類型,Long和Double類型是64位的,須要2個寄存器;
V 只能用於返回值類型;.net

3.數組和對象是引用類型

數組的表示方式是在基本類型前加上前中括號「[」,例如int數組和float數組分別表示爲:[I、[F;
對象類型以L做爲開頭來表示,格式是Lpackage/ClassName;(用分號表示對象結束是必須的),示例:
String對象在smali中爲:Ljava/lang/String;
Class1對象的一個boolean成員表示爲:Lcom/disney/Class1;->isRunning:Z
Class1對象的一個String對象成員表示爲:Lcom/disney/Class1;->name:Ljava/lang/String;
能夠總結爲格式爲對象類型->成員名:成員類型,->表示所屬關係,類型尾部必須包括一個分號。
內部類表示爲:Lpackage/ClassName$innerObjectName;,也就是在內部類前加「$」符號對象

4.函數

格式:Func-Name (Para-Type1Para-Type2Para-Type3…)Return-Type

返回類型在最後,參數之間沒有任何分隔符,示例:

void fun()
fun()V

boolean fun(int, int, int)
fun(III)Z

String fun(boolean, int[], int[], String, long)
fun(Z[I[ILjava/lang/String;J)Ljava/lang/String;

5.語法

#標記,構造函數的返回類型爲V,名字爲<init>

# static fields        定義靜態變量的標記
# instance fields      定義實例變量的標記
# direct methods       定義靜態方法的標記??
# virtual methods      定義非靜態方法的標記??
 .class public Lcom/disney/WMW/WMWActivity;
 .super Lcom/disney/common/BaseActivity;
 .source "WMWActivity.java"
 .implements Lcom/burstly/lib/ui/IBurstlyAdListener;

上面這幾行代碼表示類名,父類名,源文件名,實現了接口。

.annotation
 內部類
.end annotation

6.局部變量

本地寄存器(local register,非參寄存器)用v開頭數字結尾的符號來表示,如v0、v一、v二、…,
參數寄存器(parameter register)用p開頭數字結尾的符號來表示,如p0、p一、p二、…,
.registers 用來標明方法中寄存器的總數,即參數寄存器和非參寄存器的總數。
.local 0,標明在這個函數中最少要用到的本地寄存器的個數,出如今方法中的第一行。在這裏,因爲只須要調用一個父類的onDestroy()處理,因此只須要用到p0,因此使用到的本地寄存器數爲0,在植入代碼後不要忘記可能要修改.local的值。
如 .local 4,則可使用的寄存器是v0-v3。
當一個方法被調用的時候,方法的參數被置於最後N個寄存器中。
在實例函數中,p0代指「this」,p1表示函數的第一個參數,p2表明函數中的第二個參數…,
在static函數中,p1表示函數的第一個參數,p2表明函數中的第二個參數…,由於Java的static方法中沒有this方法。
示例:

const/4 v0, 0x0
iput-boolean v0, p0, Lcom/disney/Class1;->isRunning:Z

上面第一句中把值0x0存到v0本地寄存器中,
第二句用iput-boolean指令把v0中的值存放到this.isRunning這個成員變量中,即this.isRunning = false; 由於在實例函數中p0表明的是「this」,Lcom/disney/Class1;是類名,對應實例是p0。

7.成員變量和指令

# static fields
.field private static final PREFS_INSTALLATION_ID java/lang/String; = "installationId"
# instance fields
.field private _activityPackageName java/lang/String;

獲取和操做靜態成員變量和實例成員變量有不一樣的指令。
讀取的指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget-object等,
賦值的指令有:iput、sput、iput-boolean、sput-boolean、iput-object、sput-object等。
帶「-object」表示操做的成員變量是對象類型,沒有「-object」後綴的表示操做的成員變量對象是基本數據類型,特別地boolean類型則使用帶「-boolean」的指令操做。

獲取static fields的指令示例:

sget-object v0, Lcom/disney/Class1;->PREFS_INSTALLATION_ID:Ljava/lang/String;

上句中sget-object指令把PREFS_INSTALLATION_ID這個String成員變量獲取並放到v0寄存器中。

獲取instance fields的指令與static fields的相似,須要指明對象所屬的實例。示例:

iget-object v0, p0, Lcom/disney/Class1;->_view:Lcom/disney/Class2;

上句iget-object指令比sget-object多了一個參數p0,就是該變量所在類的實例,在這裏就是p0即「this」。

put指令的使用和get指令是統一的,示例:

const/4 v3, 0x0
sput-object v3, Lcom/disney/Class1;->globalIapHandler:Lcom/disney/config/GlobalPurchaseHandler;

上句至關於Class1.globalIapHandler = null;

8.函數調用

smali中的函數調用也分爲direct和virtual兩種類型,direct method就是private函數,public和protected函數都屬於virtual method。在調用函數時,有invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface等幾種不一樣的指令。還有invoke-XXX/range 指令的,這是參數多於4個的時候調用的指令,比較少見。

invoke-static:就是調用static函數的,示例:

invoke-static {}, Lcom/disney/Class1;->fun()Z

上句invoke-static後面有一對大括號「{}」,內部是調用該方法的實例和參數列表,因爲這是static方法也不須要參數,因此{}內爲空。

invoke-super:調用父類方法,在onCreate、onDestroy等方法都能看到。
invoke-direct:調用private函數,示例:

invoke-direct {p0}, Lcom/disney/Class1;->getGlobalIapHandler()Lcom/disney/config/GlobalPurchaseHandler;

上句即this->getGlobalIapHandler(),函數GlobalPurchaseHandler getGlobalIapHandler()是定義在Class1中的一個private函數。

invoke-virtual:用於調用protected或public函數,示例:

sget-object v0, Lcom/disney/Class1;->shareHandler:Landroid/os/Handler;
invoke-virtual {v0, v3}, Landroid/os/Handler;->removeCallbacksAndMessages(Ljava/lang/Object;)V

上句v0是shareHandler android/os/Handler,v3是傳遞給removeCallbackAndMessage方法的Ljava/lang/Object參數。

9.獲取函數調用結果

在smali裏調用函數和返回函數結果須要分開來完成,在調用的函數返回非void後,用move-result(返回基本數據類型)和move-result-object(返回對象)指令獲取返回結果。

示例:

const/4 v2, 0x0
invoke-virtual {p0, v2}, Lcom/disney/Class1;->getPreferences(I)Landroid/content/SharedPreferences;
move-result-object v1

上句v1保存的就是調用this.getPreferences(int)方法返回的SharedPreferences實例。

10.函數體

.method   和  .end method之間。

示例:

.method protected onDestroy()V
.locals 0

.prologue
.line 277
invoke-super {p0}, Lcom/disney/common/BaseActivity;->onDestroy()V

.line 279
return-void
.end method

上段是onDestroy()函數。
.line 277,標註了該代碼在原Java文件中的行數,它不是必須的,去掉沒有編譯問題。它在出錯時能夠指出錯誤位置,jd-gui工具便是經過分析這些信息將smali代碼還原成Java代碼的。

11.條件語法

if-eq p1, v0, :cond_8 
    :cond_8
    invoke-direct {p0}, Lcom/paul/test/a;->d()V

上段表示若是p1和v0相等,則執行cond_8的流程:調用com.paul.test.a的d()方法

if-ne p1, v0, :cond_b 
    :cond_b
    const/4 v0, 0x0
    invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
    invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
    move-result v0

上段表示不相等則執行cond_b的流程。

相關文章
相關標籤/搜索