Smali
Smali是Android虚拟机的反汇编语言
Android代码一般是用JVM语言编写,执行Androdi程序一般需要用到JVM,在Android平台上也不例外,但是出于性能上的考虑,并没有使用标准的JVM,而是使用专门的Android虚拟机(5.0以下为Dalvik,5.0以上为ART)。Android虚拟机的可执行文件并不是普通的class文件,而是再重新整合打包后生成的dex文件。smali是dex格式的文件的汇编器
反汇编器\ 其语法是一种宽松的jasmin/dedexer 语法,实现了.dex格式的所有功能(注解/调试信息/线路信息等)
学习smali必要性
- 动态调试与修改APK, 当静态分析已经无法满足时,此时便需要对Android进行动态调试, 而动态调试便是调试smail
- 修改APK运行逻辑, 通过修改smali代码,在重新打包.便可对app进行持久化的修改.(常用的注入均在外部而不是app内部)
插件: java2smail
Smali基本语法
关键字
关键字
关键字 | 说明 |
---|---|
.class | 定义类名 |
.super | 定义父类名 |
.source | 定义源文件名 |
.filed | 定义字段 |
.method | 定义方法开始 |
.end method | 定义方法结束 |
.annotation | 定义注解开始 |
.end annotation | 定义注解结束 |
.implements | 定义接口指令 |
.local | 指定了方法内局部变量的个数 |
.registers | 指定方法内使用寄存器的总数 |
.prologue | 表示方法中代码的开始处 |
.line | 表示java源文件中指定行 |
.paramter | 指定方法的参数 |
.param | 和.paramter含义一致,但是表达格式不同 |
数据类型
Smali | Java | 备注 |
---|---|---|
v | void | 只能用于返回值类型 |
Z | boolean | |
B | byte | |
S | short | |
C | char | |
I | int | |
J | long | |
F | float | |
D | double | |
Lpackage/name; | 对象类型 | L表示这是一个对象类型,package表示该对象所在的包,;表示对象名称的结束 |
[类型 | 数组 | [I表示一个int型数据,[Ljava/lang/String 表示一个String的对象数组 |
类声明
1 |
.class + 修饰符 + 类名 |
构造函数
1 |
.method 权限修饰符 constructor <init>(参数类型) V |
成员变量定义格式
1 |
.field public/private [static][final] varName:<类型> |
返回值关键字
返回关键字 | Java数据类型 |
---|---|
return | byte short float char boolean |
return-void | void |
return-wide | long double |
return-object | 数组 object |
获取指令
1 |
iget, sget, iget-boolean, sget-boolean, iget-object, sget-object |
操作指令
1 |
iput, sput, iput-boolean, sput-boolean, iput-object, sput-object |
指令解析
1 |
sget-object v0,Lcom/aaa;->ID:Ljava/lang/String; |
example
1 |
// example 1 相当于java代码:this.timer = null; |
调用指令
调用关键字 | 作用 |
---|---|
invoke-virtual | 非私有实例方法调用 |
invoke-direct | 构造方法以及私有方法的调用 |
invoke-static | 静态方法的调用 |
invoke-super | 父类方法的调用 |
invoke-interface | 接口方法调用 |
调用格式: invoke-指令类型 {参数1, 参数2,…}, L类名;->方法名 如果不是是静态方法,参数1代表调用该方法的实例。
寄存器
Java中变量都是存放在内存中的,Android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型。64位类型(Long/ Double) 用2个格式的寄存器表示; Dalvik字节码有两种类型: 原始类型和引用类型(
包括对象和数组)
寄存器分为如下两类: 1、本地寄存器: 用v开头数字结尾的符号来表示,v0, v1, v2,… 2、参数寄存器: 用p开头数字结尾的符号来表示,p0,p1,p2,…
注意:
在非static方法中,p0代指this,p1为方法的第一个参数。
在static方法中,p0为方法的第一个参数。
1 |
const/4 v0, 0x1 //把值0x1存到v0本地寄存器 |
tip:
查看smali代码时可以和java代码结合来看