smali语法从入门到精通

smali语法从入门到精通

相关资源

视频中提到的apk和源代码资源,到这里下载

Smali是什么

Smali是Android虚拟机的反汇编语言。Android虚拟机的可执行文件并不是普通的class文件,而是再重新整合打包后生成的dex文件。dex文件反编译之后就是Smali代码,所以说,Smali语言是Android虚拟机的反汇编语言。

掌握Smali有哪些好处

  1. 动态调试APK,通常静态分析APK是不够的,如果需要彻底分析APK的执行逻辑,需要通过动态调试来进行。
  2. 修改APK运行逻辑,通过修改Smali代码,再重新编译打包成新的APK,是Android逆向的基本操作。

Smali基本语法

数据类型

Smali(方法类型)

Smali(代码)

Java

备注

V

return-void

void

只能用于返回值类型

Z

const/4 v0,0x1

boolean

布尔值类型,判断逻辑

Ljava/lang/String;

const-string v0,”字符串”

String

字符串类型

I

const/4 v0,0x1

int

整数类型

Lpackage/name;

Lpackage/name;

对象类型

L表示这是一个对象类型,package表示该对象所在的包,; 表示对象名称的结束

S

const/16 v0, 0x64

short

短整数类型

J

const-wide/32 v0, 0x186a0

long

长整数类型

F

const/high16 v0, 0x42c80000   

float

浮点数类型

D

const-wide/high16 v0, 0x4059000000000000L

double

双浮点数类型

C

const/16 v0, 0x61

char

字符类型

B

const/4 v0, 0x1

byte

字节类型

