七的博客

安卓逆向smali语法入门

Android

安卓逆向smali语法入门

为什么要学习 smali 的语法? 以为要逆向安卓软件的时候,反编译出来的代码都是 smali 代码,你看不懂的话,根本改动不了里面的逻辑。

smali 就是类似于汇编一样的语法,不过相对比起来已经是比较简单的了。通过学习一部分的语法,就可以看得懂很多软件的逻辑。简单来说,你要想改动软件里面的逻辑,你至少需要会 Java 基础 + Android 基础 + smali 语法基础,那么你就可以去分析安卓软件的逻辑,然后通过修改 Smali 代码来修改逻辑。如果没有基础直接上手,那么大概率会很吃力,而且也很难逆向成功。

使用 apktool 反编译后的文件夹里面,/smali 文件夹里面的就是这种代码。要分析逻辑就是从这个文件夹里面去分析,修改。

由于 smali 的语法太多,而且很多很复杂,在学的时候不用全部都去学。最好就是边学边用,边实践,不会的时候就去翻。

首先需要学习的就是 smali 的数据类型,这个跟 Java 语言的类型是可以对应上的。

  • boolean Z
  • byte B
  • char C
  • short S
  • int I
  • long J
  • float F
  • double D
  • void V

前面的类型就是 Java 类型,后面的就是 smali 的类型。记起来也比较好记,smali 的数据类型缩写其实就是是 Java 类型的首字母的大写。 只有 boolean 这个类型比较特殊,缩写是 Z。

引用一个类型的语法是:

Ljava/lang/String;  # L表示引用类类型,后面跟着这个类的路径,使用分号;来结尾

在 Java 里面这么写:

String str;

上面的这个例子 Ljava/lang/String 就是对应于 Java 中的 java.lang.String 类,也可以替换成其他的类。反正格式就是 L 开头。

smali 中也是支持数组的,数组的定义如下:

[I   # 表示 int 数组
[Ljava/lang/String;  # 表示 String 数组

上面的代码换成 Java代码就是:

int[] intArray;
String[] strArray;

多维数组也类似,就是多加一个 [:

int[][] multiArray;

[[I  # 表示二维 int 数组

方法的定义:

.method public add(II)I
    .locals 1
    这里是是具体的方法体
    return v0
.end method

上面的代码就是定义了一个方法。方法以 .method 作为开始,.end method 作为结束。

其中 add(II)I 表示方法名为 add,接受两个 int 类型的参数,方法返回一个 int 参数。参数类型放在括号里面,返回类型放在括号后面。

换成 Java 代码就是:

public int add(int a1, int a2);

类的定义:

.class public Lcom/suny/MyClass;
.super Ljava/lang/Object;

上面就是定义了一个类,类声明以 .class 指令开始,后跟访问修饰符和类名。

字段的定义:

.field private myFieldName:Ljava/lang/String

上面使用 .field 来声明字段,包括访问修饰符、字段名和类型。

条件语句也是非常重要的一点,通过条件语句我们可以直接改变流程,节省很多工作量:

.method public max(II)I
    .registers 3
    .param p1, "a"    # I
    .param p2, "b"    # I

    if-le p1, p2, :cond_4
    move v0, p1
    :goto_3
    return v0

    :cond_4
    move v0, p2
    goto :goto_3
.end method

上面就是一个求 2 个数中,最大的那个数程序。如果 p1 <= p2,则跳转到 :cond_4 分支。如果 p1 > p2 ,就把 p1 的值移动到 v0 寄存器。然后程序就会执行 return v0 返回最大值。

if-eq 就是一个条件跳转,goto 就是无条件跳转。分支跳转是很重要的一个语法,在修改一些软件的逻辑的时候。

调用方法主要分为调用对象的方法,还有调用静态方法。

调用对象的方法语法是:invoke-virtual {参数列表}, 类名->方法名(参数类型)返回类型。举个例子:

invoke-virtual {v0, v1}, Ljava/lang/String;->substring(I)Ljava/lang/String;

上面例子是调用了 String 对象的 substring 这个方法,v0 是一个 String 对象,v1 是当做传递给 substring 方法的入参。

调用静态方法的语法是:invoke-static {参数列表}, 类名->方法名(参数类型)返回类型。

invoke-static {v0, v1}, Ljava/lang/Math;->max(II)I

上面的例子是调用了 Math 类的静态方法 max,入参 v0以及 v1 就是传入两个数值。

基本上掌握了上面的基础语法,就可以开始尝试逆向,碰到不会的语法现学即可。