Samli文件详解

  1. 通过反编译工具反编译出来每个.smali,都对应与java中的一个类,每个smali文件都是Davilk指令组成的,并遵循一定的结构.smali存在很多的指令用于描述对应的java文件,所有的指令都以”.”开头,常用的指令如下:
    .filed 定义字段
    .method…end method 定义方法
    .annotation…end annotation 定义注解
    .implements 定义接口指令
    .local 指定了方法内局部变量的个数
    .registers 指定方法内使用寄存器的总数
    .prologue 表示方法中代码的开始处
    .line 表示java源文件中指定行
    .paramter 指定了方法的参数
    .param 和.paramter含义一致,但是表达格式不同

  2. 一个简单的例子

  3. 类定义:
    public class MainActivity extends AppCompatActivity{}
    如图所示,我们可以得出以下这些信息:
    1、这是一个公有的类。
    2、类名叫MainActivity。
    3、继承自AppCompatActivity.
    接下来,我们来看一下,反编译后,对应的Smali代码是什么样的。
    .class public Labc/hehe/MainActivity;
    .super Landroid/support/v7/app/AppCompatActivity;
    .source “MainActivity.java”
    如图所示,我们可以得出以下这些信息:
    1、.class表示,这是一个类,后面的public,代表其是公有的,即该类的访问权限。
    2、类名, 是以完整包名的形式展示的。
    3、.super表示,这是一个父类, 类名同样是,以完整包名的形式展示的。
    4、.source表示,该类所在的文件名为MainActivity.java。
    5、L,完整包名前的这个修饰符,表示这是一个对象类型。
    6、;,分号放于对象类型的结尾,类似于Java的一条语句的结尾,一样是必须的。
    从上所述,我们可以得出以下总结:
    1、.class <访问权限> <关键修饰字> <类名;>
    2、.super <关键修饰字> <父类名;>
    3、.source <源文件名>

  4. 成员变量(类字段)定义:
    smali java
    .field public booleanType:Z <-----> public boolean booleanType
    .field private stringType:/Ljava/land/String; <------> private String stringType;
    .field protected intType:I <--------> protected int intType;

  5. 方法的定义:
    private void onPrivateMethod(){

    }
    .method private onPrivateMethod()V.locals 0.prologue.line 27return-void
    .end method
    

