Android 逆向分析(一) 之 Smali語法

Smali 語法

引言

  • 你們都知道apk安裝包其實就是個zip包,咱們經過解壓軟件解壓出來會看到裏面的架構java

    • assets數組

    • META_INF 存放簽名信息緩存

    • lib架構

      • arm
      • ...
    • res性能

    • AndroidManifest.xml優化

    • classes.dex Java代碼編譯獲得的Dalvik VM能直接執行的文件編碼

    • resources.arsc翻譯

asset和res資源目錄的不一樣在於:設計

1. res目錄下的資源文件在編譯時會自動生成索引文件(R.java),assets的資源文件不須要生成索引,在Java代碼中須要用AssetManager來訪問

 2. 通常來講,除了音頻和視頻資源(須要放在raw或asset下),使用Java開發的Android工程使用到的資源文件都會放在res下;使用C++遊戲引擎(或使用Lua binding等)的資源文件均須要放在assets下。

Dalvik

  • Dalvik虛擬機是Google等廠商合做開發的Android移動設備平臺的核心組成部分之一。 它能夠支持已轉換爲 .dex格式的Java應用程序的運行,.dex格式是專爲Dalvik設計的一種壓縮格式,適合內存和處理器速度有限的系統。 Dalvik 通過優化,容許在有限的內存中同時運行多個虛擬機的實例,而且每個Dalvik 應用做爲一個獨立的Linux 進程執行。獨立的進程能夠防止在虛擬機崩潰的時候全部程序都被關閉。

Dalvik和JVM 的關係

  • Dalvik是基於寄存器的,而JVM是基於棧的。Dalvik運行dex文件,而JVM運行java字節碼自Android 2.2開始,Dalvik支持JIT(just-in-time,即時編譯技術)。優化後的Dalvik較其餘標準虛擬機存在一些不一樣特性: 
    • 1.佔用更少空間 
    • 2.爲簡化翻譯,常量池只使用32位索引  
    • 3.標準Java字節碼實行8位堆棧指令,Dalvik使用16位指令集直接做用於局部變量。局部變量一般來自4位的「虛擬寄存器」區。這樣減小了Dalvik的指令計數,提升了翻譯速度。 當Android啓動時,Dalvik VM 監視全部的程序(APK),而且建立依存關係樹,爲每一個程序優化代碼並存儲在Dalvik緩存中。Dalvik第一次加載後會生成Cache文件,以提供下次快速加載,因此第一次會很慢。Dalvik解釋器採用預先算好的Goto地址,每一個指令對內存的訪問都在64字節邊界上對齊。這樣能夠節省一個指令後進行查表的時間。爲了強化功能, Dalvik還提供了快速翻譯器(Fast Interpreter)。

ART

  • Android Runtimecode

    ART 的機制與 Dalvik 不一樣。在Dalvik下,應用每次運行的時候,字節碼都須要經過即時編譯器(just in time ,JIT)轉換爲機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成爲真正的本地應用。這個過程叫作預編譯(AOT,Ahead-Of-Time)。這樣的話,應用的啓動(首次)和執行都會變得更加快速。

  • 優缺點

    優勢:

    - 一、系統性能的顯著提高。
      - 二、應用啓動更快、運行更快、體驗更流暢、觸感反饋更及時。
      - 三、更長的電池續航能力。
      - 四、支持更低的硬件。

    缺點:

    - 1.機器碼佔用的存儲空間更大,字節碼變爲機器碼以後,可能會增長10%-20%(不過在應用包中,可執行的代碼經常只是一部分。好比最新的 Google+ APK 是 28.3 MB,可是代碼只有 6.9 MB。)
      - 2.應用的安裝時間會變長。

一 Smali語法:Registers(寄存器)

  • 引言

    在Dalvik字節碼中,寄存器都是32位的,可以支持任何類型。64位類型(Long和Double型)用2個寄存器表示。有兩種方式指定一個方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的總數。.locals指令代表了方法中非參寄存器的數量。

  • 寄存器命名方式

    V命名方式和P命名方式。P命名方式中的第一個寄存器就是方法中的第一個參數寄存器。

    • 敲黑板 舉例說明: 若是一個方法有3個參數,5個寄存器 表示方法以下

      - v0                 the first local Register
        - v1				 the second local Register
        - v2		p1       the first parameter Register
        - v3		p2       the second parameter  Register
        - v4		p3       the thrid parameter  Register

    你能夠用任何一種方式來引用參數寄存器——他們沒有任何差異。

Smali 語法

  • 數據類型

    JAVA 對比 Smali

    - byte					B
      - boolean               Z
      - int                   I
      - float                 F
      - long                  J   64bit  兩個寄存器
      - double                D   64bit  兩個寄存器
      - short                 S
      - char                  C
      - void                  V
      - Object                L    L 表明對象 注意區別 long
      - Array                 [

    對象類型

    L能夠表示java類型中的任何類.在java代碼中以package.name.ObjectName的方式引用,而在Davilk中其描述則是以Lpackage/name/ObjectName;的形式表示.L即上面定義的JAVA類類型,表示後面跟着的是類的全限定名.好比java中的java.lang.String對應的描述--> Ljava/lang/String

    數組類型

    "[" 類型用來表示全部基本類型的數組,"["後跟着是基本類型的描述符.每一維度使用一個前置的"[", 好比java中的int[] 用匯編碼表示即是**[I**;二維數組int[][][[I,三維數組則用**[[[I**表示.

    對於對象數組來講,"["後跟着對應類的全限定符.好比java當中的String[]對應的是[java/lang/String;.

  • 字段描述

    基本類型和引用類型,不過兩種類型引用格式類型相同

    - 對象類型描述符->字段名:類型描述符
      - eg:好比org.professor.demo 裏面個Test類,該類中有兩個變量,一個爲int  一個爲String
      Lorg/professor/demo/Test;->name:Ljava/lang/String;
      Lorg/professor/demo/Test;->age:I
  • 方法描述

    JAVA中方法的簽名包括方法名,參數及返回值,在Smali相應的描述規則爲:

    對象類型描述符->方法名(參數類型描述符)返回值類型描述符
      eg:
      java方法:public char charAt(int index){...}
      Davilk描述:Ljava/lang/String;->charAt(I)C
    
      java方法:public void getChars(int srcBegin,int srcEnd,char dst[],int dstBegin){...}
      Davilk描述:Ljava/lang/String;->getChars(II[CI)V
    
      java方法:public boolean equals(Object anObject){...}
      Davilk描述:Ljava/lang/String;->equals(Ljava/lang/Object)Z
相關文章
相關標籤/搜索