1. 程式人生 > >Dalvik指令集練習(smali檔案的編寫)

Dalvik指令集練習(smali檔案的編寫)

移動智慧終端安全

(作者:Baron_wu 禁止轉載)

**
一、 實驗內容

  • 編寫smali檔案,輸出HelloXidian
  • 編寫smali檔案,計算(7+5)*(7-5)

二、相關原理與知識
Smali檔案編寫原理:
檔案頭
.class <訪問許可權> [修飾關鍵字] <類名>
.super <父類名>
.source <原始檔名>
上面的<訪問許可權>指類訪問許可權修飾符,<修飾關鍵字>是Dalvik位元組碼的一種約定,具體約定如下:
Dalvik位元組碼有兩種型別,原始型別和引用型別,同時引用型別又包括物件和陣列。

對於陣列型別,則使用 [ 和上面的型別進行組合,比如下面
//int陣列 int[]
[I
//String陣列 String[]
[L java/lang/String

方法
#表示之後的內容為註釋,是apktool為我們新增的
.line n 表示該內容在原始碼中的行數
.method和.end method 表示一個方法的開始和結束
方法又分為direct methods和virtual methods兩種。

direct methods的宣告格式為
.method <訪問許可權> [修飾關鍵字] <方法原型>
.locals <區域性變數個數>
.param <方法的引數>
.prologue
.line
.end method

上面的<方法原型>包括方法的名稱、引數和返回值(這裡的返回值形式為型別的首字母大寫[V表示void])。
上面的.prologue表示程式碼的開始。
成員變數
除了方法,還有成員變數,成員變數又分為靜態成員變數和例項變數。

靜態成員變數的宣告格式
#static fields
.field private static count:I
.field <訪問許可權> static [修飾關鍵字] <欄位名>:<欄位型別>

例項成員變數的宣告格式
#instance fields
.field private name:Ljava/lang/String;
.field <訪問許可權> [修飾關鍵字] <欄位名>:<欄位型別>

介面
介面的格式
.implements <介面名>

註解
註解的格式
.annotation [註解屬性] <註解類名>
[註解欄位 = 值]
.end annotation

Smali檔案的編譯與執行過程:
編譯 smali 程式
將 .smali 檔案編譯為 .dex 檔案:
java –jar smali.jar –o classes.dex Hello.smali
執行 smali 程式
開啟虛擬機器環境;
adb push Hello.zip /data/local
adb shell dalvikvm –cp /data/local/Hello.zip HelloXidian

java程式碼轉smali程式碼原理:
把java程式碼轉成smali程式碼共需要以下三個步驟

1、編譯java程式碼為class檔案:
javac -source 1.6 -target 1.6 (dex不支援jdk8)

2、把class檔案轉成dex檔案
我們知道apk包裡java程式碼最後生成的是class.dex檔案,把class轉化成dex檔案就需要用到android SDK提供的一個工具dx,該jar包位於android-sdk\build-tools\23.0.1\lib,找到該包後執行以下命令:
java -jar dx.jar –dex –output=smaliTest.dex smaliTest.class

3、把dex轉化成smali檔案
這時候會使用到另外一個工具baksmali,該工具位於android-sdk\platform-tools\,找到該包後執行以下命令:
java -jar baksmali.jar smaliTest.dex
生成的檔案儲存在out資料夾中

三種檔案型別:
Java檔案-----應用程式原始檔android本身相當一部分都是用java編寫而成(基本上架構圖裡頭藍色的部份都是用Java開發的),
android的應用必須使用java來開發

Class檔案------Java編譯後的目標檔案不像J2se,java編譯成class就可以直接執行,android平臺上class檔案不能直接在android上執行。
由於Google使用了自己的Dalvik來執行應用, 所以這裡的class也肯定不能在AndroidDalvik的java環境中執行,
android的class檔案實際上只是編譯過程中的中間目標檔案,需要連結成dex檔案後才能在dalvik上執行

Dex檔案-----Android平臺上的可執行檔案Android虛擬機器Dalvik支援的位元組碼檔案格式Google在新發布的Android平臺上使用了自己的Dalvik虛擬機器來定義, 這種虛擬機器執行的並非Java位元組碼, 而是另一種位元組碼:
dex格式的位元組碼。在編譯Java程式碼之後,通過Android平臺上的工具可以將Java位元組碼轉換成Dex位元組碼。雖然Google稱Dalvik是為了移動裝置定做的,但是業界很多人認為這是為了規避向sun申請Javalicense。這個DalvikVM針對手機程式/CPU做過最佳化,可以同時執行許多VM而不會佔用太多Resource。

二、 實驗過程
HelloXidian.smali編譯執行過程:

首先編輯Hello.smali檔案並存入Android-sdk的tools資料夾中,並將smali.jar下載後放入到Android-sdk的tools資料夾中
在這裡插入圖片描述

開啟終端進入到Android-sdk的tools資料夾中

在這裡插入圖片描述
之後執行命令java -jar smali2.1.0.jar -o classes.dex Hello.smali將.smali檔案轉變為dex檔案

在這裡插入圖片描述
在這裡插入圖片描述
之後將classes.dex打包壓縮為Hello.zip

在這裡插入圖片描述
之後再執行命令adb push Hello.zip /data/local將Hello.zip上傳

在這裡插入圖片描述
最後執行命令adb shell dalvikvm -cp /data/local/Hello.zip HelloXidian
在這裡插入圖片描述
(7-5)*(7+5)計算的smali檔案生成過程:
方法一:

編寫math.operation.smali檔案

.class public Lmath;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
    .registers 5
    const/16 v0, 0x07
    const/16 v1, 0x05
    #兩數相加
    add-int v2,v0,v1
	#兩數相減
    sub-int v3,v0,v1
	#兩數相乘
    mul-int v3,v2,v3
    #將結果輸出
    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(I)V
    return-void
.end method

在這裡插入圖片描述

將其放到tools資料夾中,並執行命令java -jar smali-2.1.0.jar -o classes.dex math.smali

在這裡插入圖片描述

執行命令後將生成一個名為classes.dex的檔案,將此檔案壓縮為math.zip檔案
在這裡插入圖片描述

再在終端執行命令adb push math.zip /data/local 將math.zip 上傳到虛擬機器裡

在這裡插入圖片描述
待成功上傳後執行命令adb shell dalvikvm -cp /data/local/math.zip math 之後將會在終端看到輸出24
在這裡插入圖片描述

方法二:
首先編輯math_operation.java檔案

在這裡插入圖片描述
將此檔案放到Android-sdk的tools中並進入此資料夾
執行命令javac math_operation.java將其編譯為class檔案
在這裡插入圖片描述
在這裡插入圖片描述
再將dx.jar檔案放入tools資料夾中
在這裡插入圖片描述
執行命令java -jar dx.jar --dex –output=math.dex math_operation.class
在這裡插入圖片描述
在這裡插入圖片描述
執行命令java -jar baksmali-2.1.0.jar math.dex
在這裡插入圖片描述

將會在tools資料夾中產生一個out資料夾
在這裡插入圖片描述
在out資料夾中將會看到math_operation.smali檔案
在這裡插入圖片描述
最後生成的.smali檔案如下所示:
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
將生成的smali檔案放入D:\Android-sdk\tools進行編譯
java -jar smali2.1.0.jar -o classes.dex Hello.smali
將.smali檔案轉變為dex檔案
之後將classes.dex打包壓縮為math.zip
生成math.zip後,將其上傳到/data/local資料夾中
adb push math.zip /data/local
之後再進行執行
adb shell dalvikvm -cp /data/local/math.zip mathoperation
執行後的結果如下圖所示:
在這裡插入圖片描述
四、原始碼

HelloXiDian.smali檔案原始碼:

.class public LHelloXidian;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
    .registers 2
    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
    const-string v1, "HelloXidian!"
    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
    return-void
.end method

(7-5)(7+5)計算的原始碼(一):*

.class public Lmath;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
    .registers 5
    const/16 v0, 0x07
    const/16 v1, 0x05
    #兩數相加
    add-int v2,v0,v1
	#兩數相減
    sub-int v3,v0,v1
	#兩數相乘
    mul-int v3,v2,v3
    #將結果輸出
    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(I)V
    return-void
.end method

(7-5)(7+5)計算的原始碼(二):*

.class public Lmath_operation;
.super Ljava/lang/Object;
.source "math_operation.java"

 direct methods
.method public constructor <init>()V
    .registers 1
    .prologue
    .line 2
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method

.method public static add(II)I
    .registers 3
    .prologue
    .line 14
    add-int v0, p0, p1
    return v0
.end method

.method public static main([Ljava/lang/String;)V
    .registers 5
    .prologue
    .line 6
    const/4 v0, 0x7
    const/4 v1, 0x5
    .line 8
    invoke-static {v0, v1}, Lmath_operation;->add(II)I
    move-result v2
    .line 9
    invoke-static {v0, v1}, Lmath_operation;->sub(II)I
    move-result v0
    .line 10
    invoke-static {v2, v0}, Lmath_operation;->multiply(II)I
    move-result v0
    .line 11
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    new-instance v2, Ljava/lang/StringBuilder;
    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
    const-string v3, "(7+5)*(7-5)\u7684\u7ed3\u679c\u4e3a\uff1a"
    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 v0
    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
    move-result-object v0
    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
    .line 12
    return-void
.end method

.method public static multiply(II)I
    .registers 3
    .prologue
    .line 20
    mul-int v0, p0, p1
    return v0
.end method

.method public static sub(II)I
    .registers 3
    .prologue
    .line 17
    sub-int v0, p0, p1
    return v0
.end method