即前篇文章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"); } }
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(); } }
package com.example.crackdemo; public interface SuperInterface { public void doInterfaceSomething(); }
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
.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
.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
.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 实际上调用的是子类中的方法。