用Smali寫一個加法程序

最近對移動端產生了很濃厚的興趣,那就開始學習吧!因爲還有工作任務,忙裏偷閒把豐生強的前3章認真讀了一遍。小結內容是說必須熟練掌握這一部分的內容,可通過手動編寫Dalvik彙編代碼來熟悉一下指令,爲後面的分析夯實好基礎。

書上的是一個顯示HelloWorld的例子,爲了練習好基礎。準備要用Dalvik彙編寫一個簡單的程序,功能如下:


按照書上的,把框架搭好如下:

.class public Ltest;
.super Ljava/lang/Object;
.method public constructor <init>()V


#寄存器數量待定

    .registers 1 
.parameter
.prologue
    return-void
.end method


思路:由於要傳2個參數進去計算,並不是像書上的例子一樣,只是打印出一行字,所以要弄清楚參數是如何傳進去的。寫一個簡單的程序反編譯看看。程序代碼:

public class test2 {
public static void main(String[] args) {
String a = args[0];       
}
}

編譯成smali代碼先看看參數是怎麼樣傳進去的,smali代碼如下:

.class public Ltest2;
.super Ljava/lang/Object;
.source "test2.java"
# direct methods
.method public constructor <init>()V
    .registers 1
    .prologue
    .line 1
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method
.method public static main([Ljava/lang/String;)V
    .registers 2
    .prologue
    .line 4
    const/4 v0, 0x0
    aget-object v0, p0, v0
 
    .line 6
    return-void
.end method
發現除了main函數外還有一個direct method:
.method public constructor <init>()V
表示該類的不帶參數缺省的構造方法
看來這就是傳參的關鍵。
 const/4 v0, 0x0
 aget-object v0, p0, v0
Main函數中用這2句的接受傳進來的值。
所以應該先添加這個構造方法:
# direct methods
.method public constructor <init>()V
    .registers 1
    .prologue
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method
接着寫代碼如下:
#V0 V1 清零
 const/4 v0, 0x0
 const/4 v1, 0x0
#接收傳進來的2個參數
 aget-object v0, p0, v0
     aget-object v1, p0, v1
#把第一個參數轉化成int類型 給vo
    invoke-static {v0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
    move-result v0
#把第二個參數轉化成int類型 給v1
    invoke-static {v1}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
    move-result v1
#兩個參數相加  值存 給vo
    add-int/2addr v0, v1
#把vo中的結果轉化成String類型  再給v0
    invoke-static {v0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
    move-result-object v0
#構造一個String類型對象的新實例 把值賦給v2
    new-instance v2, Ljava/lang/StringBuilder;
#調用實例的直接方法
    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
#定義一個字符串常量
    const-string v3, "The Sum is :"
#調用實例方法,把v3與v2裏的字符串相加再給v2 invoke-virtual{v2,v3},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
#調用實例方法,把v0與v2裏的字符串相加再給v2 
invoke-virtual{v2,v0},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
#輸出結果
invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

終於寫完了,我們編譯好來看看結果。

編譯出dex文件:


Pushandroid裏:


執行:


發現報錯了。百思不得其解,糾結了好久。代碼也檢查了好幾遍,最後都要崩潰了,還是出錯。後來實在忍無可忍,寫了個程序反編譯出dex文件看看吧。結果發現了原來少了這麼一句:

#此句加在輸入結果之前,將v2裏的東西轉化成String類型。
 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v2


重新編譯dex-->PUSH-->執行再試試:


好了,當然編寫的過程中可能會出現各種各樣的錯誤,需要耐心+毅力。
最後要說一下,.parameter這行我是刪了,用了2個版本的


都試了一下,發現沒有.parameter,有的話會報錯。可能是豐寫此書的時候版本還很低吧,這個大家要注意哦。
總的來說,雖然就這麼一點代碼,也不難。但確實是花了我不少時間,不過同時也學到了不少東西,對smali語句和adb命令,dex、class、smali等幾種格式的互相轉化也很熟練了。
最後感謝豐大牛,書寫得很好,有的細節不夠完美,但瑕不掩瑜。路漫漫其修遠兮,打牢基礎才能走得更遠。

By Ericky 

2014.11.27


發佈了31 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章