[类型

[类型

数组

[l表示一个int型数据,[Ljava/lang/String 表示一个String的对象数组

语法关键词

关键词

说明

.class

定义java类名

.super

定义父类名

.source

定义Java源文件名

.filed

定义字段

.method

定义方法开始

.end method

定义方法结束

.annotation

定义注解开始

.end annotation

定义注解结束

.implements

定义接口指令

.local

指定了方法内局部变量的个数

.registers

指定方法内使用寄存器的总数

.prologue

表示方法中代码的开始处

.line

表示java源文件中指定行

.paramter

指定了方法的参数

.param

和.paramter含义一致但是表达格式不同

寄存器

Java中变量都是存放在内存中的,Android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型。

寄存器分为如下两类:
1、本地寄存器
用v开头数字结尾的符号来表示,v0, v1, v2,...
2、参数寄存器
用p开头数字结尾的符号来表示,p0,p1,p2,...
注意:
在非static方法中,p0代指this,p1为方法的第一个参数。
在static方法中,p0为方法的第一个参数。

Smali代码示例

const/4 v0, 0x1 //把值0x1存到v0本地寄存器

iput-boolean v0,p0,Lcom/aaa;->IsRegisterd:Z //把v0中的值赋给com.aaa.IsRegistered,p0代表this,相当于this.Isregistered=true

成员变量

成员变量定义格式为:
.field public/private [static][final] varName:<类型>

获取指令
iget, sget, iget-boolean, sget-boolean, iget-object, sget-object

操作指令
iput, sput, iput-boolean, sput-boolean, iput-object, sput-object
array的操作是aget和aput

指令解析
sget-object v0,Lcom/aaa;->ID:Ljava/lang/String;
获取ID这个String类型的成员变量并放到v0这个寄存器中
iget-object v0,p0,Lcom/aaa;->view:Lcom/aaa/view;
iget-object比sget-object多一个参数p0,这个参数代表变量所在类的实例。这里p0就是this

Smali代码示例1:

const/4 v3, 0x0

sput-object v3, Lcom/aaa;->timer:Lcom/aaa/timer;

相当于java代码:this.timer = null;

Smali代码示例2:

.local v0, args:Landroid/os/Message;

const/4 v1, 0x12

iput v1,v0,Landroid/os/Message;->what:I

相当于java代码:args.what = 18;
其中args为Message的实例

函数

函数定义格式为:
.method public/private [static][final] methodName()<类型>
.end method

Smali代码示例

.method private ifRegistered()Z

    .locals 2            // 本地寄存器的个数

    .prologue

    const/4 v0, 0x1      //v0赋值为1

    if-eqz v0, :cond_0   //判断v0是否等于0,等于0则跳到cond_0执行

    const/4 v1, 0x1      //符合条件分支

    :goto_0              //标签

    return v1            //返回v1的值

    :cond_0              //标签

    const/4 v1, 0x0      //cond_0分支

    goto :goto_0         //跳到goto_0执行

.end method

函数分为两类:direct method和virtual method
direct method就是private方法,virtual method就是指其余的方法。

调用指令:
invoke-direct
invoke-virtual
invoke-static
invoke-super
invoke-interface

调用格式:
invoke-指令类型 {参数1, 参数2,...}, L类名;->方法名
如果不是是静态方法,参数1代表调用该方法的实例。

Smali代码示例:

const-string v0, "NDKLIB"

invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

相当于java代码:System.loadLibrary("NDKLIB")

函数返回结果
Smali需要用指令move-result或move-result-object来保存函数返回的结果

Smali代码示例:

const-string v0, "Eric"

invoke-static {v0}, Lcmb/pbi;->t(Ljava/lang/String;)Ljava/lang/String;

move-result-object v2

表示将方法t返回的String对象保存到v2中。

方法的定义

private static int sum(int a, int b) {

        return a+b;

}

使用编译后是这样

.method private static sum(II)I

    .locals 4   表示需要申请4个本地寄存器

    .parameter

    .parameter 这里表示有两个参数

    .prologue

    .line 27

    move v0, p0

    .local v0, a:I

    move v1, p1

    .local v1, b:I

    move v2, v0

    move v3, v1

    add-int/2addr v2, v3

    move v0, v2

    .end local v0           a:I

    return v0

.end method

从上面可以看到函数声明使用.method开始 .end method结束,java中的关键词private,static 等都可以使用,同时使用签名来表示唯一的方法,这里是sum(II)I。

指令执行

smali字节码是类似于汇编的,如果你有汇编基础,理解起来是非常容易的。
比如:
move v0, v3 把v3寄存器的值移动到寄存器v0上.
const v0, 0x1 把值0x1赋值到寄存器v0上。
invoke-static {v4, v5}, Lme/isming/myapplication/MainActivity;->sum(II)I 执行方法sum(),v4,v5的值分别作为sum的参数

条件跳转分支

"if-eq vA, vB, :cond_x" --- 如果vA等于vB则跳转到:cond_x

"if-ne vA, vB, :cond_x" --- 如果vA不等于vB则跳转到:cond_x

"if-lt vA, vB, :cond_x" --- 如果vA小于vB则跳转到:cond_x

"if-ge vA, vB, :cond_x" --- 如果vA大于等于vB则跳转到:cond_x

"if-gt vA, vB, :cond_x" --- 如果vA大于vB则跳转到:cond_x

"if-le vA, vB, :cond_x" --- 如果vA小于等于vB则跳转到:cond_x

"if-eqz vA, :cond_x" --- 如果vA等于0则跳转到:cond_x

"if-nez vA, :cond_x" --- 如果vA不等于0则跳转到:cond_x

"if-ltz vA, :cond_x" --- 如果vA小于0则跳转到:cond_x

"if-gez vA, :cond_x" --- 如果vA大于等于0则跳转到:cond_x

"if-gtz vA, :cond_x" --- 如果vA大于0则跳转到:cond_x

"if-lez vA, :cond_x" --- 如果vA小于等于0则跳转到:cond_x

常用修改技巧

const-string v0,”json数据”     //写死抓包返回的vip信息的数据

goto :cond_x       //无视后面的任何判断,直接跳转到校验成功后的代码段

return-void       //如果方法是返回的void,直接在某个代码的后面加上,终止后面的代码的执行

const/4 v0,0x1    //对于判断,写死true 0x1或者false 0x0

#               //某行代码前添加#,代表该行代码被注释掉,和删掉这行代码一样,但方便恢复

if-eq/…          //直接修改判断条件

你可能感兴趣的:(安卓修改,安卓反编译,安卓打包,安卓编程,安卓开发,安卓教程,安卓反向工程)