[Android Security] Smali和逆向分析

copy : https://blog.csdn.net/u012573920/article/details/44034397

1.Smali簡介

Smali是Dalvik的寄存器語言,它與Java的關係,簡單理解就是彙編之於C。假如你對彙編有足夠的駕馭能力,那你能夠經過修改彙編代碼來改變C/C++代碼的走向。固然,學過彙編的都清楚,彙編比BrainFuck還難學,更不用說去反編譯修改了。php

可是Smali有一點不同,就是它很簡單,只有一點點的語法,只要你會java,瞭解Android的相關知識,那你徹底能夠經過修改Smali代碼來反向修改java代碼,雖然繞了一點,可是在某些狀況下你不得不這麼作。還好,Smali很簡單。html

2.apktool

說了這麼多,尚未說Smali哪來?沒錯。Smali代碼是安卓APK反編譯而來的,因此Smali文件和Java文件一一對應。獲取Smali文件,咱們須要下載一個輔助工具:ApkTool。apktool這個命令行工具若是詳細使用功能參數是比較多的,可是這裏咱們只須要用到2個最基礎的功能:java

一個是反編譯decode:android

apktool d xxx.apk

另外一個是打包build:數組

apktool b

這裏要注意的是路徑問題,apktool若是沒有加入到環境變量中,記得cd到apktool的目錄去使用它。另外一個是打包,若是隻是簡單的使用參數b,那要求是要在反編譯出來的項目目錄下執行,而打包好的文件會保存在這個項目目錄下的dist目錄。安全

這是一個HelloWorld的應用程序反編譯和打包的目錄結構:app

3.Smali語法

(1)數據類型

 

dalvik字節碼有兩種類型,原始類型和引用類型。對象和數組是引用類型,其它都是原始類型。ide

smali數據類型都是用一個字母表示,若是你熟悉Java的數據類型,你會發現表示smali數據類型的字母實際上是Java基本數據類型首字母的大寫,除boolean類型外,在smail中用大寫的」Z」表示boolean類型。函數

V void,只能用於返回值類型
Z boolean
B byte
S short
C char
I int
J long (64 bits)
F float
D double (64 bits)

 對象以Lpackage/name/ObjectName;的形式表示。前面的L表示這是一個對象類型,package/name/是該對象所在的包,ObjectName是對象的名字,「;」表示對象名稱的結束。至關於java中的package.name.ObjectName。工具

例如:Ljava/lang/String;至關於java.lang.String

 

數組的表示形式

