smali语法整理

来源:互联网 发布:淘宝丝袜4成是男的买的 编辑:程序博客网 时间:2024/04/30 09:20

1.概续

最近由于工作的需要,研究了下反编译相关,自己整理了些smali语法相关的资料,在这里分享给大家,如果有错误的地方还望大家能指出来,一起讨论学习~

好了,先上代码,咱跟着代码一步一步学习。

.class public Lcom/example/tex/MainActivity;.super Landroid/app/Activity;.source "MainActivity.java"# annotations.annotation system Ldalvik/annotation/MemberClasses;    value = {        Lcom/example/tex/MainActivity$ProtocolState;    }.end annotation# static fields.field private static final LOGIN_TYPE:J# instance fields.field private bb:I.field d:J# direct methods.method static constructor <clinit>()V    .locals 2     .prologue     .line 16     invoke-static {}, Ljava/lang/System;->currentTimeMillis()J    move-result-wide v0    sput-wide v0, Lcom/example/tex/MainActivity;->LOGIN_TYPE:J    return-void.end method.method public constructor <init>()V     .locals 2    .prologue     .line 12     invoke-direct {p0}, Landroid/app/Activity;-><init>()V    .line 14    const/4 v0, 0x1     iput v0, p0, Lcom/example/tex/MainActivity;->bb:I    .line 48    const-wide/32 v0, 0x87eccb     iput-wide v0, p0, Lcom/example/tex/MainActivity;->d:J    .line 12    return-void .end method 

这是从activity类里截取的一段代码,如果有汇编基础的话,看上面代码应该是没压力的,那么要看懂上面代码,我们需要了解以下几点:

  • smali的数据类型
  • smali的方法定义和调用
  • smali的成员变量定义和调用
  • smali的逻辑定义
  • smali文件内容分析

1.smali的数据类型

