天天看點

Android 靜态分析smail

     即前篇文章Android 靜态分析 smali,我一直在思考以下幾個問題:

     1、子類使用的父類中的方法,那麼對應的smail是invoke-super還是invoke-virtual呢?對應的類是父類還是子類呢?

     解釋:invoke-direct {p0}, Landroid/app/Activity;-><init>()V,這裡所說的父類還是子類指的是invoke參數後面跟着的類,在這個例子中是Landroid/app/Activity。

     2、在抽象的父類中使用抽象的方法,但是這個方法的實作卻在子類,那麼對應的smali的類是父類還是子類呢?

     3、生成子類的對象後,通過這個對象去調用父類的方法,那麼對應的smali的類是父類還是子類呢?

     4、如果子類向上轉型為父類,再調用被子類覆寫的方法時,那麼對應的smali的類是父類還是子類呢?

     5、如果子類向上轉型為父類,并且父類是接口,再調用被子類覆寫的接口中的方法時,那麼對應的smali的類是父類還是子類呢?

     帶着這些疑問,我們先建一個Android工程。

     MainActivity.java

package com.example.crackdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//生成子類對象(子類public構造函數),可以使用子類public方法和父類未被覆寫的public方法。
		SubClass subClass = new SubClass(this);
		subClass.doSomething();
		subClass.doSuperSomething(this);
		
		//如果向上轉型生成父類對象,隻能調用父類的public方法如果子類複寫了該方法,那麼調用子類的對應方法。
		SuperClass subClass1 = new SubClass(this);
		subClass1.doSubSomething();
		
		//如果向下轉型,可以使用子類public方法和父類未被覆寫的public方法。
		//如果被覆寫了,則調用子類的對應方法
		SubClass subClass2 = (SubClass) subClass1;
		subClass2.doSubSomething();
		
		//如果向上轉型生成父類對象,隻能調用父類的public方法如果子類複寫了該方法,那麼調用子類的對應方法。
		SuperInterface superInterface = new SubClass(this);
		superInterface.doInterfaceSomething();
	}
}
           

     SubClass.java

package com.example.crackdemo;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

public class SubClass extends SuperClass implements SuperInterface {
	private Context mContext;

	public SubClass(Context context) {
		mContext = context;
	}

	@Override
	public void doSubSomething() {
		Toast.makeText(mContext, "doSubSomething", Toast.LENGTH_LONG).show();
	}

	public void doSomething() {
		doSuperSomething(mContext);
		doOwnSomething();
	}
	
	private void doOwnSomething() {
		Toast.makeText(mContext, "doOwnSomething", Toast.LENGTH_LONG).show();
	}

	@Override
	public void doInterfaceSomething() {
		Log.d("jltxgcy", "doInterfaceSomething");
	}

}
           

     SuperClass.java

package com.example.crackdemo;

import android.content.Context;
import android.widget.Toast;

public abstract class SuperClass {
	public abstract void doSubSomething();
	
	public void doSuperSomething(Context context){
		doSubSomething();
		Toast.makeText(context, "doSuperSomething", Toast.LENGTH_LONG).show();
	}
}
           

    SuperInterface.java

package com.example.crackdemo;

public interface SuperInterface {
	public void doInterfaceSomething();
}
           

    反編譯,生成的smail:

     MainActivity.smali

.class public Lcom/example/crackdemo/MainActivity;
.super Landroid/app/Activity;


# direct methods
.method public constructor <init>()V
    .locals 0

    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    return-void
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 1

    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    const/high16 v0, 0x7f030000

    invoke-virtual {p0, v0}, Lcom/example/crackdemo/MainActivity;->setContentView(I)V
	

    new-instance v0, Lcom/example/crackdemo/a;

    invoke-direct {v0, p0}, Lcom/example/crackdemo/a;-><init>(Landroid/content/Context;)V

    invoke-virtual {v0}, Lcom/example/crackdemo/a;->b()V

    invoke-virtual {v0, p0}, Lcom/example/crackdemo/a;->a(Landroid/content/Context;)V //調用了父類的doSuperSomething
	

    new-instance v0, Lcom/example/crackdemo/a;

    invoke-direct {v0, p0}, Lcom/example/crackdemo/a;-><init>(Landroid/content/Context;)V

    invoke-virtual {v0}, Lcom/example/crackdemo/b;->a()V //調用了子類的doSubSomething
	

    check-cast v0, Lcom/example/crackdemo/a;

    invoke-virtual {v0}, Lcom/example/crackdemo/a;->a()V //調用了子類的doSubSomething
	

    new-instance v0, Lcom/example/crackdemo/a;

    invoke-direct {v0, p0}, Lcom/example/crackdemo/a;-><init>(Landroid/content/Context;)V

    invoke-interface {v0}, Lcom/example/crackdemo/c;->c()V //調用了子類的doInterfaceSomething

    return-void
.end method
           

     a.smail(SubClass.java)

.class public Lcom/example/crackdemo/a;
.super Lcom/example/crackdemo/b;

# interfaces
.implements Lcom/example/crackdemo/c;


# instance fields
.field private a:Landroid/content/Context;


