特點
Smali彙編指令特點:
參數操作從目標到源的順序(類似x86彙編)
根據字節碼的類型和大小,添加後綴消除歧義
64位常規字節碼添加-wide
特殊字節碼添加具體類型
基於寄存器操作,不存在傳統彙編的棧操作,沒有pop,push
每個寄存器均爲32位,64位數據類型用連續兩個寄存器存儲表示
基本類型
V void (只能用於返回值類型)
Z boolean
B byte
S short
C char
I int
J long
F float
D Double
數據類型
對象類型
表示方法:L包名+類名;(L;作爲起始結束符)
eg:
java.lang.String
Ljava/lang/String;
com.example.applicationandjni.MainActivity
Lcom/example/applicationandjni/MainActivity;
數組表示,類型前面加[
int[] --> [I
Int[][] --> [[I
String[] --> Ljava/lang/String;
方法的表示形式:
Lpackage/name/ObjectName;——>methodName(III)Z 詳解如下:
Lpackage/name/ObjectName 表示類型
methodName 表示方法名
III 表示參數(這裏表示爲3個整型參數)
字段的表示形式:
Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;表示: 包名,字段名和各字段類型
寄存器
有兩種方式指定一個方法中有多少寄存器是可用的:
.registers 指令指定了方法中寄存器的總數
.locals 指令表明了方法中非參寄存器的總數,出現在方法中的第一
方法的傳參:
當一個方法被調用的時候,方法的參數被置於最後N個寄存器中;
例如,一個方法有2個參數,5個寄存器(v0~v4)
那麼,參數將置於最後2個寄存器(v3和v4)
非靜態方法中的第一個參數總是調用該方法的對象;一般都爲p0
說明:對於靜態方法除了沒有隱含的this參數外,其他都一樣
常用命令法V和P
v表示本地寄存器,p表示參數寄存器
eg:一個方法有兩個局部變量,三個參數
v0 v0第一個本地寄存器
v1 v1第二個本地寄存器
v2 p0 (this)
v3 p1 第一個參數
v4 p2 第二個參數
v5 p3 第三個參數
V命名法和P命名法的比較:使用P命名是爲了防止以後如果在方法中增加寄存器,需要對參數寄存器重新進行編號的缺點
再次強調:Long和Double類型是64位的,需要2個寄存器
例如:對於非靜態方法
LMyObject——>myMethod(IJZ)V;
有4個參數:LMyObject,int,long,bool; 需要5個寄存器來存儲參數;
P0 this
P1 I (int)
P2,P3 J (long)不能分開用,因爲JAVA解釋執行,沒有這種
P4 Z(bool)
smali文件
頭部
.class public Lcom/example/applicationandjni/MyApplication;
.super Landroid/app/Application;
.source "MyApplication.java"
.field
成員變量(靜態,非靜態)
.method
成員方法
其他
通過讀dex確定的smali文件結構。
字段聲明表示
public static aa:F
作用域 變量名:變量類型
方法聲明表示:
public pri_method(ILjava/lang/String;)Ljava/lang/String;
作用域 方法名(參數類型)返回值類型
public 、protected聲明
invoke-virtual(因爲繼承,有重載)
private聲明
invoke-direct
Static聲明
invoke-static
調用父類方法
invoke-super
所有smali彙編調用的方法沒有默認返回值比如x86/64的eaxrax,必須要調用一個move-result-object/其他類型 vx
Demo
下面分析一個彙編demo,先變成class,再變成dex,將dex,用baksmali解包
像那些R$的都是一些資源文件。跟資源文件耦合。
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.registers 6
.param p1, "savedInstanceState" # Landroid/os/Bundle;p0傳的是this
.prologue
.line 51
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 52
const/high16 v0, 0x7f030000
invoke-virtual {p0, v0}, Lcom/example/testtype/MainActivity;->setContentView(I)V
.line 54
const/4 v0, 0x1
const-string v1, "1"
invoke-virtual {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pub_method(ILjava/lang/String;)V
.line 55
const/4 v0, 0x2
const-string v1, "2"
invoke-virtual {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pro_method(ILjava/lang/String;)I
.line 56
const/4 v0, 0x3
const-string v1, "3"
invoke-direct {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pri_method(ILjava/lang/String;)Ljava/lang/String;
.line 58
const/4 v0, 0x4
const-string v1, "4"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pub_static_method(ILjava/lang/String;)V
.line 59
const/4 v0, 0x5
const-string v1, "5"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pro_static_method(ILjava/lang/String;)I
.line 60
const/4 v0, 0x6
const-string v1, "6"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pri_static_method(ILjava/lang/String;)Ljava/lang/String;
.line 62
const-wide/16 v0, 0xa#long
iput-wide v0, p0, Lcom/example/testtype/MainActivity;->a:J #看起來用了v0,實際上是v0v1,因爲是long
.line 63
const/16 v0, 0x14
iput v0, p0, Lcom/example/testtype/MainActivity;->b:I
.line 64
const/high16 v0, 0x41f00000 # 30.0f
sput v0, Lcom/example/testtype/MainActivity;->aa:F
.line 65
const-wide/high16 v0, 0x4044000000000000L # 40.0
sput-wide v0, Lcom/example/testtype/MainActivity;->bb:D
.line 67
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;#java特性,字符串不可變,將2個字符串相加先newstringbuild,然後拼接起來,然後tostring
iget-wide v2, p0, Lcom/example/testtype/MainActivity;->a:J
invoke-static {v2, v3}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;#java/lang/String類的valueOf方法傳入一個Jlong型,返回字符串型。
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V#兩個參數第一個參數相當於this是個對象,第二個參數是含參的構造函數,就是new一個對象,先new對象,上面的函數,再調用他的構造函數
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;//掉stringbuilder轉成String
move-result-object v1#生成strign給v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 68
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
iget v2, p0, Lcom/example/testtype/MainActivity;->b:I
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 69
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
sget v2, Lcom/example/testtype/MainActivity;->aa:F
invoke-static {v2}, Ljava/lang/String;->valueOf(F)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 70
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
sget-wide v2, Lcom/example/testtype/MainActivity;->bb:D
invoke-static {v2, v3}, Ljava/lang/String;->valueOf(D)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 71
return-void
.end method
.method protected pro_method(ILjava/lang/String;)I
.registers 7
.param p1, "n" # I
.param p2, "tag" # Ljava/lang/String;
.prologue
.line 21
mul-int/lit8 v0, p1, 0x2
.line 22
.local v0, "m":I
const-string v1, "MF"
new-instance v2, Ljava/lang/StringBuilder;
invoke-static {p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v3
invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)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 v2
invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 23
return v0
.end method
.method public pub_method(ILjava/lang/String;)V
.registers 7
.param p1, "n" # I
.param p2, "tag" # Ljava/lang/String;
.prologue
.line 16
mul-int/lit8 v0, p1, 0x2
.line 17
.local v0, "m":I
const-string v1, "MF"
new-instance v2, Ljava/lang/StringBuilder;
invoke-static {p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v3
invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)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 v2
invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 18
return-void
.end method
第二個pro_method逆向寫僞代碼如下
package com.example.testtype
class Mainactivity extends Activity{
protected int pro_method(int n,String tag)
{
int v0=n*0x2;
string v1="MF";
String v3=String.valueOf(tag);
SrtringBuilder v2=new StringBuilder(v3);
v3=":";
v2=v2.append(v3);
v2=v2.append.(v0);
String v2=v2.toString();
log.i(v1,v2);
return v0;
//其實這些代碼再java裏就是
int m=n*0x02;
Log.i("MF",tag+":"+m);
return m;
}
}
之所以要逆smali代碼,因爲是如果是大數組,jeb反編譯回是空,不是正常的。只能看smali彙編。