smali語言還是相對純機器碼來說,比較容易理解的
--但最好是結合工具一起學--
--還可以參考其他的整理文章--
先來一個最簡單的模型類
對應的smali
(表格只是簡單做一個映射關系的整理)
java | smali | description |
---|---|---|
package | .class | 包名 |
extends | .super | 父類名 |
class | .source | 類名 |
params | .field | 定義字段 |
int | I | int類型 |
Integer | Ljava/lang/Integer | Integer類型 |
引用類型 | Lxx/xx/xx | 該引用類型的完整包名 |
boolean | Z | 布爾值 |
byte | B | 字節 |
short | S | 短整型 |
char | C | 字符 |
long | J | 長整型 |
float | F | 浮點數 |
double | D | 浮點數 |
void | V | 無 |
數組類型 | [ | 數組 |
function | .method | 定義方法 |
constructor | 構造器方法 | |
.prologue | 開始了 | |
.registers | 申請寄存器的個數,貌似不用關心這個 | |
.line x | 對應源java文件行數 |
func1括號里有Lxx/xx/xx說明有形參,形參類型是String,也有返回值,返回值類型也是String
.param 指名 形參名 value
.prologue以下開始正式的代碼邏輯
.line 38 ,源碼38行的代碼
return-object 返回該對象的引用,其實就是把p0里的值返回來。
func2無形參,返回值類型String
const-string 聲明了一個String 類型的變量 ,值是 "abcdefg"
.local 說是 指定了使用的局部變量的個數,我這里簡單的認為,就是把v0給了一個局部變量 func2string
沒想到這么長。
這里有點繞,根據
當vB為0的時候
則直接翻譯smali為
L93-int類型形參num,放到寄存器p1
L96~L97-源碼47行,如果p1的值小于等于0,跳到cond_3
L99~L102-源碼49行,結束local寄存器p1,跳到goto_2,
返回p1的值
L104~L109-源碼48行,重開寄存器p1,cond_3 入口
如果p1的值 不等于0,跳到cond_7
否則(也就是p1等于0)把 0x0這個值給p1,然后跳到goto_2
L113~L115 -也就是源碼49行,cond_7入口,
neg-int對第一個p1進行求補,然后把值給第二個p1
L117~L118 -goto_2入口,end_method
是不是感覺和java代碼func3看起來不一樣?
我給自己的解釋是類似java內存模型發生了重排序的優化,也不知道對不對,有大神知道的話評論區求解答。
不過回過頭來再看這個smali,
順序上雖然和源碼順序并不一致,但是按照直接翻譯的意思去寫java代碼
if( p1 <= 0){
if(p1 != 0)return -p1
else return 0
} else return p1
結果是一樣的。
再來一個
有了func3的翻譯經驗
func4就很好翻譯了
if-eqz p1,也就是形參num p1等于0的話,直接到cond_3,賦值0,最后返回。
其余的直接返回p1
if(p1 == 0)return 0
else return p1
這個優化感覺更能說服自己了,==操作比!=操作更簡單
來一個switch跳轉
L145~L146-源碼59行,拿p1做switch(packed-switch關鍵字)偏移區pswitch_data_a
要看到底部
L174~L179-實際上只有兩個case需要做判斷 pswitch-6和pswitch-8(也就是兩個偏移區)
L156~L163-pswitch_6,把0x0給v0,跳到goto_5
L165~L172-pswitch_8,把0x1給v0,跳到goto_5
L151~L154-goto_5入口把int型的本地(.local關鍵字)參數result指向寄存器v0,返回v0
其余的 把0x29a給v0
int result;
switch(p1){
case pswitch_6:
result = 0;
break;
case pswitch_8:
result = 1;
break;
default:
result = 0x29a;
break;
}
return result;
相當于幫我優化了case -1,因為case -1和default都是同樣的處理方法
常用的加log打印信息的方法
那加入在有些情況下,調用Log.d,該類并沒有引入
android.util.Log包怎么辦?
放一個四哥的自定義代碼添加方案
以上筆記,僅供參考。