即前篇文章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 實際上調用的是子類中的方法。