注意:本篇是一個以方法論為導向的文章。
Q1:Smali是什么。
Smali是一種寬松式的Jasmin/dedexer語法.
簡單來說就是我們用java寫的代碼編譯成class打包成dex文件后使用baksmali程序逆向回來的一種語法。
Q2:為什么要學習Smali。
首先,提到smali就不得不說逆向。早在還沒有android之前,各大平臺和語言上就有對應的逆向一說。那么到目前為止,逆向一個apk通常是安全工程師(逆向工程師)和做破解等惡意分子因為某些利益在做(apk二次打包插入廣告、破解收費應用、惡意代碼植入、剽竊api等)。
技術是一把雙刃劍,怎么用在人。而不在技術本身上。那么我們說為什么應用層開發者也要學smali呢?我能想到以下幾點供參考。
1.借鑒 當我們發現其他應用有一個很牛逼功能,而我們想不明白如何實現的時候。拿不到源碼可以選擇逆向。
2.安全 我們寫的app需要考慮安全性,但是我們可能只知道混淆和第三方加固,需要明白別人是怎么破解我們的應用。
3.適配 當我們發現api在某些手機上被棄用,而其他應用或系統應用又能實現該功能的時候。關于這點我之前寫過一篇逆向小米做適配的文章。
喂,差不多夠了吧?還不能打動你學嗎?給你升職加薪怎么樣? :)
噗,壞蛋!!!,我學 我學,還不行嗎?
Q3:Smali難不難?
不難。也許你很早之前看過一些文章。或者也常用一些工具去打開反編譯后的代碼。看著一團麻的指令和一些你從未見過的關鍵字、代碼格式風格,賴不住性子就潦草的關掉了。但實際上是你沒有找對方法來學習它。
Q4:怎么學
我一向的風格都是不愛把知識生拉硬套的往腦子里塞,我更加習慣從實踐中去分析,而后反過來做總結。現在給大家推薦一款好用的Smali學習工具插件。我們打開AndroidStudio找到插件安裝的位置。如下圖
打開 Browse Repositories,輸入java2smali安裝重啟即可。
github地址在這里:intellij-java2smali
這個步驟以后,我們就可以愉快的將任何java代碼在androidStudio中直接轉換成smali來學習里。步驟如下。
1.編寫一個最簡單的java文件。比如下面這樣的。
然后我們點擊Build->Compile to smali
稍等幾秒鐘后就會得到smali文件。
接下來我們就可以對照著java代碼來逐行分析這個smali文件。如果是第一次看我們可能會被一些沒見過關鍵字干擾到。其實這里有個很簡單的辦法。注意.line關鍵字就是用來描述當前代碼在java源文件中的行數。然后你可以通過對照兩組代碼的方法進行反推。這樣就可以很輕松的學會看smali文件。
好下面是一個示例代碼,供參考。
示例代碼:
原java代碼
public AA methodAReturn(AA mAA, AA sAA) {
return mAA;
}
AA aa= new AA();
//調用
methodAReturn(aa, aa);
Smali代碼
.method public methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
.registers 3
.param p1, "mAA" # Lcom/bolex/AA;
.param p2, "sAA" # Lcom/bolex/AA;
.prologue
.line 34
return-object p1
.end method
.line 21
new-instance v0, Lcom/bolex/AA;
invoke-direct {v0}, Lcom/bolex/AA;-><init>()V
.line 22
invoke-virtual {p0, v0, v0}, Lcom/bolex/seamAct;->methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
.line
.line 34
表示當前代碼在源java文件中的行數。
method
.method public methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
表示來自公共方法methodAReturn返回值是一個對象com.bolex.AA
registers
.registers 3
表示該函數上需要使用3個寄存器
param
.param p1, "mAA" # Lcom/bolex/AA;
.param p2, "sAA" # Lcom/bolex/AA;
表示接收兩個入參都是AA對象,并標記寄存器p1和p2
.prologue
.prologue
表示函數內執行的起始標記。直譯為開場白的意思。
.line
.line 34
表示在源代碼中的第34行。
return-object
return-object p1
表示 返回寄存器上p1對象
.end method
.end method
表示函數結束標記
new-instance
new-instance v0, Lcom/bolex/AA;
創建一個AA對象
invoke-direct
invoke-direct {v0}, Lcom/bolex/AA;-><init>()V
表示使用無參構造方法直接調用
invoke-virtual
invoke-virtual {p0, v0, v0}, Lcom/bolex/seamAct;->methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
表示為虛擬方法
就是這個樣子的,有沒有很簡單呢?
以上只舉例了部分關鍵字,更多的關鍵字可以自行依賴兩組文件反推。其實有時候更加講究的是一個方法。我覺得這個方法就挺不錯的,所以就分享給大家咯,咱也不需要刻意去背下來。熟能生巧,玩多了豈能不是老司機?
關于smali的知識還有很多本文并未詳細闡述,如寄存器、類型(原始類型、對象類型)、數組方法的表示形式。如讀者還需要進一步深入挖。可以參考官方文檔。里面有詳細的解釋,已翻譯成中文版了。
https://source.android.com/devices/tech/dalvik/dex-format
如何下次找到我?
- 關注我的簡書
- 本篇同步Github倉庫:https://github.com/BolexLiu/DevNote (可以關注)
本文首發香脆的大雞排 原創文章轉載請先取得聯系。