指令集

  • 特点

    • 1 参数采用从目标到源的方式。

    • 2 根据字节码的大小与类型不同,一些字节码添加了名称后缀以消除歧义
      32位常规类型的字节码未添加任何后缀

         64常规类型的字节码添加 -wide 后缀特殊类型的字节码根据具体类型添加后缀。它们可以是 -boolean、-byte、-char、-short、 -int、-long、-float、-double、-object、-string、-void之一。
      
    • 3 根据字节码的布局与选项不同,一些字节码添加了字节码后缀以消除歧义。这些后缀通过在字节码主名称后缀添加斜杠“/”来分割开。

    • 4 在指令集的描述中,宽度值中每个字幕表示宽度为4位。
      举个例子: move-wide/from16 vAA, vBBBB
      该指令表示:move为基础字节码,标识这是基本操作。wide为名称后缀,标识指令操作的数据宽度(64位)。from16为字节码后缀(opcode suffix),标识源为一个16位的寄存器引用变量。vAA为目的寄存器,它始终在源的前面,取值范围为v0v255。vBBBB为源寄存器,取值范围为v0v65535。 指令集中大多数指令用到了寄存器作为目的操作数或源操作数,其中 A/B/C/D/E/F/G/H 代表一个4位的数值, 可用来表示v0~v15的寄存器。 AA/BB/…/HH代表一个8位的数值。 AAAA/BBBB/…/HHHH 代表一个16位的数值

  • 数据操作指令
    数据操作指令为move。move指令的原型为“move destination,source”,move指令根据字节码的大小与类型不同,后面会跟上不同的后缀。 eg:
    - “move vA, vB”:将vB寄存器的值赋给vA寄存器,源寄存器与目的寄存器都为4位。 - “move /from 16 VAA,VBBBB”:将VBBBB寄存器的值赋给VAA寄存器,源寄存器为16位,目标寄存器为8位 - “move /from 16 VAAAA,VBBBB”:将VBBBB寄存器的值赋给VAAAA,源寄存器和目标寄存器都为16位 - “move-wide vA, vB”:为4位的寄存器对赋值。源寄存器与目的寄存器都为4位 - “move-object vA,vB”:将vB寄存器中的对象引用赋值给vA寄存器,vA寄存器和vB寄存器都是4位 - “move-result vAA”:将上一个“invoke”(方法调用)指令,操作的单字(32位) - “move-result-wide vAA” :将上一个invoke指令操作的双字(64位)非对象结果赋值给vAA寄存器 - “mvoe-result-object vAA”:将上一个invoke指令操作的对象结果赋值给vAA寄存器 - “move-exception vAA”:保存上一个运行时发生的异常到vAA寄存器

  • 数据定义指令
    数据定义指令用来定义程序中用到的常量、字符串、类等数据。它的基础字节码为const。
    - const/4 vA,#+B 将数值符号扩展为32位后赋给寄存器 vA
    - const/16 vAA,#+BBBB 将数值符号扩展为32位后赋给寄存器 vAA
    - const vAA,#+BBBBBBBB 将数值赋给寄存器vAA
    - const/high16 vAA,#+BBBB0000 将数值右边 0 扩展为32位后赋给寄存器vAA
    - const-wide/16 vAA,#+BBBB 将数值符号扩展64位后赋给寄存器对vAA
    - const-wide vAA,#+BBBBBBBBBBBBBBBB 将数值赋给寄存器对vAA
    - const-wide/high16 vAA,#+BBBB000000000000 将数值右边 0 扩展为64位后付赋值给寄存器 vAA
    - const-string vAA,string@BBBB 通过字符串索引构造一个字符串并赋给寄存器对 vAA
    - const-string/jumbo vAA,string@BBBBBBBB 通过字符串索引(较大) 构造一个字符串并赋值给寄存器对vAA
    - const-class vAA,type@BBBB 通过类型索引获取一个类引用并赋值给寄存器 vAA
    - const-class/jumbo vAAAA,type@BBBBBBBB 通过给定的类型那个索引获取一个类索引并赋值给寄存器vAAAA(这条指令占用两个字节,值为0x00ff,是Android4.0中新增的指令)

  • 数据返回指令
    返回指令指的是函数结尾时运行的最后一条指令。它的基础字节码为return,共有以下四条返回指令:
    - “return-void”:表示什么也不返回 - “return vAA”:表示函数返回一个32位非对象类型的值 - “return-wide vAA”:表示函数返回一个64位非对象类型的值 - “return-object vAA”:表示函数返回一个对象类型的值

  • 数组操作指令
    数组操作包括读取数组长度、新建数组、数组赋值、数组元素取值与赋值等操作。
    - array-length vA,vB 获取给定vB寄存器中数组的长度并将值赋给vA寄存器,数组长度指的是数组的条目个数。 - new-array vA,vB,type@CCCC 构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器。 - new-array/jumbo vAAAA,vBBBB,type@CCCCCCCC 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大(Android4.0中新增的指令) - filled-new-array {vC,vD,vE,vF,vG},type@BBBB 构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还制订了参数的个数,vC~vG是使用到的参数寄存器序列 - filled-new-array/range {vCCCC, … ,vNNNN},type@BBBB 指定功能与上一条指令相同,只是参数寄存器使用range字节码后缀指定了取值范围,vC是第一个参数寄存器, N=A+C-1。 - filled-new-array/jumbo {vCCCC, … ,vNNNN},type@BBBBBBBB 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大(Android4.0中新增的指令) - fill-array-data vAA, +BBBBBBBB 用指定的数据来填充数组,vAA寄存器为数组引用,引用必须为基础类型的数组,在指令后面会紧跟一个数据表 - arrayop vAA,vBB,vCC 对vBB寄存器指定的数组元素进入取值与赋值。vCC寄存器指定数组元素索引,vAA寄存器用来寄放读取的或需要设置的数组元素的值。读取元素使用aget类指令,元素赋值使用aput指令,元素赋值使用aput类指令,根据数组中存储的类型指令后面会紧跟不同的指令后缀,指令列表有aget、aget-wide、aget-object、aget-boolean、aget-byte、aget-char、aget-short、aput、aput-wide、aput-boolean、aput-byte、aput-char、aput-short。

  • 数据转换指令
    数据转换指令用于将一种类型的数值转换成另一种类型,它的格式为 unop vA,vB 。 vB寄存器或vB寄存器对存放需要转换的数据,转换后的结果保存在vA寄存器或vA寄存器对中。
    neg-int 对整型数求补
    not-int 对整型数求反
    neg-long 对长整型求补
    not-long 对长整型求反
    neg-float 对单精度浮点型数求补
    neg-double 对双精度浮点型数求补 int-to-long 将整型数转换为长整型 int-to-float 将整型数转换为单精度浮点型 int-to-double 将整型数转换为双精度浮点型 long-to-int 将长整型数转换为整型 long-to-float 将长整型数转换为单精度浮点型 long-to-double 将长整型数转换为双精度浮点型 float-to-int 将单精度浮点型数转换为整型 float-to-long 将单精度浮点型数转换为长整型 float-to-double 将单精度浮点型数转换为双精度浮点型 double-to-int 将双精度浮点型数转换为整型 double-to-long 将双精度浮点型数转换为长整型 double-to-float 将双精度浮点型数转换为单精度浮点型 int-to-byte 将整型转换为字节型 int-to-char 将整型转换为字符串 int-to-short 将整型转换为短整型

  • 数据运算指令
    数据运算指令包括算术运算指令与逻辑运算指令。算术运算指令主要进行数值间如加、减、乘、除、模、移位等运算,逻辑运算主要进行数值间与、或、非、异或等运算。数据运算指令有如下四类(数据运算时可能在寄存器或寄存器对间进行,下面的指令作用讲解时使用寄存器来描述):
    binop vAA,vBB,vCC 将vBB寄存器与vCC寄存器进行运算,结果保存到vAA寄存器
    binop/2addr vA,vB 将vA寄存器与vB寄存器进行运算,结果保存到vA寄存器
    binop/lit16 vA,vB,#+CCCC 将vB寄存器与常量CCCC进行运算,结果保存到vA寄存器
    binop/lit8 vAA,vBB,#+CC 将vBB寄存器与常量CC进行运算,结果保存到vAA寄存器
    后面3类指令比第1类指令分别多了addr、lit16、lit8等指令后缀。四类指令中基础字节码后面加上数据类型后缀,如-int或-long分别表示操作的数据类型那个为整型与长整型。第1类指令可归类如下:
    add-type vBB寄存器与vCC寄存器值进行加法运算(vBB + vCC)
    sub-type vBB寄存器与vCC寄存器值进行减法运算(vBB - vCC)
    mul-type vBB寄存器与vCC寄存器值进行乘法运算(vBB * vCC)
    div-type vBB寄存器与vCC寄存器值进除法运算(vBB / vCC)
    rem-type vBB寄存器与vCC寄存器值进行模运算(vBB % vCC)

      and-type     vBB寄存器与vCC寄存器值进行与运算(vBB  & vCC)or-type     vBB寄存器与vCC寄存器值进行或运算(vBB  | vCC)xor-type     vBB寄存器与vCC寄存器值进行异或运算(vBB  ^ vCC)shl-type     vBB寄存器(有符号数)左移vCC位(vBB << vCC)shr-type     vBB寄存器(有符号数)右移vCC位(vBB >> vCC)ushr-type     vBB寄存器(无符号数)右移vCC位(vBB >> vCC)其中基础字节码后面的-type可以是-int、-long、-float、-double。后面3类指令与之类似。
    
  • 对象操作指令
    与对象实例相关的操作,比如对象创建,对象检查等.
    - new-instance vAA,type@BBBB 构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器,类型符号type指定的类型不能是数组类。
    - instance-of vA,vB,type@CCCC 判断vB寄存器中的对象引用是否可以转换成指定的类型,如果可以vA寄存赋值为1,否则vA寄存器为0
    - check-cast vAA,type@BBBB 将vAA寄存器中对象的引用转成指定类型,成功则将结果赋值给vAA,否则抛出ClassCastException异常.

  • 跳转指令
    跳转指令用于从当前地址跳转到指定的偏移处。Dalvik指令集中有三种跳转指令:无条件跳转(goto),分支跳转(switch)与条件跳转(if)。
    goto +AA 无条件跳转到指定偏移处,偏移量AA不能为0
    goto/16 +AAAA 无条件跳转到指定偏移处,偏移量AAAA不能为0。 goto/32 +AAAAAAAA 无条件跳转到指定偏移处。
    packed-switch vAA,+BBBBBBBB 分支跳转指令。vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个packed-switch-payload格式的偏移表,表中的值是有规律递增的。
    sparse-switch vAA,+BBBBBBBB 分支跳转指令。vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个sparse-switch-payload格式的偏移表,表中的值是无规律的偏移表,表中的值是无规律的偏移量。 if-test vA,vB,+CCCC 条件跳转指令。比较vA寄存器与vB寄存器的值,如果比较结果满足就跳转到CCCC指定的偏移处。偏移量CCCC不能为0。if-test类型的指令有以下几条:
    if-eq 如果vA不等于vB则跳转。Java语法表示为 if(vA == vB)
    if-ne 如果vA不等于vB则跳转。Java语法表示为 if(vA != vB)
    if-lt 如果vA小于vB则跳转。Java语法表示为 if(vA < vB)
    if-le 如果vA小于等于vB则跳转。Java语法表示为 if(vA <= vB)
    if-gt 如果vA大于vB则跳转。Java语法表示为 if(vA > vB)
    if-ge 如果vA大于等于vB则跳转。Java语法表示为 if(vA >= vB) if-testz vAA,+BBBB 条件跳转指令。拿vAA寄存器与 0 比较,如果比较结果满足或值为0时就跳转到BBBB指定的偏移处。偏移量BBBB不能为0。 if-testz类型的指令有一下几条:
    if-nez 如果vAA为 0 则跳转。Java语法表示为 if(vAA == 0)
    if-eqz 如果vAA不为 0 则跳转。Java语法表示为 if(vAA != 0)
    if-ltz 如果vAA小于 0 则跳转。Java语法表示为 if(vAA < 0)
    if-lez 如果vAA小于等于 0 则跳转。Java语法表示为 if(vAA <= 0)
    if-gtz 如果vAA大于 0 则跳转。Java语法表示为 if(vAA > 0)
    if-gez 如果vAA大于等于 0 则跳转。Java语法表示为 if(vAA >= 0)

  • 比较指令

    ** 比较指令用于比较两个寄存器中值的大小,其基本格式格式是cmp+kind-type vAA,vBB,vCC,type表示比较数据的类型,如-long,-float等;kind则代表操作类型,因此有cmpl,cmpg,cmp三种比较指令.coml是compare less的缩写,cmpg是compare greater的缩写,因此cmpl表示vBB小于vCC中的值这个条件是否成立,是则返回1,否则返回-1,相等返回0;cmpg表示vBB大于vCC中的值这个条件是否成立,是则返回1,否则返回-1,相等返回0. cmp和cmpg的语意一致,即表示vBB大于vCC寄存器中的值是否成立,成立则返回1,否则返回-1,相等返回0 **

    eg:

      cmpl-float vAA,vBB,vCC    比较两个单精度的浮点数.如果vBB寄存器中的值大于vCC寄存器的值,则返回-1到vAA中,相等则返回0,小于返回1cmpg-float vAA,vBB,vCC    比较两个单精度的浮点数,如果vBB寄存器中的值大于vCC的值,则返回1,相等返回0,小于返回-1cmpl-double vAA,vBB,vCC    比较两个双精度浮点数,如果vBB寄存器中的值大于vCC的值,则返回-1,相等返回0,小于则返回1cmpg-double vAA,vBB,vCC    比较双精度浮点数,和cmpl-float的语意一致cmp-double vAA,vBB,vCC    等价与cmpg-double vAA,vBB,vCC指令
    
  • 字段操作指令

    字段操作指令表示对对象字段进行设值和取值操作,就像是你在代码中长些的set和get方法.基本指令是iput-type,iget-type,sput-type,sget-type.type表示数据类型.

      *前缀是i的iput-type和iget-type指令用于普通字段的读写操作.*iget-byte vA,vB,filed_id         读取vB寄存器中的对象中的filed_id字段值赋值给vA寄存器iput-byte vA,vB,filed_id         设置vB寄存器中的对象中filed_id字段的值为vA寄存器的值iget-boolean vA,vB,filed_id    iput-boolean vA,vB,filed_id    iget-long vA,vB,filed_id    iput-long vA,vB,filed_id    前缀是s的sput-type和sget-type指令用于静态字段的读写操作sget-byte vA,vB,filed_id    sput-byte vA,vB,filed_id    sget-boolean vA,vB,filed_id    sput-boolean vA,vB,filed_id    sget-long vA,vB,filed_id    sput-long vA,vB,filed_id
    
  • 方法调用指令
    Davilk中的方法指令和JVM的中指令大部分非常类似.目前共有五条指令集:
    invoke-direct{parameters},methodtocall 调用实例的直接方法,即private修饰的方法.此时需要注意{}中的第一个元素代表的是当前实例对象,即this,后面接下来的才是真正的参数.比如指令invoke-virtual {v3,v1,v4},Test2.method5:(II)V中,v3表示Test2当前实例对象,而v1,v4才是方法参数
    invoke-static{parameters},methodtocall 调用实例的静态方法,此时{}中的都是方法参数
    invoke-super{parameters},methodtocall 调用父类方法
    invoke-virtual{parameters},methodtocall 调用实例的虚方法,即public和protected修饰修饰的方法
    invoke-interface{parameters},methodtocall 调用接口方法

      这五种指令是基本指令,除此之外,你也会遇到invoke-direct/range,invoke-static/range,invoke-super/range,invoke-virtual/range,invoke-interface/range指令,该类型指令和以上指令唯一的区别就是后者可以设置方法参数可以使用的寄存器的范围,在参数多于四个时候使用.再此强调一遍对于非静态方法而言{}的结构是{当前实例对象,参数1,参数2,…参数n},而对于静态方法而言则是{参数1,参数2,…参数n}
    

    如果要获取方法执行有返回值,需要通过上面说道的move-result指令获取执行结果.

  • 同步指令
    同步一段指令序列通常是由java中的synchronized语句块表示,则JVM中是通过monitorenter和monitorexit的指令来支持synchronized关键字的语义的,而在Davilk中同样提供了两条类似的指令来支持synchronized语义:
    monitor-enter vAA 为指定对象获取锁操作
    monitor-exit vAA 为指定对象释放锁操作

  • 异常指令
    throw vAA 抛出vAA寄存器中指定类型的异常

