安卓逆向smali语法入门
安卓逆向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 就是传入两个数值。
基本上掌握了上面的基础语法,就可以开始尝试逆向,碰到不会的语法现学即可。