Android 逆向Smali语言初识
Smali,Baksmali分别是指安卓系统里的Java虚拟机(Dalvik)所使用的一种.dex格式文件的汇编器,反汇编器。
函数语法
Smali 语法规范与格式Smali 是对 Dalvik 虚拟机字节码的一种解释,虽然不是官方标准语言,但所有语句都遵循一套语法规范。要了解 smali 语法规范,可以先从了解 Dalvik 虚拟机字节码的指令格式开始。3.1 Dalvik 虚拟机字节码指令格式在 Android 4.0 源码 Dalvik/docs 目录下提供了一份文档 instruction-formats.html,里面详细列举了 Dalvik 虚拟机字节码指令的所有格式。
Dalvik 虚拟机字节码的类型、方法和字段的表示方法3.2.1 类型Dalvik 字节码有两种类型,基本类型和引用类型。对象和数组是引用类型,其它都是基本类型。
Dalvik 字节码类型描述符
描述符 类型
- V void,只能用于返回值类型
- Z boolean
- B byte
- S short
- C charI intJ long(64 位)
- F floatD double(64 位)
- L Java 类类型
- [ 数组类型
常见的代码含义:
#表示当前代码在源java文件中的行数。
.line
.line 34
#表示来自公共方法methodAReturn返回值是一个对象com.bolex.AA
method
.method public methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
#表示该函数上需要使用3个寄存器
registers
.registers 3
#表示接收两个入参都是AA对象,并标记寄存器p1和p2
param
.param p1, "mAA" # Lcom/bolex/AA;
.param p2, "sAA" # Lcom/bolex/AA;
#表示函数内执行的起始标记
.prologue
.prologue
#表示 返回寄存器上p1对象
return-object
return-object p1
#表示函数结束标记
.end method
#创建一个AA对象
new-instance
new-instance v0, Lcom/bolex/AA;
#表示使用无参构造方法直接调用
invoke-direct
invoke-direct {v0}, Lcom/bolex/AA;-><init>()V
#表示为虚拟方法
invoke-virtual
#数组操作指令
#new-array构造指定类型I也就是int类型并且把值赋给v0
# v0=new int[8];
new-array v0,v0,[ I
#array-length 获取给定v0寄存器中数组的长度并将值赋给v1寄存器,数组长度就是数组的个数。v1=v0,也就是说v1=8
array-length v1,v0
# 方法调用指令
#new-instance v1,... 构造一个指定类型对象的新实例,并将对象引用赋值给v1寄存器。
#L表示java类型中的任何类,
# StringBuilder对象是动态对象,允许扩充它所封装的字符串中字符的数量,但是您可以为它可容纳的最大字符数指定一个值。相当于是一个string的升级版。
new-instance v1,Ljava/lang/StringBuilder;
# 方法调用指令
#<init>:在实例创建出来的时候调用,包括调用new操作符;
new-direct v1,Ljava/lang/StringBuilder;-><init>( )v
# 跳转指令 if (v0!=0)
#if-nez 的意思就是 not equal zero 如果v0不等于0,那么就继续向下执行,如果等于0就跳转到标号名为cond_0的位置。
if-nez v0, : cond_0
# goto的含义就是强行跳转到标号名为goto_0的地方
goto :goto_0
#标号cond_0
:cond_0
# 数据转换指令
#把int型变量转变为float变量
int-to-float v2,v2
# 数据运算指令
# 相当于 v2+=v2,第一个v2是寄存器,第二个和第三个是数据
add-float v2,v2,v2
Java编译dex文件
以下用常见的hello world来表示smali语法结构。
public class firedt {
public static void main(String[] args){
System.out.println("hello world");
}
}
在AS中打开代码,安装java2smali插件后,在build->compile to smali编译为smali代码。
编译完成后的代码为以下,并对关键代码进行注释含义:
.class public Lfiredt; #定义一个firedt类
.super Ljava/lang/Object; #继承object类
.source "firedt.java" #由firedt.java编译来
# direct methods
.method public constructor <init>()V
.registers 1 #注册一个寄存器
.prologue #代码开始
.line 1 #第一行
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static main([Ljava/lang/String;)V #说明一个main的静态方法,类型为void
.registers 3
.prologue
.line 3
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; #获取变量对象保存到v0
const-string v1, "hello world" #赋值一个字符串v1=hello world
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V #调用printstream的println方法把v0赋值v1
.line 4
return-void
.end method #方法结束,一个method对应一个end method