史上超详细的smali文件解读

小编 2026-06-25 阅读:1566 评论:0
smali文件的头3行 # 指定了当前类的类名,访问权限为public,类名开头的L是遵循Dalvik字节码的相关约定 .class public Lcom/example/administrator...

smali文件的头3行

# 指定了当前类的类名,访问权限为public,类名开头的L是遵循Dalvik字节码的相关约定

.class public Lcom/example/administrator/myapplication/Demo;  

# super指令指定了当前类的父类,父类为Object

.super Ljava/lang/Object;  


//指定了当前类的源文件名。注意:经过混淆的dex文件,反编译出来的smali代码可能没有源文件信息,source可能为空。

.source \"Demo.java\"  


字段的声明:


smali文件的字段的声明使用\".field\"指令,字段有静态字段和实例字段两种:
静态字段格式:  .field 访问权限 static 修饰关键字  字段名  字段类型 

.field public static HELLO:Ljava/lang/String;

上面smali代码转为java代码为:

public static String HELLO = \"hello\";

实例字段格式: .field 访问权限 修饰关键字 字段名  字段类型

.field private button:Landroid/widget/Button;
.field public number:I

上面的smali代码转为java代码为:

private Button button;
 public  int number =5;

 

方法的声明

使用\".method\"指令,分为直接方法(用private修饰的)和虚方法(用public和protected修饰的),直接方法和虚方法的声明是一样的。在调用函数时,有invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface等几种不同的指令。还有invoke-XXX/range 指令的,这是参数多于4个的时候调用的指令,比较少见:
 

.method private static getCount(II)V       
    .registers 2      
    .param p0, \"x\"    
    .param p1, \"y\"    

    .prologue       
    .line 28     
    return-void       
.end method      

第一行为方法的开始处,此处方法的修饰符是static,访问权限是private,方法名是getCount,有两个参数,都是int类型的(I代表int),V代表无返回值。

第二行指定寄存器的大小。

第三行和第四行为方法的参数,每有一个参数,就写一个参数,此处有两个参数。

第五行为 方法的主体部分(.prologue)

第六行指定了该处指令在源代码中的行号,这里是从java源码中底28行开始的

第七行return-void表示无返回值

第八行(.end method)方法结束

上面的smali转为java代码为:

private static void   getCount(int x,int y){

    }

类实现接口

如果一个类实现了接口,会在smali 文件中使用“.implements ”指令指出,相应的格式声明如下:

# interfaces
.implements Lcom/example/administrator/myapplication/TestParent;  

上面smali代码表明了实现了TestParent这个接口。

类使用注解

如果一个类使用了注解,会在 smali 文件中使用“.annotation ”指令指出,注解的格式声明如下:  
# annotations  
.annotation [ 注解属性] < 注解类名>  
    [ 注解字段 =  值]  
.end annotation  

注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,“.annotation ”指令会直接定义在smali 文件中,如果是方法或字段,“.annotation ”指令则会包含在方法或字段定义中。

.field public sayWhat:Ljava/lang/String;           
    .annotation runtime Lcom/droider/anno/MyAnnoField;  
        info = ”Hello my friend”  
    .end annotation  
.end field  

如上String 类型 它使用了 com.droider.anno.MyAnnoField 注解,注解字段info 值 为“Hello my friend”  
转换成java代码为:

@com.droider.anno.MyAnnoField(info = ”Hello my friend”)
public String sayWhat;


程序中的类


1)内部类:内部类可以有成员内部类,静态嵌套类,方法内部类,匿名内部类。
      格式: 外部类$内部类.smali

class Outer{

      class Inner{}

}

baksmali反编译上面的代码后会生成两个文件:Outer.smali和Outer$Inner.smali

Inner.smali文件如下:

.class public Lcom/example/myapplication/Outer$Inner;
.super Ljava/lang/Object;
.source \"Outer.java\"

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/example/myapplication/Outer;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x1
    name = \"Inner\"
.end annotation

# instance fields
.field final synthetic this$0:Lcom/example/myapplication/Outer;

# direct methods
.method public constructor <init>(Lcom/example/myapplication/Outer;)V
    .registers 2
    .param p1, \"this$0\"    # Lcom/example/myapplication/Outer;

    .prologue
    .line 4
    iput-object p1, p0, Lcom/example/myapplication/Outer$Inner;->this$0:Lcom/example/myapplication/Outer;

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    
    return-void
.end method

 

this$0是Outer类型,syntheitc关键字表明它是“合成的”。

.field final synthetic this$0:Lcom/example/myapplication/Outer;