[I——表示一個整型一維數組,至關於java中的int[]。對於多維數組,只要增長[就好了。[[I至關於int[][],[[[I至關於int[][][]。注意每一維的最多255個。

 對象數組的表示

[Ljava/lang/String;表示一個String對象數組。

(2)方法

 

方法一般必須詳細的指定方法類型(?the type that contains the method) 方法名,參數類型,返回類型,全部這些信息都是爲虛擬機是可以找到正確的方法並執行。

方法表示形式:Lpackage/name/ObjectName;->MethodName(III)Z

在上面的例子中,Lpackage/name/ObjectName;表示類型,MethodName是方法名。III爲參數(在此是3個整型參數),Z是返回類型(bool型)。

方法的參數是一個接一個的,中間沒有隔開。

一個更復雜的例子:method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

在java中則爲:String method(int, int[][], int, String, Object[])

一個比較全面的例子:

.class public interface abstract Lcom/kit/network/CachableImage;  
.super Ljava/lang/Object;  
.source "SourceFile"  
  
# virtual methods  
.method public abstract getIsLarge()Z  
.end method  
  
.method public abstract getUrl()Ljava/lang/String;  
.end method  
  
.method public abstract getViewContext()Landroid/content/Context;  
.end method  
  
.method public abstract setBitmap(Landroid/graphics/Bitmap;Z)V  
.end method  
  
.method public abstract setIsLarge(Z)V  
.end method  
  
.method public abstract setUrl(Ljava/lang/String;)V  
.end method  

上面的smali代碼還原後的java代碼爲:

 
//#注:在實際代碼中咱們還必須引入相關的包  
import android.content.Context;  
import android.graphics.Bitmap;  
  
public interface CachableImage {  
  
    public abstract boolean getIsLarge();  
  
    public abstract String getUrl();  
  
    public abstract Context getViewContext();  
  
    public abstract void setBitmap(Bitmap bitmap);  
  
    public abstract void setIsLarge(boolean islarge);  
  
    public abstract void setUrl(String url);  
}  

  

 

 (3)字段

 

表示形式:Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;即包名,字段名和各字段類型。 eg:

 
.field private _requestLayout:Z  
  
.field public isLarge:Z  
  
.field public resize:Z  
  
.field public thumbnailSize:I  
  
.field public url:Ljava/lang/String;  

  

還原後的java代碼爲:
 
public boolean _requestLayout;  
public boolean isLarge;  
public boolean resize;  
public int thumbnailSize;  
public String url;  

  

這裏仍然以一個默認的HelloWorld的應用程序進行解釋吧。新建一個HelloWorld安卓項目,在MainActivity中只保留onCreate函數。代碼以下:

package com.fusijie.helloworld;  
  import android.app.Activity;  
  import android.os.Bundle;  
  public class MainActivity extends Activity {  
  @Override  
  protected void onCreate(Bundle savedInstanceState) {  
      super.onCreate(savedInstanceState);  
      setContentView(R.layout.activity_main);  
      }  
  }  

 

反編譯後的Smali文件以下:

 
.class public Lcom/fusijie/helloworld/MainActivity;  
.super Landroid/app/Activity;  
.source "MainActivity.java"  
# direct methods  
.method public constructor ()V  
  .locals 0  
  .prologue  
  .line 14  
  invoke-direct {p0}, Landroid/app/Activity;->()V  
  return-void  
.end method  
# virtual methods  
.method protected onCreate(Landroid/os/Bundle;)V  
  .locals 1  
  .parameter "savedInstanceState"  
  .prologue  
  .line 18  
  invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V  
  .line 19  
  const/high16 v0, 0x7f03  
  invoke-virtual {p0, v0}, Lcom/fusijie/helloworld/MainActivity;->setContentView(I)V  
  .line 20  
  return-void  
.end method  

 

對比一下,能夠比較清楚的看出來,smali代碼其實就是對java代碼一個翻譯,只是沒有java看起來那麼簡單,smali把不少應該複雜的東西還原成複雜的狀態了。簡單解釋下這段代碼。

  • 前三行指明瞭類名,父類名,和源文件名。
  • 類名以「L」開頭相信熟悉Jni的童鞋都比較清楚。
  • 「#」是smali中的註釋。
  • 「.method」和「.end method」相似於Java中的大括號,包含了方法的實現代碼段。
  • 方法的括號後面指明瞭返回類型,這一樣相似與Jni的調用。
  • 「.locals」指明瞭這個方法用到的寄存器數量,固然寄存器能夠重複利用,從「V0」起算。
  • 「.prologue」指定了代碼開始處。
  • 「.line」代表這是在java源碼中的第幾行,其實這個值無所謂是多少,能夠任意修改,主要用於調試。
  • 「invoke-direct」這是對方法的調用,能夠看到這裏調用了是Android.app.Activity的init方法,這在java裏是隱式調用的。
  • 「return-void」代表了返回類型,這和java不同,即便沒有返回值,也須要這樣寫。
  • 接下來是onCreate方法,「.parameter」指明瞭參數名,可是通常沒有用,須要注意的是p0表明的是this,p1開始表明函數參數,靜態函數沒有this,因此從p0開始就表明參數。
  • 在實現裏先是調用了父類的方法,而後再調用setContentView,注意這裏給了一個傳參。整形的傳參,這個值是先賦給寄存器v0,而後再調用的使用傳遞進去的。smali中都是這麼使用,全部的值必須經過寄存器來中轉。這點和彙編很像。

對比了Java代碼和Smali代碼,能夠很清楚的看到,本來只有幾行的代碼到了Smali,內容被大大擴充了。Smali還原了Java隱藏的東西,同時顯式地指定了不少細節。這還只是個最基本的HelloWorld的onCreate函數,若是有內部類,還會分文件顯示。

這樣看來,其實Smali只能說複雜,不能說難。若是想全面瞭解smali語法,這裏給出幾個連接,算是總結的相對好一點的(其實我都沒看到有系統總結的。。。若是你有好的資料,歡迎跟帖分享)

這裏順便提供2個利器:

從上面一個例子對Smali的用途就很清楚了,沒錯,Smali注入。如今常見的除了測試之外的用途,Smali注入明顯是帶有黑客性質的,小的如破解遊戲,替換遊戲廣告,大的甚至利用漏洞去破解密碼,偷竊我的資料,財產等等。對Smali,安卓逆向分析,安卓系統安全比較清楚的,這些事其實都不算事。

相關文章
相關標籤/搜索