数据类型 含义 I int B byte C char D double F float J long S short V void Z boolean [XXX 数组 LXXX/YY 对象

前面几种类型相信大家都清楚,后面两个说一下:数组的表示方式是:在类型前加上前中括号“[”,例如int数组和String数组分别表示为:[I、[Ljava/lang/String;对象的表示则以L作为开头,格式是LpackageName/objectName;

2.smali的方法定义和调用

格式:.method modify FunctionName(ParamType,ParamType1….) ReturnType

例子:.method public setName (Ljava/lang/String;)v 这就是设置名字的方法,返回值为空,对应java方法:public void setName(String name){}

注意地方:当参数是基本类型时,参数之间没有“;”如:

.method public setXXX (ZII)v —> public void setXXX(boolean b,int i,int j){}

调用方式:

  • invoke-direct:调用private修饰的方法
  • invoke-virtual:调用除private修饰外的方法
  • invoke-static : 调用静态方法
  • invoke-super:在重写父类方法里,调用父类方法
  • invoke-interface:调用接口方法
  • invoke-xxxxx/range:当方法的参数大于4个时,用这种方式调用

例子:
invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
这就是调用StringBuilder的append(int)方法,其中v1为StringBuilder对象,p2为方法传进来的参数,对应Java代码:v1.append(p2); 需要注意的是当此方法不是静态方法时,第一个参数p0表示该类的对象,如果是静态方法并且有参数的话,则p0表示第一个参数。

3.smali的成员函数定义

格式:.field modify fieldName:fieldType;(如果不是基本类型的话,最后这个“;”不能丢)

例子:.field private final u:Ljava/lang/Runnable; 定义了个全局的runnable对象。

调用方式:sget、iget、sget-boolean、iget-object、iget-boolean、sget-object、sput、iput、sput-boolean、iput-object、iput-boolean、sput-object等。一般地,没有“-object”后缀的表示操作的成员变量对象是基本数据类型,带“-object”表示操作的成员变量是对象类型,而”iget”或“iput”前缀表示得到或设置成员变量值,“sget”或“sput”前缀表示得到或设置静态变量值。

例子:iget v1, p0, Lcom/example/tex/MainActivity;->bb:I 表示:获取MainActivity的成员变量bb的值并赋给v1。

4.smali的逻辑定义

直接看代码:

.line 1452const-string v0, "tag"const-string v1, "demo"if-eqz v0, :cond_0invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)Icond_0:return-void

对应的java代码:
String msg = “demo”;
if(msg != null){
Log.i(“tag”,msg);
}
相信大家都已经明白了,这里就不在啰嗦。下面是我整理的一些常用smali逻辑相关语法:

逻辑语句 含义 if-eq vx,vy,目标 如果vx==vy,跳转到目标 if-ne vx,vy,目标 如果vx!=vy,跳转到目标 if-lt vx,vy,目标 如果vx < vy,跳转到目标 if-ge vx,vy,目标 如果vx>=vy,跳转到目标 if-gt vx,vy,目标 如果vx > vy,跳转到目标 if-le vx,vy,目标 如果vx<=vy,跳转到目标 if-eqz vx,目标 如果vx==0,跳转到目标 if-nez vx,目标 如果vx!=0,跳转到目标 if-ltz vx,目标 如果vx < 0,跳转到目标 if-gez vx,目标 如果vx>=0,跳转到目标 if-gtz vx,目标 如果vx > 0,跳转到目标 if-lez vx,目标 如果vx<=0,跳转到目标 if-eqz vx,vy,目标 如果vx==vy,跳转到目标 movevx,vy 将vx的值赋给vy move-result vx 将上一次调用方法的返回值赋给vx return-void 返回空值 const/4 vx,值 存入4位常量到vx new-instance vx,类型ID 创建一个类型ID的对象 aget vx,vy,vz 从int数组vy中获取索引为vz的值存到vx aget-wide vx,vy,vz 从long/double数组vy中获取索引为vz的值存到vx aget-boolean vx,vy,vz 从boolean数组vy中获取索引为vz的值存到vx aget-object vx,vy,vz 从对象数组vy中获取索引为vz的值存到vx aput vx,vy,vz 将vx的值存入int数组vy的vz索引处 aput-object vx,vy,vz 将vx的值存入对象数组vy的vz索引处 iget vx,vy,x 将引用vy获取int类型字段x的值赋给vx iget-object vx,vy,x 将引用vy获取字段x的值赋给vx iput vx,vy, x 通过引用vy将vx的值赋给int类型的字段x iput-object vx,vy,x 通过引用vy将vx的值赋给对象x sget vx,字段ID 获取某个类的int类型的静态字段的值赋给vx sget-object vx,字段ID 获取某个类的静态对象赋给vx int-to-float vx,vy 将int类型的vy的值强转成float类型存入vx float-to-int vx,vy 将float类型的vy的值强转成int类型存入vx add-int vx,vy,vz vx = vy + vz (vx,vy,vz都为int类型) sub-int vx,vy,vz vx = vy - vz mul-int vx,vy,vz vx = vy * vz div-int vx,vy,vz vx = vy / vz rem-int vx,vy,vz vx = vy % vz and-int vx,vy,vz vx = vy & vz or-int vx,vy,vz vx = vy add-int/2addr vx,vy vx = vx + vy sub-int/2addr vx,vy vx = vx - vy mul-int/2addr vx,vy vx = vx * vy div-int/2addr vx,vy vx = vx / vy neg-float vx, vy vx = -vy (将vy值变成负值给vx) monitor-enter vx 为指定的对象vx获取锁 monitor-exit vx 释放指定的对象vx的锁

5.smali文件内容分析

咱上面把smali文件中常用的语法都过了一遍,然后接下来我们将内容在分析一遍,基本上你就可以很轻松的看懂smali文件了,废话不多说,上代码~

.class public Lcom/example/tex/MainActivity;//类的全名.super Landroid/app/Activity;//此类的父类.source "MainActivity.java"//文件名# annotations//内部类ProtocolState声明.annotation system Ldalvik/annotation/MemberClasses;    value = {        Lcom/example/tex/MainActivity$ProtocolState;    }.end annotation# static fields.field private static final LOGIN_TYPE:J //long类型的静态变量# instance fields.field private bb:I//int类型的成员变量bb.field d:J//long类型的成员变量d.method static constructor <clinit>()V    .locals 2 //表示此方法里用了2个寄存器,寄存器是用来存局部变量的值    .prologue //表示方法开始    .line 16 //行数    invoke-static {}, Ljava/lang/System;->currentTimeMillis()J //获取系统当前时间    move-result-wide v0 //将系统当前时间存入v0    sput-wide v0, Lcom/example/tex/MainActivity;->LOGIN_TYPE:J //将v0赋值给静态变量LOGIN_TYPE    return-void //空返回.end method //方法结束标志# direct methods.method public constructor <init>()V //构造函数    .locals 2//表示此方法里用了2个寄存器,寄存器是用来存局部变量的值    .prologue //表示方法开始    .line 12 //行数    invoke-direct {p0}, Landroid/app/Activity;-><init>()V//调用init()方法    .line 14    const/4 v0, 0x1 //定义一个局部变量v0 值为1(十六进制)    iput v0, p0, Lcom/example/tex/MainActivity;->bb:I//将v0的值赋给成员变量bb    .line 48    const-wide/32 v0, 0x87eccb //将0x87eccb存入32位常量    iput-wide v0, p0, Lcom/example/tex/MainActivity;->d:J//将v0的值赋给成员变量d    .line 12    return-void //空返回.end method //方法结束标志

没错,上面就是开篇引入的代码,我都加上注释了,大家跟着看,就不在一行一行解释了。在这里提几个重要的地方:

  1. 代码中的“#”是smali里面的注释标识。
  2. 大家看得仔细点就会看到该类有两个构造函数,constructor <clinit>()constructor <init>()他们有啥区别呢?第一个的作用是在jvm第一次加载class文件时调用,包括静态变量初始化语句和静态块的执行。第二个的作用是在实例创建出来的时候调用,包括调用new操作符。之后找静态变量赋值的地方,就找constructor <clinit>()就可以了。
  3. 第一个构造方法里的.locals 2:表示此方法里用了2个寄存器v0,v1。寄存器是用来存局部变量的值,这个字段很重要,当你在植入代码时,如果用到了寄存器,但是没有修改此值,那就很可能报VerifyError错误。
  4. 第一个构造方法里的.prologue:表示方法的开始。这个也同上面重要,要是你植入的代码在这个字段前就不会达到预期的效果。

到此,smali语法的整理就结束了,这是我利用空余时间写的第一篇博客,前前后后也花了两三天时间,非常荣幸屏前的你能一直看完,相信这篇文章能帮助到你,如果你觉得这篇文章对你有用,那么赞一个或者留个言吧~

接下来我会写一篇如何修改smali文件相关的博客,希望大家前来学习和讨论!

2 0
原创粉丝点击