smali語法小結
smali語言是Davlik的寄存器語言,語法上和匯編語言相似,Dalvik VM與JVM的最大的區別之一就是Dalvik VM是基於寄存器的。基於寄存器的意思是,在smali裏的所有操作都必須經過寄存器來進行。Link
Smali-數據類型
Davlik字節碼中,寄存器都是32位的,能夠支持任何類型,64位類型(Long/Double)用2個寄存器表示。Dalvik字節碼有兩種類型:原始類型;引用類型(包括對象和數組)@link。
M1.基本數據類型
V void Z boolean B byte S short C char I int J long(64位) F float D double(64位) J、Z兩個不是對應類型的首字母
基本數據類型示例: .method public final pubFinalMethod()V //返回值 .field private boType:Z // boolean .field private byteType:B // byte .field private shortType:S // short .field private charType:C // char .field private intType:I // int .field private longType:J //long .field private floatType:F //float .field private doubleType:D // double
M2.對象類型
Lpackage/name/ObjectName; 相當於java中的package.name.ObjectName; L 表示這是一個對象類型
,package/name 該對象所在的包 ,ObjectName 對象名稱 , 標識對象名稱的結束。
.method private priParamsOne(Ljava/lang/String;)V // 對象參數類型 new-instance v1, Ljava/lang/StringBuilder; // 對象實例化 invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V //對象調用 invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; // 返回值類型
M3.數組類型
[I :表示一個整形的一維數組,相當於java的int[];
對於多維數組,只要增加[ 就行了,[[I = int[][];註:每一維最多255個;
對象數組的表示形式:
[Ljava/lang/String 表示一個String的對象數組;
.method private varargs priParamsUncertain(Ljava/lang/String;[Ljava/lang/String;)V
Smali-方法
smali方法結構 link #direct methods .method <訪問權限> [修飾關鍵字] <方法原型> <.registers> [.param] [.prologue] [.line] <.local> <代碼體> .end method #direct methods是註釋,是baksmali添加的,訪問權限和修飾關鍵字跟字段是一樣的。 方法原型描述了方法的名稱、參數與返回值。 .registers 指令指定了方法中寄存器的總數,這個數量是參數和本地變量總和。 .param表明了方法的參數,每個.param指令表示一個參數,方法使用了幾個參數就有幾個.parameter指令。 .prologue指定了代碼的開始處,混淆過的代碼可能去掉了該指令。 .line指明了該處代碼在源代碼中的行號,同樣,混淆後的代碼可能去掉了行號。 .local 使用這個指定表明方法中非參寄存器 s1.方法聲明 private void priParamsUncertain(String str0, String... params) // java .method private varargs priParamsUncertain(Ljava/lang/String;[Ljava/lang/String;)V // smali 格式:.method + 訪問修飾符 + 方法名(參數表) + 返回值類型 s2.調用結構 (StringBuilder)v1.append(v2); // JAVA invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; invoke-virtual調用方法聲明 {v1, v2}數據寄存器 對象 -> 方法名(參數類型)返回值 invoke-virtual 非靜態方法調用 invoke-static 靜態方法調用 invoke-direct 構造方法調用? invoke-super 調用父類方法 invoke-interface 調用接口 s3.寄存器 本地寄存器(local register,非參寄存器)用v開頭數字結尾的符號來表示,如v0、v1、v2、…, 參數寄存器(parameter register)用p開頭數字結尾的符號來表示,如p0、p1、p2、…, .registers 用來標明方法中寄存器的總數,即參數寄存器和非參寄存器的總數。 .local 0,標明在這個函數中最少要用到的本地寄存器的個數,出現在方法中的第一行。 如 .local 4,則可以使用的寄存器是v0-v3。 當一個方法被調用的時候,方法的參數被置於最後N個寄存器中。 在實例函數中,p0代指“this”,p1表示函數的第一個參數,p2代表函數中的第二個參數…, 在static函數中,p1表示函數的第一個參數,p2代表函數中的第二個參數…,因為Java的static方法中沒有this方法。 s4.其他 .method // 方法的開始 .end method // 方法結束 move-result(返回基本數據類型)和move-result-object(返回對象) 獲取和操作靜態成員變量和實例成員變量有不同的指令。 讀取的指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget-object等, 賦值的指令有:iput、sput、iput-boolean、sput-boolean、iput-object、sput-object等。 帶“-object”表示操作的成員變量是對象類型,沒有“-object”後綴的表示操作的成員變量對象是基本數據類型,特別地boolean類型則使用帶“-boolean”的指令操作。
Smali與java聲明方法參考 .method private priParamsVoid()V // smali private void priParamsVoid() // java .method private varargs priParamsUncertain(Ljava/lang/String;[Ljava/lang/String;)V private void priParamsUncertain(String str0, String... params) .method private priParamsType(ILjava/lang/Long;Ljava/lang/String;Ljava/lang/Object;)V private void priParamsType(int var, Long varL, String str, Object object) .method private priParamsInf(Lcom/simple/dec/basic/basic/basic1/ClazzInterface;)V private void priParamsInf(ClazzInterface clazzInterface) smali與java方法聲明結構非常相似
Smali-對象
頭文件 .class <訪問權限> [關鍵修飾字] <類名>; .super <父類名>; .source <源文件名> .implements <實現接口> 構造方法 # direct methods .method static constructor <clinit>()V // 初始化靜態變量構造方法 .locals 1 .prologue .line 10 const/4 v0, 0x0 sput-boolean v0, Lcom/simple/dec/basic/basic/basic2/StateTry;->isLoop:Z return-void .end method .method public constructor <init>()V // 默認構造方法 .locals 0 .prologue .line 8 invoke-direct {p0}, Ljava/lang/Object;-><init>()V return-void .end method super-implements .super Lcom/disney/common/BaseActivity; .implements Lcom/burstly/lib/ui/IBurstlyAdListener; 內部類 # annotations .annotation system Ldalvik/annotation/MemberClasses; value = { Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerInterface;, Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerAbsClazz;, Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerPubStaticClazz;, Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerPubClazz;, Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerDefClazz;, Lcom/simple/dec/basic/basic/basic1/ClazzJava$InnerPriClazz; } .end annotation
Smali-語句
M1.if判斷語句
if判斷一共有12條指令:
if-eq vA, VB, cond_** 如果vA等於vB則跳轉到cond_**。相當於if (vA==vB) if-ne vA, VB, cond_** 如果vA不等於vB則跳轉到cond_**。相當於if (vA!=vB) if-lt vA, VB, cond_** 如果vA小於vB則跳轉到cond_**。相當於if (vA<vB) if-le vA, VB, cond_** 如果vA小於等於vB則跳轉到cond_**。相當於if (vA<=vB) if-gt vA, VB, cond_** 如果vA大於vB則跳轉到cond_**。相當於if (vA>vB) if-ge vA, VB, cond_** 如果vA大於等於vB則跳轉到cond_**。相當於if (vA>=vB) if-eqz vA, :cond_** 如果vA等於0則跳轉到:cond_** 相當於if (VA==0) if-nez vA, :cond_** 如果vA不等於0則跳轉到:cond_**相當於if (VA!=0) if-ltz vA, :cond_** 如果vA小於0則跳轉到:cond_**相當於if (VA<0) if-lez vA, :cond_** 如果vA小於等於0則跳轉到:cond_**相當於if (VA<=0) if-gtz vA, :cond_** 如果vA大於0則跳轉到:cond_**相當於if (VA>0) if-gez vA, :cond_** 如果vA大於等於0則跳轉到:cond_**相當於if (VA>=0)
M2.switch分支語句
Switch語句的smali文件解釋結構
整形順序結構switch(int) :pswitch_data_0 .packed-switch 0x0 :pswitch_0 :pswitch_1 .end packed-switch 整形非順序結構switch(int) :sswitch_data_0 .sparse-switch 0x0 -> :sswitch_0 0x1 -> :sswitch_1 0xa -> :sswitch_2 .end sparse-switch switch(String) :pswitch_data_0 .packed-switch 0x41 :pswitch_0 :pswitch_1 .end packed-switch :pswitch_data_1 .packed-switch 0x0 :pswitch_2 :pswitch_3 .end packed-switch
M3.循環語句
常用的循環結構有:叠代器循環,for/foreach循環,while/do-while循環。
# virtual methods .method public statementFor()Z .locals 4 .prologue .line 17 const/4 v0, 0x0 .local v0, "a":I :goto_0 const/16 v1, 0x64 if-ge v0, v1, :cond_0 // 結束循環條件 .line 18 const-string v1, "StateLoop" new-instance v2, Ljava/lang/StringBuilder; invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V const-string v3, "" invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I .line 17 add-int/lit8 v0, v0, 0x1 goto :goto_0 // 通過goto實現循環 .line 20 :cond_0 const/4 v1, 0x0 return v1 .end method for/foreach循環,while/do-while 幾種循環結構smali語法均通過goto實現,內部嵌入if-xxx 實現跳出循環。
M4.try/catch語句
# virtual methods .method public statementTry()Z .locals 4 .prologue .line 14 const-wide/16 v2, 0x3e8 :try_start_0 invoke-static {v2, v3}, Ljava/lang/Thread;->sleep(J)V :try_end_0 .catch Ljava/lang/InterruptedException; {:try_start_0 .. :try_end_0} :catch_0 .line 18 :goto_0 const/4 v1, 0x1 return v1 .line 15 :catch_0 move-exception v0 .line 16 .local v0, "e":Ljava/lang/InterruptedException; invoke-virtual {v0}, Ljava/lang/InterruptedException;->printStackTrace()V goto :goto_0 .end method
工具:
JesusFreke/smali dex/smali
Dalvik opcodes
參考:
Smali語法詳解
smali 語言語法 小菜的愛
[求助]關於SMALI語法最早介紹
靜態分析Android程序——smali文件解析 CSDN
Smali和逆向分析推酷
V void Z boolean B byte S short C char I int J long(64位) F float D double(64位) |
smali語法小結