• Smali语法基础


    Smali是什么

    Smali是Android虚拟机的反汇编语言。
    我们都知道,Android代码一般是用java编写的,执行java程序一般需要用到java虚拟机,在Android平台上也不例外,但是出于性能上的考虑,并没有使用标准的JVM,而是使用专门的Android虚拟机(5.0以下为Dalvik,5.0以上为ART)。Android虚拟机的可执行文件并不是普通的class文件,而是再重新整合打包后生成的dex文件。dex文件反编译之后就是Smali代码,所以说,Smali语言是Android虚拟机的反汇编语言。

    掌握Smali有哪些好处

    1、动态调试APK,通常静态分析APK是不够的,如果需要彻底分析APK的执行逻辑,需要通过动态调试来进行。
    具体教程参考:https://www.jianshu.com/p/9931a1e77066
    2、修改APK运行逻辑,通过修改Smali代码,再重新编译打包成新的APK,是Android逆向的基本操作。

    Smali基本语法

    数据类型

    语法关键词

    寄存器

    Java中变量都是存放在内存中的,Android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型。
    为什么寄存器比内存快,可以参考这篇文章:http://www.ruanyifeng.com/blog/2013/10/register.html

    寄存器分为如下两类:
    1、本地寄存器
    用v开头数字结尾的符号来表示,v0, v1, v2,...
    2、参数寄存器
    用p开头数字结尾的符号来表示,p0,p1,p2,...
    注意:
    在非static方法中,p0代指this,p1为方法的第一个参数。
    在static方法中,p0为方法的第一个参数。

    Smali代码示例:

    const/4 v0, 0x1 //把值0x1存到v0本地寄存器
    iput-boolean v0,p0,Lcom/aaa;->IsRegisterd:Z //把v0中的值赋给com.aaa.IsRegistered,p0代表this,相当于this.Isregistered=true
    

    成员变量

    成员变量定义格式为:
    .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的实例

    函数

    函数定义格式为:
    .method public/private [static][final] methodName()<类型>
    .end method

    Smali代码示例

    .method private ifRegistered()Z
        .locals 2            // 本地寄存器的个数
        .prologue
        const/4 v0, 0x1      //v0赋值为1
        if-eqz v0, :cond_0   //判断v0是否等于0,等于0则跳到cond_0执行
        const/4 v1, 0x1      //符合条件分支
        :goto_0              //标签
        return v1            //返回v1的值
        :cond_0              //标签
        const/4 v1, 0x0      //cond_0分支
        goto :goto_0         //跳到goto_0执行
    .end method
    

    函数分为两类:direct method和virtual method
    direct method就是private方法,virtual method就是指其余的方法。

    调用指令:
    invoke-direct
    invoke-virtual
    invoke-static
    invoke-super
    invoke-interface

    调用格式:
    invoke-指令类型 {参数1, 参数2,...}, L类名;->方法名
    如果不是是静态方法,参数1代表调用该方法的实例。

    Smali代码示例:

    const-string v0, "NDKLIB"
    invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
    

    相当于java代码:System.loadLibrary("NDKLIB")

    函数返回结果
    Smali需要用指令move-result或move-result-object来保存函数返回的结果

    Smali代码示例:

    const-string v0, "Eric"
    invoke-static {v0}, Lcmb/pbi;->t(Ljava/lang/String;)Ljava/lang/String;
    move-result-object v2
    

    表示将方法t返回的String对象保存到v2中。

    方法的定义

    private static int sum(int a, int b) {
            return a+b;
    }
    

    使用编译后是这样

    .method private static sum(II)I
        .locals 4   #表示需要申请4个本地寄存器
        .parameter
        .parameter #这里表示有两个参数
        .prologue
        .line 27 
        move v0, p0
        .local v0, a:I
        move v1, p1
        .local v1, b:I
        move v2, v0
        move v3, v1
        add-int/2addr v2, v3
        move v0, v2
        .end local v0           #a:I
        return v0
    .end method
    

    从上面可以看到函数声明使用.method开始 .end method结束,java中的关键词private,static 等都可以使用,同时使用签名来表示唯一的方法,这里是sum(II)I。

    指令执行

    smali字节码是类似于汇编的,如果你有汇编基础,理解起来是非常容易的。
    比如:
    move v0, v3 #把v3寄存器的值移动到寄存器v0上.
    const v0, 0x1 #把值0x1赋值到寄存器v0上。
    invoke-static {v4, v5}, Lme/isming/myapplication/MainActivity;->sum(II)I #执行方法sum(),v4,v5的值分别作为sum的参数

    条件跳转分支

    "if-eq vA, vB, :cond_x" --- 如果vA等于vB则跳转到:cond_x
    "if-ne vA, vB, :cond_x" --- 如果vA不等于vB则跳转到:cond_x
    "if-lt vA, vB, :cond_x" --- 如果vA小于vB则跳转到:cond_x
    "if-ge vA, vB, :cond_x" --- 如果vA大于等于vB则跳转到:cond_x
    "if-gt vA, vB, :cond_x" --- 如果vA大于vB则跳转到:cond_x
    "if-le vA, vB, :cond_x" --- 如果vA小于等于vB则跳转到:cond_x
    "if-eqz vA, :cond_x" --- 如果vA等于0则跳转到:cond_x
    "if-nez vA, :cond_x" --- 如果vA不等于0则跳转到:cond_x
    "if-ltz vA, :cond_x" --- 如果vA小于0则跳转到:cond_x
    "if-gez vA, :cond_x" --- 如果vA大于等于0则跳转到:cond_x
    "if-gtz vA, :cond_x" --- 如果vA大于0则跳转到:cond_x
    "if-lez vA, :cond_x" --- 如果vA小于等于0则跳转到:cond_x
    转自:https://www.jianshu.com/p/ba9b374346dd
  • 相关阅读:
    软件实施工程师是一个什么样的工作?他的具体工作内容是什么?发展前景怎样?
    做金融(基金、证券)方面的软件实施工程师有没有发展前途?职业发展空间如何。
    做软件实施工程师的一点建议
    系统实施工程师主要工作职则
    软件实施工程师
    UE编辑器编译和运行java设置
    猜数字
    猜数字
    Problem G
    Problem G
  • 原文地址:https://www.cnblogs.com/songzhixue/p/12027822.html
Copyright © 2020-2023  润新知