参考资料
https://ctf-wiki.github.io/ctf-wiki/android/basic_operating_mechanism/java_layer/smali/smali-zh/
简述
在执行 Android Java 层的代码时,其实就是 Dalvik(ART) 虚拟机(使用 C 或 C++ 代码实现)在解析 Dalvik 字节码,从而模拟程序的执行过程。而smali则是Dalvik的指令集。Java文件中的每一个内部类,都会产生一个单独的smali文件。
文件描述
.class < 访问权限> [ 修饰关键字] < 类名>
.super < 父类名>
.source <源文件名>
如果一个类实现了接口还有以下的说明
#interfaces
.implements <接口名称>
数据类型
描述符 | Java类型 | 说明 | |
---|---|---|---|
B | byte | 字节 | |
C | char | 字符 | |
D | double | 双精度浮点数 | |
F | float | 单精度浮点数 | |
I | int | 整型 | |
J | long | 长整型 | |
S | short | 短整型 | |
V | void | 无类型 | |
Z | boolean | 布尔型 | |
[ | array | [ XXX ,XXX为数组类型有几个就为几维数组 | |
L | object | Lxxx/yyy,xxx/yyy为对象的包名路径 |
运算符
运算类型 | 说明 | ||
---|---|---|---|
add-type | vBB + vCC | ||
sub-type | vBB - vCC | ||
mul-type | vBB * vCC | ||
div-type | vBB / vCC | ||
rem-type | vBB % vCC | ||
and-type | vBB & vCC | ||
or-type | vBB \ | vCC | |
xor-type | vBB ^ vCC | ||
shl-type | vBB << vCC ,有符号数左移 | ||
shr-type | vBB >> vCC,有符号数右移 | ||
ushr-type | vBB >>> vCC,无符号数右移 |
寄存器的命名
Dalvik字节码中,register(寄存器)一定是32位
p 开头的寄存器都是参数寄存器
v 开头的寄存器都是局部变量寄存器
两者的数量之和为方法申请的寄存器数量
方法自身占用一个寄存器 引用自身类的this 如果是子类还会隐含父类的this
函数描述
调用函数
指令 | 说明 | |
---|---|---|
invoke-super | 调用父函数 | |
invoke-direct | 调用private函数 | |
invoke-static | 调用static函数 | |
invoke-virtual | 调用protected或public函数 | |
invoke-xxxx/range {v0 .. vn} | 多于5个时(含5个)在后面加上“/range”,range表示范围 n为参数个数 xxxx为类型 |
if 指令
指令 | 说明 | |
---|---|---|
if-eq vA,vB,target | 如果 vA=vB,跳转 | |
if-ne vA,vB,target | 如果 vA!=vB,跳转 | |
if-lt vA,vB,targe | 如果 vA<vB,跳转 | |
if-gt vA,vB,target | 如果 vA>vB,跳转 | |
if-ge vA,vB,target | 如果 vA>=vB,跳转 | |
if-le vA,vB,target | 如果 vA<=vB,跳转 | |
if-eqz vAA,target | 如果 vA=0,跳转 | |
if-nez vAA,target | 如果 vA!=0,跳转 | |
if-ltz vAA,target | 如果 vA<0,跳转 | |
if-gtz vAA,target | 如果 vA>0,跳转 | |
if-lez vAA,target | 如果 vA<=0,跳转 | |
if-gtz vAA,target | 如果 vA>=0,跳转 |
注解
注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,“.annotation”指令会直接定义在 smali 文件中,如果是方法或字段,“.annotation”指令则会包含在方法或字段定义中
格式为
常用系统注释
MemberClasses注解
MemberClasses注解是编译时自动加上的,Memberclasses是一个子类的集合,说明当前类有多少子类。
EnclosingMethod注解
EnclosingMethod 注解用于说明当前smali文件的作用范围,
Method说明它作用于一个方法。
只要有EnclosingMethod 那么InnerClass一定出现,而且一个类不得同时包含 EnclosingClass 和 EnclosingMethod 注释。
EnclosingClass
EnclosingClass 注解用于说明当前smali文件的作用范围,
Class说明它作用于一个类。
只要有EnclosingClass那么InnerClass一定出现,而且一个类不得同时包含 EnclosingClass 和 EnclosingMethod 注释。
|
|
InnerClass
表明是一个内部类 accessFlags为访问标志 name为内部类的名称
访问标志名称 | 值 | |
---|---|---|
ACC_ABSTRACT | 0x0400 | |
ACC_FINAL | 0x0010 | |
ACC_INTERFACE | 0x0200 | |
ACC_NATIVE | 0x0100 | |
ACC_PRIVATE | 0x0002 | |
ACC_PROTECTED | 0x0004 | |
ACC_PUBLIC | 0x0001 | |
ACC_STATIC | 0x0008 | |
ACC_STRICT | 0x0800 | |
ACC_SUPER | 0x0020 | |
ACC_SYNCHRONIZED | 0x0020 | |
ACC_TRANSIENT | 0x0080 | |
ACC_VOLATILE | 0x0040 |
下面的0x9 则是ACC_STATIC | ACC_PUBLIC 计算出来的
对应java文件
数据移动
move系列指令以及move-result 用于处理小于等于 32 位的基本类型。
move-wide系列指令和move-result-wide用于处理 64 位类型,包括long和double类型。
move-object系列指令和move-result-object用于处理对象引用。
move-result 是把上一条执行的代码的返回值放到指定寄存器上
move A: 目标寄存器 B: 源寄存器
数组定义
指令 | 说明 | |
---|---|---|
new-array v0, v1, I | v0为存放数组的寄存器,v1为数组长度,I为类型 | |
filled-new-array {v1, v2, v3, v4, v5}, I move-result v0 | v0为存放数组的寄存器, v1-v5为存放的参数, I为类型 |
“特殊”的synthetic方法
在smail文件中会看到定义为 .method static synthetic access$xxx 的方法,这些方法是由编译器生成的,目的是方便内部类/外部类 访问 外部类/内部类 的私有方法。