Smali语法

Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组)。

原始类型:

  • V void 只能用于返回值类型
  • Z boolean
  • B byte
  • S short
  • C char
  • I int
  • J long(64位)
  • F float
  • D double(64位)

对象类型:

表示方法:Lpackage/name/ObjectName;

相当于java中的package.name.ObjectName;

解释如下:

  • L 表示这是一个对象类型
  • package/name 该对象所在的包
  • ; 表示对象名称的结束

数组

表示形式:

  • [I表示一个整形的一维数组,相当于java的int[];
  • 对于多维数组,只要增加[就行了,[[I = int[][];
  • 每一维最多255个。

方法

表示形式: Lpackage/name/ObjectName;——>methodName(III)Z

详解如下:

  • Lpackage/name/ObjectName表示类型
  • methodName表示方法名
  • III表示参数(这里表示为3个整型参数)

说明:方法的参数是一个接一个的,中间没有隔开;

一个更复杂的例子:

method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

在java中则为:

String method(int, int\[][], int, String, Object[])

字段

表示形式:

Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

即包名,字段名和各字段类型。

寄存器

在dalvik字节码中,寄存器都是32位的,能够支持任何类型。64位类型(Long和Double型)用2个寄存器表示。

有两种方式指定一个方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的总数。.locals指令表明了方法中非参寄存器的数量。

方法的传参

当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。如果一个方法有2个参数,5个寄存器(v0-v4),那么参数将置于最后2个寄存器——v3和v4。

非静态方法中的第一个参数总是调用该方法的对象。

例如,非静态方法LMyObject;->callMe(II)V有2个整型参数,另外还有一个隐含的LMyObject;参数,所以总共有3个参数。假如在该方法中指定了5个寄存器(v0-v4),以.registers方式指定5个或以.locals方式指定2个(即2个local寄存器+3个参数寄存器)。当该方法被调用的时候,调用该方法的对象(即this引用)存放在v2中,第一个整型参数存放在v3中,第二个整型参数存放在v4中。

对于静态方法除了没有隐含的this参数外其它都一样。

寄存器的命名方式

有两种方式——V命名方式和P命名方式。P命名方式中的第一个寄存器就是方法中的第一个参数寄存器。在下表中我们用这两种命名方式来表示上一个例子中有5个寄存器和3个参数的方法。

v0      第一个local register
v1      第二个local register
v2  p0  第一个parameter register
v3  p1  第二个parameter register
v4  p2  第三个parameter register

你可以用任何一种方式来引用参数寄存器——他们没有任何差别。

注意:baksmali默认对参数寄存器使用P命名方式。如果想使用V命名方式,可以使用-pl—no-parameter-registers选项。

使用P命名方式是为了防止以后如果要在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点。

Long/Double值

Long和double类型是64位的,需要2个寄存器(切记切记)。

例如,对于非静态方法LMyObject;->MyMethod(IJZ)V,参数分别是LMyObject;intlongbool。故该方法需要5个寄存器来存储参数。

p0  this
p1  I
p2, p3  J
p4  Z

补充

# static fields        定义静态变量的标记
# instance fields      定义实例变量的标记
# direct methods       定义静态方法的标记
# virtual methods      定义非静态方法的标记

构造函数的返回类型为V,名字为<init>

if-eq p1, v0, :cond_8表示如果p1和v0相等,则执行cond_8的流程:

:cond_8
invoke-direct {p0}, Lcom/paul/test/a;->d()V

调用com.paul.test.a的d()方法

if-ne p1, v0, :cond_b表示不相等则执行cond_b的流程:

:cond_b
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
move-result v0

大概意思就是调用com.paul.test.asetPressed方法,然后再调用父类ViewonKeyUp方法,最后return v0

参考

点这里查看所有指令。