this$0是什么东西呢?

this$0是内部类自动保留的一个指向所在外部类的隐隐个,左边的this表示为父类的引用,右边的数值0表示引用的层数:

public class Outer {
    public class FirstInner{}  //this$0
    public class SecondInner{} //this$1
    public class ThirdInner{}  //this$2
}

没往里一层右边的数值就加一,如ThirdInner类访问FirstInner类的引用为this$1.在生成的反汇编代码中,this$X型字段都被指定了synthetic属性,表明它们是被编译器合成的,虚构的,代码的作者并没有生命该字段。
 

紧接着来看Inner.smali的构造函数:

从下面的构造函数中可以看到.param指定了一个参数,却使用了p0和p1两个寄存器,因为Dalvik虚拟机对于一个非静态的方法而言,会隐含的使用p0寄存器当做类的this使用,因此,这里的确是使用了2个寄存器(.registers 2),p0表示Outer$Inner.smali自身的引用,p1表示this$0,也就是Outer的引用。

# direct methods
.method public constructor <init>(Lcom/example/myapplication/Outer;)V
    .registers 2
    .param p1, \"this$0\"    # Lcom/example/myapplication/Outer;

    .prologue
    .line 4
    iput-object p1, p0, Lcom/example/myapplication/Outer$Inner;->this$0:Lcom/example/myapplication/Outer;

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

    return-void
.end method

分析如下:

 .param p1, \"this$0\"    # Lcom/example/myapplication/Outer;

这个是默认的构造函数,没有参数,但是有一个默认的参数就是this$0,他是Outer的应用,如果构造函数有参数的话,会在

.param p1,\"this$0\"下面继续列出。

iput-object p1, p0, Lcom/example/myapplication/Outer$Inner;->this$0:Lcom/example/myapplication/Outer;

将Outer引用赋值给this$0

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

调用默认的构造函数。

 

2)监听器

Android程序开发中使用了大量的监听器,比如Button的点击事件OnClickListener等等,由于监听器只是临时使用一次,没有什么服用价值,因此,编写代码中多使用匿名内部类的形式来实现。

java源码:

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });

相应的smali代码:

.method protected onCreate(Landroid/os/Bundle;)V
    .registers 4
    .param p1, \"savedInstanceState\"    # Landroid/os/Bundle;
    .prologue
    .line 12
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 13
    const v1, 0x7f09001c
    invoke-virtual {p0, v1}, Lcom/example/myapplication/MainActivity;->setContentView(I)V
    .line 15
    const v1, 0x7f070022
    invoke-virtual {p0, v1}, Lcom/example/myapplication/MainActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/Button;
    .line 16
    .local v0, \"button\":Landroid/widget/Button;
    #新建一个MainActivity$1实例
    new-instance v1, Lcom/example/myapplication/MainActivity$1; 
    invoke-direct {v1, p0}, Lcom/example/myapplication/MainActivity$1;-><init>(Lcom/example/myapplication/MainActivity;)V
    #设置按钮点击事件监听器
    invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
    .line 22
    return-void
.end method
MainActivity$1代码如下:
.class Lcom/example/myapplication/MainActivity$1;
.super Ljava/lang/Object;
.source \"MainActivity.java\"

# interfaces
.implements Landroid/view/View$OnClickListener;

# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lcom/example/myapplication/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation

# instance fields
.field final synthetic this$0:Lcom/example/myapplication/MainActivity;

# direct methods
.method constructor <init>(Lcom/example/myapplication/MainActivity;)V
    .registers 2
    .param p1, \"this$0\"    # Lcom/example/myapplication/MainActivity;

    .prologue
    .line 16
    iput-object p1, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method

# virtual methods
.method public onClick(Landroid/view/View;)V
    .registers 2
    .param p1, \"v\"    # Landroid/view/View;

    .prologue
    .line 20
    return-void
.end method

在MainActivity$1.smali文件的开头使用了“,implements”指令指定该类实现了按钮点击事件的监听器接口,因此,这个类实现了它的OnClick()方法,这时在分析程序时关心的地方。程序中的注解与监听器的构造函数都是编译器为我们自己生成的,实际分析过程中不必关心。

3)R.java

下面是R.java文件的一部分:

public final class R {
  public static final class anim {
    public static final int abc_fade_in=0x7f010000;
  }
}

由于这些资源文件类都是R类的内部类,因此他们都会独立生成一个类文件,在反编译出的代码中,可以发现有R.smali,R$attr.smali,R$dimen.smali,R$drawable.smali等等。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表