smali文件格式分析

smali文件是apktool将dex文件解析成更直观易读的一种文件形式。除了apktool之外,baksmali工具也可以将dex文件转为smali文件。
今天就来学习一下smali文件的格式,让我们可以读懂smali代码。

编辑生成简单的待测试的apk

我们做一个简单的测试apk,页面就一个输入框,一个按钮,点击按钮,将输入框中的内容用Toast展示出来。
代码如下:

package cn.codekong.hello;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private static int count = 0;
    private String name = "name";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText inputEd = findViewById(R.id.ed_input);
        Button clickBtn = findViewById(R.id.btn_click);

        clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, inputEd.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

编译生成一个debug版本的apk备用。

逆向apk为smali文件

使用如下命令来逆向apk获得smali文件。

apktool d xxx.apk

在生成的目录下找到smali文件夹,里面会按程序的目录层次放置生成的smali文件。这里需要注意的是,普通类、抽象类、接口和内部类都会被反编译成单独的smali文件。

我们打开smali文件夹中的MainActivity.smali文件进行分析,内容如下:

.class public Lcn/codekong/hello/MainActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "MainActivity.java"


# static fields
.field private static count:I


# instance fields
.field private name:Ljava/lang/String;


# direct methods
.method static constructor <clinit>()V
    .locals 1

    .prologue
    .line 11
    const/4 v0, 0x0

    sput v0, Lcn/codekong/hello/MainActivity;->count:I

    return-void
.end method

.method public constructor <init>()V
    .locals 1

    .prologue
    .line 10
    invoke-direct {p0}, Landroid/support/v7/app/AppCompatActivity;-><init>()V

    .line 12
    const-string/jumbo v0, "name"

    iput-object v0, p0, Lcn/codekong/hello/MainActivity;->name:Ljava/lang/String;

    return-void
.end method


# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 3
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    .line 15
    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    .line 16
    const v2, 0x7f09001b

    invoke-virtual {p0, v2}, Lcn/codekong/hello/MainActivity;->setContentView(I)V

    .line 18
    const v2, 0x7f070030

    invoke-virtual {p0, v2}, Lcn/codekong/hello/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v1

    check-cast v1, Landroid/widget/EditText;

    .line 19
    .local v1, "inputEd":Landroid/widget/EditText;
    const v2, 0x7f070023

    invoke-virtual {p0, v2}, Lcn/codekong/hello/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/Button;

    .line 21
    .local v0, "clickBtn":Landroid/widget/Button;
    new-instance v2, Lcn/codekong/hello/MainActivity$1;

    invoke-direct {v2, p0, v1}, Lcn/codekong/hello/MainActivity$1;-><init>(Lcn/codekong/hello/MainActivity;Landroid/widget/EditText;)V

    invoke-virtual {v0, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    .line 27
    return-void
.end method
文件头

最前面3行格式如下:

.class <访问权限> [修饰关键字] <类名>
.super <父类名>
.source <源文件名>

上面的<访问权限>指类访问权限修饰符,<修饰关键字>是Dalvik字节码的一种约定,具体约定如下:
Dalvik字节码有两种类型,原始类型和引用类型,同时引用类型又包括对象和数组,下面通过表格来说明。

类型关键字类型关键字
voidVintI
booleanZbyteB
shortScharC
longJfloatF
doubleD对象L

对于数组类型,则使用 [ 和上面的类型进行组合,比如下面

//int数组 int[]
[I
//String数组 String[]
[L java/lang/String
方法

下面的内容部分也解释一下:

# 表示之后的内容为注释,是apktool为我们添加的

.line n 表示该内容在源码中的行数

.method和.end method 表示一个方法的开始和结束
方法又分为direct methods和virtual methods两种。
direct methods的声明格式为

.method <访问权限> [修饰关键字] <方法原型>
.locals <局部变量个数>
.param <方法的参数>
.prologue
.line
代码体
.end method

上面的<方法原型>包括方法的名称、参数和返回值(这里的返回值形式为类型的首字母大写[V表示void])。
上面的.prologue表示代码的开始。

成员变量

除了方法,还有成员变量,成员变量又分为静态成员变量和实例变量。
静态成员变量的声明格式

# static fields
.field private static count:I

.field <访问权限> static [修饰关键字] <字段名>:<字段类型>

实例成员变量的声明格式

# instance fields
.field private name:Ljava/lang/String;

.field <访问权限> [修饰关键字] <字段名>:<字段类型>
接口

接口的格式

.implements <接口名>
注解

注解的格式
.annotation [注解属性] <注解类名>
[注解字段 = 值]
.end annotation

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页