smali 中内部类, 函数内部, 解析

时间:2022-10-31 16:56:11

从类的角度去理解smali的文件组织结构。

内部类:

public classMainActivity extends Activity {  

   public class firstinner

   {

      public class secondinner

      {

         public class thirdinner

         {

           

         }       

      }    

   }

}

 

对于形如此类的内部类声明格式。

文件的产生方式为:

smali 中内部类, 函数内部, 解析

即:   [外部类]$内部类.smali 的形式,并依此迭代。

对于匿名的内部类,将以[外部类]$NUM.smali的形式迭代,NUM代表从1开始的数字。

打开文件:MainActivity$firstinner$secondinner.smali

 

1、其中开头的注解域为

# annotations

#表明MainActivity$firstinner$secondinner这个类的作用范围,EnclosingClass 表明作用范围//是一个类,value表明的就是作用于MainActivity$firstinner这个类。还有EnclosingMethod,//表明类作用的范围是一个方法。比如声明在一个方法里面的监听类等。

.annotationsystem Ldalvik/annotation/EnclosingClass;
   value = Lcom/example/smali/MainActivity$firstinner;
.end annotation


#accessFlags

enum {

   kDexVisibilityBuild          = 0x00,     /*annotation visibility */

   kDexVisibilityRuntime        = 0x01,

   kDexVisibilitySystem            = 0x02,

}; 

.annotationsystem Ldalvik/annotation/InnerClass;            #表明本身是一个内部类
   accessFlags = 0x1
   name = "secondinner"
.end annotation


.annotationsystem Ldalvik/annotation/MemberClasses;              #列出了内部类的列表
   value = {
       Lcom/example/smali/MainActivity$firstinner$secondinner$thirdinner;
    }
.end annotation



2、实例域

# instance fields
.field final syntheticthis$1:Lcom/example/smali/MainActivity$firstinner;

Synthetic代表它是由编译器合成的,虚构的。

this$1 内部类存储的外部类的一个引用。即Lcom/example/smali/MainActivity$firstinner;的引用。

 

3、对于一个有内容的内部类SNChecker。有如下构造函数

# direct methods
.method publicconstructor <init> (Lcom/droider/crackme0502/MainActivity;Ljava/lang/String;)V
.locals0                #在这个函数中最少要用到的本地寄存器的个数
.parameter             #p1 -> 代表Lcom/droider/crackme0502/MainActivity的引用
    .parameter "sn"         #p2 ->  Ljava/lang/String字符串sn
 
    .prologue              #具体代码的开始
    .line 83
    iput-object p1, p0,Lcom/droider/crackme0502/MainActivity$SNChecker ;->this$0 :Lcom/droider/crackme0502/MainActivity;
 
    invoke-direct {p0},Ljava/lang/Object;-><init>()V  #代表调用Ljava/lang/Object;类型的直接方法。参数是p0。
 
    .line 84
    iput-object p2, p0,Lcom/droider/crackme0502/MainActivity$SNChecker;->sn:Ljava/lang/String;
 
    .line 85
    return-void            #返回空
.end method

#有两种寄存器命名方式,V命名 和 P命名。  在一个函数中,V命名代表函数内声明的局部变量;P命名代表函数中引入的参数变量。

#以.method 和.end method 包围一个方法。 “publicconstructor <init>”是方法的修饰。

括号里面的是参数(Lcom/droider/crackme0502/MainActivity; Ljava/lang/String; )

最后的V代表返回的类型。返回类型为空void

#.locals  在这个函数中最少要用到的本地寄存器的个数。如果是 .registers4 这种形式代表使用v0、v1、v2寄存器与一个参数寄存器

#. parameter   代表函数引入的参数声明,有几个参数,就有几个parameter 。

# iput-object p1, p0,L…     代表,将p1的值放入p0中。P1的值来源于L…中声明的引用。

# Lcom/droider/crackme0502/MainActivity$SNChecker;->sn  :  Ljava/lang/String;

冒号之前的部分“Lcom/droider/crackme0502/MainActivity$SNChecker;”代表后面的变量属于哪个类的成员。即sn属于此内容中的成员。  冒号后面的部分“Ljava/lang/String;”代表此程序的类型。这里代表String字符串类型。

Smali数据类型:

B---byte

C---char

D---double

F---float

I---int

J---long

S---short

V---void

Z---boolean

[XXX---array

Lxxx/yyy---object



关于函数的几种调用方式,有一个很好的参考总结。五种调用方式。

invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface

最常用的是invoke-direct,invoke-virtual。

invoke-direct代表使用private方法。

invoke-virtual代表public或者 protected。

http://blog.csdn.net/lpohvbe/article/details/7981386