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

参考资料:

  1. smali语法中文参考文档

  2. 逆向之Smali入门学习





# Android逆向  

tocToc: