Android工程師,如何簡單高效的學會smali語法

香脆的大雞排發表於2017-10-15

注意:本篇是一個以方法論為導向的文章。

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的知識還有很多本文並未詳細闡述,如暫存器、型別(原始型別、物件型別)、陣列方法的表示形式。如讀者還需要進一步深入挖。可以參考官方文件。裡面有詳細的解釋,已翻譯成中文版了。
source.android.com/devices/tec…


如何下次找到我?

本文發自掘金&簡書-香脆的大雞排。原創文章,未授權禁止轉載。

相關文章