apk文件通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件。
smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的。基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行。
在smali所有的操作都必须经过寄存器来进行:本地寄存器用v开头数字结尾的符号来表示,如v0,v1,v2…,参数寄存器用p开头数字结尾表示,如:p0,p1,p2…。特别注意的是,p0不一定是函数中的第一个参数,在非static函数中,p0代指“this”,p1表示函数的第一个参数,p2表示第二个参数,而在static函数中p0才对应第一个参数(因为java的static方法中没有this方法)
const/4 v0, 0x0
iput-boolean v0,p0,Lcom/aa;->IsRegistered:Z
上段表示的是:把0x0存寄到v0中,把这个值存放进com.aa.IsRegistered这个变量中,相当于this.IsRegistered=true,在非静态方法中p0代表的是this,不是参数。
Java Type | Type descriptor |
---|---|
boolean | Z |
char | C |
byte | B |
short | S |
int | I |
float | F |
long | J |
double | D |
Object | Ljava/lang/Object; |
int[] | [I |
Object[][] | [[Ljava/lang/object; |
内部类 | Lpackagename/objectname&subobjectname |
数组表示方式在 基本数据类型前加“[”符号,对象的则表示以L作为开头格式为Ljava/lang/Object; 分号在在后面。 Ljava/lang/String;其中java/lang对应java.lang包,String就是对应的该包中的对象。
if-eq p1, v0, :cond_8
:cond_8
invoke-direct {p0}, Lcom/paul/test/a;->d()V
上段表示如果p1和v0相等,则执行cond_8的流程:调用com.paul.test.a的d()方法
if-ne p1, v0, :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
上段表示p1不等于p0,跳转到:cond_b。把0x0赋值给v0,执行com/paul/test/a类中的void setPressed(blooean )公有方法。再调用View中的onkeyUp方法。返回一个基本数据类型。
move-result(返回基本数据类型)和move-result-object(返回对象)指令获取返回结果
这个声明是内部类的声明:aaa 这个类有2个成员内部类qqq和www
sget-object v0,Lcom/aaa;->ID:Ljava/lang/String;
sget-object用来获取变量值并保存到挨着的参数寄存器中,它获取的ID这个String类型的成员变量放到v0中。
注意:前面需要该变量所属的类的类型,后面需要加冒号和该成员变量的类型,中间是 "->"表示所属关系。
iget-object v0,p0,Lcom/aaa;->ID:Ljava/lang/String;
iget-object 比sget-object多了一个p0参数表示“this”,获取array我们用aget和aget-object和上述指令一致。
put 指令和get指令是统一的:
const/4 v3, 0x0
sput-object v3,Lcom/aaa;->timer:Lcom/aaa/timer;
相当于:this.timer=null
这是因为是object所以是null,,
sput-boolean v3,Lcom/aaa;->timer:Z;
相当于:this.timer=true
.local v0,args:Landroid/os/Message;
const/4 v1,0x12
iput v1,v0,Landroid/os/Message;->what:I
相当于 args.what=18;
smali 中的函数与变量分为2种类型,分别为direct和virtual。direct method就是private函数,其余的函数都是virtual method。
invoke-static{},Lcom/aaa;->Check()Z,
这里invoke-static后有一对“{}”,其实调用的是该方法的实例+参数列表,由于这个方法既不需参数也是static的,所以{}为空。
const-string v0,"NDK"
invoke-static{v0},Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
这个调用static void System.loadLibrary(v0)来编译NDK的。
2.invoke-super:调用父类方法的指令,通常是onCreat,Ondestory。
3.invoke-direct:调用private函数。
4.invoke-virtual :调用非private函数。修改smali中不要错用direct/virtual函数。
5.invoke-xxx/range:当方法的参数多余5个(含5个),不能直接使用以上指令,而是在后面加上"/range",表示范围。 invoke-direct/range{v0…v5},Lcom.aaa;->h(IIIIIZ)Z
在java代码中,调用函数和返回函数结果可以用一条语句完成,而在Smali里则需要分开来完成,在上面指令后,如果调用的函数返回非void,那么还需要用move-result(返回基本数据类型)和move-result-object(返回对象)指令:
const-string v0,"eric"
invoke-static{v0},Lcom/aaa;->t(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2
v2 保存的是t方法中的返回的String字符串
.method private ifRegister()Z
.locals 2 //有2个本地寄存器
.prologue //开始
const/4 v0, 0x1 //v0赋值为1
.locals v0,tempFlag:Z
if-eqz v0,:cond_0
const/4 v1,0x1
:goto_0 //标签
return v1 //返回v1的值
:cond_0 //标签
const/4 v1,0x0
goto :goto_0 //跳到goto_0执行,返回v1的值,这里可以改成retutn v1
.end method