SMALI学习笔记 by vrix.yan
文章目录
1. 基本语法
1.1 数据类型
Z,B,S,C,I,L,F,D为基本数据类型,从上表可以看出,Dalvik字节码基本类型的描述符基本上是java基本类型的首字母,除了boolean对应为Z外
1.2 对象类型
L加上类或者接口的全称表示对象类型,即Lpackage/objectName,如String类型描述符为Ljava/lang/String,包com.biyou下面的test类的类型描述符为Lcom/biyou/test
##1.3 数组类型
基本类型的数组为”[“加上基本类型描述符来表示,一维数组前面是一个”[“,多一个维度前面多加一个”[“,比如int类型,一维是:[I,二维是:[[I,依次类推。
对象类型的数组为”[“加上对象类型表示符来表示,如String类型表示为:[Ljava/lang/String。
1.4 语法关键词
关键词 说明
.class 定义java类名
.super 定义父类名
.source 定义Java源文件名
.filed 定义字段
.method 定义方法开始
.end method 定义方法结束
.annotation 定义注解开始
.end annotation 定义注解结束
.implements 定义接口指令
.local 指定了方法内局部变量的个数
.registers 指定方法内使用寄存器的总数
.prologue 表示方法中代码的开始处
.line 表示java源文件中指定行
.paramter 指定了方法的参数
.param 和.paramter含义一致,但是表达格式不同
2. smali中的包信息
.class public Lcom/a;
.super Lcom/b;
.source "c.java"
这是一个由c.java编译得到的smail文件。他是com.a这个包下的一个类,继承自com.b这个类。
3. smali中的声明
# annotations
.annotations system Ldalvik/annotation/MemberClasses;
value={
Lcom/a$z;
Lcom/a$x;
}
.end annotation
这个模块是内部类的声明,a这个类中有两个成员内部类:z和x。
4. 成员变量
4.1 定义
成员变量定义格式为:
.field public/private [static][final] varName:<类型>
获取指令
iget, sget, iget-boolean, sget-boolean, iget-object, sget-object
操作指令
iput, sput, iput-boolean, sput-boolean, iput-object, sput-object
array的操作是aget和aput
指令解析
sget-object v0,Lcom/aaa;->ID:Ljava/lang/String;
获取ID这个String类型的成员变量并放到v0这个寄存器中
iget-object v0,p0,Lcom/aaa;->view:Lcom/aaa/view;
iget-object比sget-object多一个参数p0,这个参数代表变量所在类的实例。这里p0就是this
Smali代码示例1:
const/4 v3, 0x0
sput-object v3, Lcom/aaa;->timer:Lcom/aaa/timer;
相当于java代码:this.timer = null;
Smali代码示例2:
.local v0, args:Landroid/os/Message;
const/4 v1, 0x12
iput v1,v0,Landroid/os/Message;->what:I
相当于java代码:args.what = 18;
其中args为Message的实例
4.2 普通字段读写操作
前缀是i的iput-type和iget-type指令用于字段的读写操作.
指令 | 描述 |
---|---|
iget-object vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器 |
iget-boolean vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
iget-wide vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
iget vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
iput-object vAA,vBB,filed_id | 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象 |
iput-boolean vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的boolean类型 |
iput-wide vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的wide类型 |
iput vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的int类型 |
4.3 静态字段读写操作
前缀是s的sput-type和sget-type指令用于静态字段的读写操作
指令 | 描述 |
---|---|
sget-object vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id对象的引用值给vBB寄存器 |
sget-boolean vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
sget-wide vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
sget vAA,vBB,filed_id | 读取vAA寄存器中的对象中的filed_id的值给vBB寄存器 |
sput-object vAA,vBB,filed_id | 把vAA寄存器指向的对象的引用赋值给vBB寄存器中的filed_id对象 |
sput-boolean vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的boolean类型 |
sput-wide vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的wide类型 |
sput vAA,vBB,filed_id | 把vAA寄存器的值给vBB寄存器中的int类型 |
5. smali寄存器
在虚拟机Dalvik中,方法中有两种方式定义方法中可以使用的寄存器数量。.registers 指令定义了方法中可以使用的寄存器的总数量。可以选择性的使用.locals ,该指令定义了方法中非参数寄存器的数量。寄存器的总数量应当包括方法参数所使用的寄存器的数量
v字命名 p字命名 说明
v0 the first local register
v1 the sencond local register
v2l p0 the first paramter register
v3 p1 the second parameter register
v4 p2 the third parameter register
在smail中所有的操作都必须经过寄存器来进行。本地寄存器用v来表示,例如v0,v1,v2等。参数寄存器用p来表示,例如p0,p1,p2等。特别的一点是,p0并不一定是函数中的第一个参数,在非静态方法中,它指代“this”,p1表示函数的第一个参数。而在静态方法中,p0就是函数的第一个参数。
寄存器的表示
const/4 v0,0x1
iput-boolean v0,p0,Lcom/a;->isTrue:Z
上面的代码块首先使用了v0本地寄存器,并把值0x1存到v0中,第二句用iput-boolean这个指令把v0中的值存放到com.a.isTrue这个成员变量中,即:this.isTrue=true;。
6. 指令
6. 1 赋值指令
move(move destination)。
move va,vb #将va=vb
move/from16 va,vb # va=vb va(为8位寄存器) vb(为16位寄存器)
move-result vaa #将上一个invoke类型指令操作的单字非对象结果返回给vaa
move-result-object vaa #将上一个invoke类型指令操作的对象结果返回给vaa
move-exception vaa #保存一个运行时发生的异常到vaa
throw vaa #抛出vaa寄存器的异常
6.2 定义指令
数据定义指令用来定义程序中用到的常量、字符串、类等。
基础字节码为const
const/4 va,#+b #将数值符号扩展为32位后赋值给寄存器va
const/16 vaa,#+bbbb #将数值符号扩展为32位后赋值给寄存器vaa
const va,#+bbbbbbb #将数值赋值给寄存器va
const/high16 vaa,#+bbbb #将数值右边零扩展为32位后赋值给寄存器vaa
const-wide/16 vaa,#+bbbb #将数值符号扩展为64位后赋值给寄存器vaa
const-string vaa,string@bbb #将字符串赋值给寄存器vaa
指令 | 描述 |
---|---|
const/4 vA,#+B | 将数值符号扩展为32后赋值给寄存器vA |
const/16 vAA, #+BBBB | 将数据符号扩展为32位后赋给寄存器vAA |
const vAA, #+BBBBBBBB | 将数值赋给寄存器vAA |
const/high16 vAA, #+BBBB0000 | 将数值右边零扩展为32位后赋给寄存器vAA |
const-wide/16 vAA,#+BBBB | 将数值符号扩展为64位后赋值个寄存器对vAA |
const-wide/32 vAA,#+BBBB | 将数值符号扩展为64位后赋值个寄存器对vAA |
const-wide vAA, #+BBBBBBBBBBBBBBBB | 将数值赋给寄存器对vAA |
const |