Dalvik虚拟机给自己搞了一套指令集,并制定了自己的指令格式和调用规则。这些指令的集合就组成了Dalvik汇编代码。
Smali文件中保存的就是.dex文件经反编译得到的Dalvik汇编代码。
下面就通过一段Smali代码,掌握阅读方法。
# virtual methods .method public foo(II)I #int foo(int, int); .registers 5 #使用5个寄存器 .parameter #参数 .parameter .prologue #代码开始 .line3 add-int v0, p1, p2 #将p1,p2相加,存入v0 sub-int v1, p1, p2 mul-int/2addr v0, v1 return v0 .end method
有几个注意点:
1..registers指令指定函数用到寄存器的个数,其中参数3个p0,p1和p2,局部变量使用2个v0和v1。函数中没有体现p0,因为p0代表的是非静态方法中的this。
2.在ARM架构中,部分寄存器被映射到ARM寄存器,部分使用调用栈进行模拟。
上面是粗略的认识,下面讲系统的方法论。
Dalvik汇编代码由类型、方法、字段和指令集构成。
1.类型
语法 含义 V void,只用于返回值类型 Z boolean B byte S short C char I int J long F float D double L Java类类型 [ 数组类型
注1,像J,D等64位类型,使用2个相邻寄存器保存,如v2,v3
注2,[I表示一个整形一维数组,n维数组等等递推
注3,Ljava/lang/String 表示Java字符串类型,以此类比
2.方法
方法格式:Lpackage/name/ObjectName;->MethodName(III)Z
举个栗子
method(I[[IILjava/lang/String; [Ljava/lang/Object; )Ljava/lang/String;
翻译成Java代码就是
String method(int, int[][], int, String, Object[])
3.字段
字段由类型(Lpackage/name/ObjectName)、字段名(FieldName)和字段类型(Ljava/lang/String)组成:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
4.指令集
Dalvik指令集按功能可划分为:空操作指令(nop)、数据操作指令(move vA, vB)、返回指令(return-void)、数据定义指令(const/16 vA, #+BBBB)、锁指令(mointor-enter vAA)、实例操作指令(new-instance vAA, type@BBBB)、数组操作指令(array-length vA, vB)、异常指令(thow vAA)、跳转指令(if-eqz)、比较指令(cmpl-double)、字段操作指令(sget-object)、方法调用指令(invoke-static)、数据转换指令(int-to-byte)、数据运算指令(mul-type)
具体的指令集信息,搜索 “dalvik opcodes” 可得到。
有时候apk逆向过程中,我们需要验证一下自己的想法,或跟踪程序执行流程,需要在smali代码中插桩。下面分别插入log,toast和加载so库的代码。
Log额外使用2个寄存器:
.method protected onCreate(Landroid/os/Bundle;)V .locals 5 #因为用到v3\v4两个额外寄存器,locals数+2 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 23 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V #### inject begin ##### const-string v3, "logInfo" #标签 const-string v4, "Hello ezreal." #日志内容 invoke-static {v3, v4}, Landroid/util/Log;->w(Ljava/lang/String;Ljava/lang/String;)I #调用Log.w() #### inject end #### .line 24 const/4 v2, 0x1
toast额外使用2个寄存器:
const-string v5, "你好我是一个toast" const/4 v6, 0x1 invoke-static {p0, v5, v6}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; move-result-object v5 invoke-virtual {v5}, Landroid/widget/Toast;->show()V
加载so库,额外使用1个寄存器:
const-string v7, "libcrackme.so" #so库名称 invoke-static {v7}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V