【翻译】apk反汇编之smali语法

转自看雪http://bbs.pediy.com/showthread.php?p=1117963


类型


Dalvik的字节码中拥有两个主要的类型:基类和引用类型。引用类型


引用类型是对象和数组,其他的一切都是基类
 
基类被一个简单的字符描述。我没有提出这些缩写词———他们实际以字符串的形式存储于dex文件中
他们被定义与dex格式网页文档中(在AOSP库中的路径是dalvik/docs/dex-format.html)
V  空类型---仅仅可以用来作为返回类型
Z  Boolean 布尔型
B  Byte字节型
S  Short短整型(16位)
C  Char字符型
I  Int 整形
J  long (64 bits)长整型(64位)
F  Float浮点型
D  double (64 bits)双精度型(64位)

对象采用这样的形式Lpackage/name/ObjectName---开始的L表明这是一个对象类型,package/name/就是该对象,对象名是是对象的名称,并且分号表明对象名的结束。这个等同于java语言中的package.name.ObjectName结构,举个更具体的例子,“ Ljava/lang/String;”就等同于java语言的“java.lang.String”。数组采用[I的形式—这代表一个一维整形数组就像java语言中的int[]。而多维数组,你简单的增加字符‘[’就行了,例如[[I=int[][](最大的维度是255).你也可以使用数组对象,例如[Ljava/lang/String就是一个字符串数组。

方法

方法总是被定义为一个非常复杂的包括方法,方法名,参数类型和返回值的形式。

所有的这些信息被要求对于虚拟机而言可以找到正确的方法并且能够表现字节码上的静态分析(为了确认挥着选择最优化)。他们采用如下形式
Lpackage/name/ObjectName;->MethodName(III)Z
在这个例子中,你应该识别出“ Lpackage/name/ObjectName; 是一个类, MethodName明显是一个方法名,(III)Z是方法的签名,‘III’在这个例子中是三个整形参数,Z是表示返回一个布尔类型的返回值。

They take the form
Lpackage/name/ObjectName;->MethodName(III)Z
In this example, you should recognize Lpackage/name/ObjectName; as a type. MethodName is obviously the name of the method. (III)Z is the method's signature. III are the parameters (in this case, 3 ints), and Z is the return type (bool).
方法的参数一个接一个的列举在右边,中间没有分号。给出一个更复杂的例子:
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位可以存放任何类型的值,2个寄存器可以用来存放64位类型(长整形和双精度型)

指定方法中的寄存器数字

这里有两种办法来指定一种方法中的多个寄存器。寄存器直接指定方法中的寄存器总数,或者区域变量直接指定方法中的非参数寄存器数。寄存器总数包括方法中参数所需的所有寄存器。

多少参数传入方法

当一个方法被调用,方法中的参数被放置到最近的几个寄存器。如果一个方法拥有两个参数和五个寄存器,这些参数会被存放到最后的两个寄存器V3和V4.

动态方法的第一个参数总是被调用的第一个对象,例如让你写一个动态方法 LMyObject;->callMe(II)V,这个方法有两个整形参数,但是还有一个隐含的参数‘LMyObject’在两个整形参数之前,所以总共有三个参数在这个方法中。

我们假设你在一个方法中制定了5个寄存器(v0-v4),既不是寄存器5管理也不是本地寄存器2管理(2个本地寄存器和3个参数寄存器)

当该方法被调用后,被调用的对象是V2,第一个整型参数是V3,第二个是V4。在静态方法中也是同样的,除非没有隐含的this指针参数。

寄存器名称

对于寄存器这里有两种命名方案—标准的V命名方案和对于参数寄存器的P命名方案。

以p命名的第一个寄存器就是方法中的第一个参数寄存器,所以让我们回到之前的总共拥有5个寄存器其中3个参数的例子。下表中显示了为每个寄存器的标准v命名,紧接着是为参数寄存器的p命名
 
v0     the first local register
第一个本地寄存器
v1     the second local register
第二个本地寄存器
v2  p0  the first parameter register
第一个参数寄存器
v3  p1  the second parameter register
第二个参数寄存器
v4  p2  the third parameter register
第三个参数寄存器

你可以通过每个名称类参照参数寄存器—这没有什么两样

p命名方案是作为一个实用的内容被引入的来解决编辑smali编码中的共同的难点。

假设你有一个已经存在的方法拥有一定数目的参数,你想增加一些代码到这个方法,你会发现你需要一个额外的寄存器。

你会想,没什么大不了的,我仅仅在寄存器管理中增加寄存器数目就可以了。但是不幸的是,这并不容易。请记住方法中的参数是寄存在最近的寄存器中的。如果你增加寄存器数—你会改变方法参数的在寄存器中的输入。所以你就不得不改变寄存器管理并且重编号参数寄存器

但是如果是你在方法中使用p命名模式来引用参数寄存器,你可以很容易的改变方法中的寄存器数而不必担心重编号任何存在的寄存器。

注意:默认baksmali对于参数寄存器使用p命名模式来命名。如果你因为某些原因不适用p命名而强制使用V命名模式,你可以使用-p/--no-parameter-registers来选择。
Long/Double values
长整型/双精度型值

鉴于以前提到过,长整型和双精度型(用J和D分别代表)的基本单元是64位,需要使用2个寄存器。

当你引用方法中的参数时必须牢牢记住。

例如,我们夹着你拥有一个非静态的方法LMyObject;->MyMethod(IJZ)V。方法的参数是“LMyObject;”,整形,长整形和布尔型。所以在这个方法中会要求五个寄存器来存放所有的参数。并且,当你以后调用这个方法时,你为了调用该指令不得不在寄存器列表中指定两个寄存器来存放任何64位的参数

猜你喜欢

转载自blog.csdn.net/zimosangtian/article/details/52382836