smali语法快速入门相关推荐

  1. python编程基础语法-Python编程基础语法快速入门

    1. 课程咨询加老师助理微信:助理1微信: chenjinglei88 ,助理2微信: omf6757 2. 决定购买并想得到陈敬雷老师亲自指导(课程或自己项目难题均可)加老师微信: chenjing ...

  2. python编程语法教程-Python编程基础语法快速入门

    1. 课程咨询加老师助理微信:助理1微信: chenjinglei88 ,助理2微信: omf6757 2. 决定购买并想得到陈敬雷老师亲自指导(课程或自己项目难题均可)加老师微信: chenjing ...

  3. Thymeleaf 语法快速入门

    1.简介 官方网站:https://www.thymeleaf.org Thymeleaf是用来开发Web和独立环境项目的现代服务器端Java模板引擎. Thymeleaf的主要目标是为您的开发工作流 ...

  4. python基础语法入门大全_python 基础语法——快速入门

    今天来讲一些老生常谈,但凡学习一门语言都逃不过基本的语法,我们也来叨逼叨逼.不过不想事无巨细地讲,因为没有意义,估计讲完了大家都忘记了,我们挑钟爱你,其他的可以自学. 变量,学习一门语言第一件事可能是 ...

  5. Object+C语法快速入门

    大部分有一点其他平台开发基础的初学者看到XCode,第一感想是磨拳擦掌,看到Interface Builder之后,第一感想是跃跃欲试,而看到Objective-C的语法,第一感想就变成就望而却步了. ...

  6. [Markdown语法][快速入门][CSDN]

    Markdown语法 Markdown学习资料 [使用建议] 快捷键 目录 标题 文本样式 列表 链接 代码片 表格 注释 & 注脚 自定义列表 LateX数字公式 插入甘耐图 插入UML图 ...

  7. Object C语法快速入门

    转载来源于: http://www.cocoachina.com/newbie/tutorial/2009/0611/150.html 大部分有一点其他平台开发基础的初学者看到XCode,第一感想是磨 ...

  8. JavaScript基础语法快速入门

    文章目录 基础语法 JavaScript的位置 预前知识 注释 原则 字面量.变量.标识符 Unicode编码 数据类型 字符串 数值 布尔值 NULL UNDEFINED 强制转换String 强制 ...

  9. 英语语法快速入门4--定语与定语从句(附思维导图)

    文章目录 4.定语和定语从句 4.1 什么是定语? 4.2 定语的成份? 4.3定语的位置? 4.4 定语从句 4.5 写作中定语和定语从句使用建议 写在前面 关于参考材料:本系列博客参考刘晓艳老师的 ...