# direct methods
.method public constructor <init>(Landroid/content/Context;)V
    .locals 0

    invoke-direct {p0}, Lcom/example/crackdemo/b;-><init>()V

    iput-object p1, p0, Lcom/example/crackdemo/a;->a:Landroid/content/Context;

    return-void
.end method

.method private d()V  //private void doOwnSomething()
    .locals 3

    iget-object v0, p0, Lcom/example/crackdemo/a;->a:Landroid/content/Context;

    const-string v1, "doOwnSomething"

    const/4 v2, 0x1

    invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    return-void
.end method


# virtual methods
.method public a()V  //public void doSubSomething()
    .locals 3

    iget-object v0, p0, Lcom/example/crackdemo/a;->a:Landroid/content/Context;

    const-string v1, "doSubSomething"

    const/4 v2, 0x1

    invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    return-void
.end method

.method public b()V //public void doSomething()
    .locals 1

    iget-object v0, p0, Lcom/example/crackdemo/a;->a:Landroid/content/Context;

    invoke-virtual {p0, v0}, Lcom/example/crackdemo/a;->a(Landroid/content/Context;)V //調用了父類的doSuperSomething

    invoke-direct {p0}, Lcom/example/crackdemo/a;->d()V

    return-void
.end method

.method public c()V //public void doInterfaceSomething()
    .locals 2

    const-string v0, "jltxgcy"

    const-string v1, "doInterfaceSomething"

    invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    return-void
.end method
           

     b.smali(SuperClass.java)

.class public abstract Lcom/example/crackdemo/b;
.super Ljava/lang/Object;


# direct methods
.method public constructor <init>()V
    .locals 0

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method


# virtual methods
.method public abstract a()V
.end method

.method public a(Landroid/content/Context;)V
    .locals 2

    invoke-virtual {p0}, Lcom/example/crackdemo/b;->a()V //調用了子類的doSubSomething	

    const-string v0, "doSuperSomething"

    const/4 v1, 0x1

    invoke-static {p1, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    return-void
.end method
           

     c.smali(SuperInterface.java)

.class public interface abstract Lcom/example/crackdemo/c;
.super Ljava/lang/Object;


# virtual methods
.method public abstract c()V
.end method
           

     回答第一個問題:

     在a.smail中的方法b,對應SubClass類中doSomething中調用了父類的doSuperSomething,如下:

     invoke-virtual {p0, v0}, Lcom/example/crackdemo/a;->a(Landroid/content/Context;)V ,我們看到這裡使用的是invoke-virtual,并且->前面使用的是子類,但是->後面的方法a(Landroid/content/Context;)V,卻是父類的方法。

     如果在java中是這樣寫的:

public void doSomething() {
		super.doSuperSomething(mContext);
		doOwnSomething();
	}
           

     那麼對應的smail是這樣的,  invoke-super{p0, v0}, Lcom/example/crackdemo/b;->a(Landroid/content/Context;)V,此時使用的invoke-super,并且->前面使用的是父類。

     回答第二個問題:

     在b.smali的方法a,對應SuperClass類中doSuperSomething中調用了doSubSomething,如下:

     invoke-virtual {p0}, Lcom/example/crackdemo/b;->a()V,我們看到這裡使用的是invoke-virtual,此時->前面Lcom/example/crackdemo/b使用的是父類,但->後面a()V實際調用的卻是子類中方法。

    回答第三個問題:

SubClass subClass = new SubClass(this);
		subClass.doSomething();
		subClass.doSuperSomething(this);
           

     doSuperSomething對應的smali如下,在MainActivity.smali的onCreate方法:

invoke-virtual {v0, p0}, Lcom/example/crackdemo/a;->a(Landroid/content/Context;)V
           

    我們可以看到->前面Lcom/example/crackdemo/a使用的是子類,但->後面a(Landroid/content/Context;)V實際調用的是父類中的方法。

    回答第四個問題:

//如果向上轉型生成父類對象,隻能調用父類的public方法如果子類複寫了該方法,那麼調用子類的對應方法。
		SuperClass subClass1 = new SubClass(this);
		subClass1.doSubSomething();
           

    doSubSomething 對應的smali如下,在MainActivity.smali的onCreate方法:

invoke-virtual {v0}, Lcom/example/crackdemo/b;->a()V
           

    我們可以看到->前面Lcom/example/crackdemo/b使用的是父類的b,但 ->後面a()V實際上調用的是子類中的方法。

     回答第五個問題:

//如果向上轉型生成父類對象,隻能調用父類的public方法如果子類複寫了該方法,那麼調用子類的對應方法。
		SuperInterface superInterface = new SubClass(this);
		superInterface.doInterfaceSomething();
           

     doInterfaceSomething 對應的smali如下,在MainActivity.smali的onCreate方法:

invoke-interface {v0}, Lcom/example/crackdemo/c;->c()V //調用了子類的doInterfaceSomething
           

      我們可以看到->前面 Lcom/example/crackdemo/c 使用的是父類接口c,但 ->後面c()V 實際上調用的是子類中的方法。

繼續閱讀