最新文章

  1. python脚本获取内网,公网ip
  2. react项目中使用mocha结合chai断言库进行单元测试
  3. any() missing 1 required positional arguments: dim
  4. [codevs 1904] 最小路径覆盖问题
  5. CMM (软件工程与集成产品开发)
  6. 【要闻】Kubernetes安全问题严峻、Linux v5.4安全性浅谈
  7. 【Python】一些函数
  8. VS2008中开发Silverlight 2.0的配置
  9. 收藏10个2012年最新发布的jQuery插件
  10. nparray和tensor的相互转化
  11. mysql面向对象例子_PHP 面向对象实例:获取数据库用户数据
  12. google海底光缆图_感受技术震撼:全球海底光缆分布图详解(附源地图链接)
  13. 在Windows上使用MSVC编译QuaZip
  14. C#递归拷贝文件夹下文件以及文件夹
  15. gvim下用Vundle安装solarized主题的方法
  16. R与Python或协同助力机器学习:听Azure ML Studio讲座有感
  17. php验证码刷新_php实现点击可刷新验证码
  18. PS3主机数据完全一览及关键词解释
  19. 解除Windows XP IIS 10个并发连接数的限制
  20. 西游记中的袁守诚的真实身份是谁?为何能知玉帝谕旨?

热门文章

  1. 特斯拉砍掉挡杆,自动驾驶已经开始改变人类?
  2. 一张白纸有了一个黑点
  3. js 打印(JavaScript 打印 CSS样式)
  4. CSDN下载积分攻略(转载)
  5. 手机玩exe游戏的模拟器_使命召唤手游模拟器和手机一起玩怎么样 拟器和手机一览_使命召唤手游...
  6. C#:字符串的常用API汇总
  7. Android版本与过高的JDK版本不兼容问题
  8. c语言-scanf里面不要加空格,逗号等
  9. 【微信公众号】2. 微信公众号申请注册流程
  10. android 关于破损图片判断,处理