• [免费专栏] Android安全之安卓APK浅析



    欢迎新同学的光临
    … …
    人若无名,便可专心练剑


    我不是一条咸鱼,而是一条死鱼啊!


    0x01 Android 应用程序分析

    随着物联网的普及,许多智能设备网联化、例如智能门锁、智能手环、智能汽车等智能设备都是由APP来进行远程控制的,比如启动、点火、远程控制,那么由此可看出,APP也是车联网安全中必不可少的一个环节,存在的安全隐患以及攻击面也是相当大的。

    0x02 Android apk安装包分析

    2.1 Android 是啥?

    Android是基于Linux系统的开源操作系统,是由Andy Rubin于2003年在美国加州创建,后被Google于2005年收购。在2008年的时候发布了第一部Android智能手机,随后Android不断发展更新,占据了全球大部分的手机市场。
    Android每一个版本都会用一个按照A-Z开头顺序的甜品来命名,但从Android P之后Google改变了这一传统的命名规则,可能是没有那么多让人熟知的甜品代号供使用以及甜品名字并不能让人直观的了解到哪一个甜品有什么特性,于是Google直接采用数字来命令系统,并且加深了logo的颜色,不再使用甜品作为代号。

    Android各版本代号、图片及市场占有率(感兴趣的可以https://blog.csdn.net/csdnxia/article/details/101513820 了解)

    2.2 Android 应用组件

    Android 四大组件分别是:

    • 活动(Activity)

    • 服务(Service)

    • 广播接收器(BroadcasReceiver)

    • 内容提供者(Content Provider)

    • Activity:通俗来讲就是提供一个界面让用户点击和各种滑动操作,例如,你正在QQ软件跟人聊天,突然微信软件有信息来了,你点击上方弹出的信息提示,你跳转到了微信软件去跟人回复信息,此时就相当于是一个Activity,QQ被暂时放到了栈底。

      • 生命周期

    启动Activity: onCreate()—>onStart()—>onResume(),Activity进入运行状态。

    Activity退居后台: 当前Activity转到新的Activity界面或按Home键回到主屏: onPause()—>onStop(),进入停滞状态。

    Activity返回前台: onRestart()—>onStart()—>onResume(),再次回到运行状态。

    Activity退居后台,且系统内存不足, 系统会杀死这个后台状态的Activity,若再次回到这个Activity,则会走onCreate()–>onStart()—>onResume()

    锁定屏与解锁屏幕 只会调用onPause(),而不会调用onStop方法,开屏后则调用onResume()

    • Service:可以在后台执行长时间运行操作而没有用户界面的应用组件(Service 分为两种工作状态,一种是启动状态,主要用于执行后台计算;另一种是绑定状态,主要用于其他组件和 Service 的交互。)

    0x03 反编译工具的使用

    jaasmali含义
    if(A==B)if-eq A,B如果A等于B
    if(A!=B)if-ne A,B如果A不等于B
    if(Aif-lt A,B如果A小于B
    if(A<=B)if-le A,B如果A小于等于B
    if(A>B)if-gt A,B如果A大于B
    if(A>=B)if-ge A,B如果A大于等于B
    if(A==0)if-eqz A如果A等于0
    if(A!=0)if-nez A如果A不等于0
    if(A<08)if-ltz A如果A小于0
    if(A>0)if-gtz A如果A大于0
    if(A>=0)if-gez A如果A大于等于0
    if(A<=0)if-lez A如果A小于等于0

    0x04 Smali 寄存器

    在Smali中,如果需要存储变量,必须先声明足够数量的寄存器,1个寄存器可以存储32位长度的类型,比如Int,而两个寄存器可以存储64位长度类型的数据,比如Long或Double。

    声明可使用的寄存器数量的方式为:.registers N,N代表需要的寄存器的总个数,同时,还有一个关键字 .local ,它用于声明非参数的寄存器个数(包含在registers声明的个数当中),也叫做本地寄存器,只在一个方法内有效,但不常用,一般使用registers即可。

    .registers 3说明该方法有三个寄存器,其中一个本地寄存器v0,两个参数寄存器p0,p1,细心的人可能会注意到没有看到p0,原因是p0存放的是this。如果是静态方法的话就只有2个寄存器了,不需要存this了。

    1.本地寄存器(local register,非参寄存器)用v开头数字结尾的符号来表示,如v0、v1、v2、…,

    2.参数寄存器(parameter register)用p开头数字结尾的符号来表示,如p0、p1、p2、…,

    3…registers 用来标明方法中寄存器的总数,即参数寄存器和非参寄存器的总数。

    4…local 0,标明在这个函数中最少要用到的本地寄存器的个数,出现在方法中的第一行。在这里,由于只需要调用一个父类的onDestroy()处理,所以只需要用到p0,所以使用到的本地寄存器数为0,在植入代码后不要忘记可能要修改.local的值。

    如 .local 4,则可以使用的寄存器是v0-v3。

    5.当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。

    6.在实例函数中,p0代指“this”,p1表示函数的第一个参数,p2代表函数中的第二个参数…,

    7.在static函数中,p1表示函数的第一个参数,p2代表函数中的第二个参数…,因为Java的static方法中没有this方法。

    那么,如何确定需要使用的寄存器的个数?

    由于非static方法,需要占用一个寄存器以保存this指针,那么这类方法的寄存器个数,最低就为1,如果还需要处理传入的参数,则需要再次叠加,此时还需要考虑Double

    4.1 Smali 介绍

    Smali是Davlik的寄存器语言,语法上和汇编语言类似. Davlik是基于寄存器的,就是说smali里的所有操作都必须经过寄存器来进行.

    4.2 Smali 函数定义

    • 函数的定义一般为:函数名(参数类型1参数类型2…)返回值类型
      • 基本数据类型的参数与参数之间没有任何分隔符(,)对象数据类型使用分号(;)结束
    test()V
    
    void test()
    
    
    test(lll)Z
    
    boolean test(int,int,int)
    
    
    test(Z[l[lLjava/lang/String;J)Ljava/lang/String;
    
    String test(boolean,int[],int[],String,long)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    PS:注意: 参数之间没有任何分隔符,返回值在最后

    4.3 Smail 基本语法

    语法语法含义
    .field private isFlag:z定义变量
    .method方法
    .parameter方法参数
    .prologue方法开始
    .line 12此方法位于第12行
    invoke-super调用父函数
    const/high16 v0, 0x7fo3把0x7fo3赋值给v0
    invoke-direct调用函数
    return-void函数返回void
    .end method函数结束
    new-instance创建实例
    iput-object对象赋值
    iget-object调用对象
    invoke-static调用静态函数
    invoke-virtual调用protected或public方法
    #smali注释
    .locals指定方法中非参寄存器总数,出现在方法第一行
    .registers指定方法中寄存器总数
    p0在静态方法中表示当前对象实例
    p1表示当前onCreate方法参数
    v0表示本地(局部)变量,存放在locals寄存器
    move-result获取方法返回基本数据类型
    move-result-object获取方法返回对象
    .class public Lcom/disney/WMW/WMWActivty;类名
    .super Lcom/XXX/XXX/XXX;父类名
    .source “XXX.java”源文件名
    .implements Lcom/XXX/XXX/XXX;实现了接口
    .annotation内部类

    4.4 Smail 基本数据类型

    smali类型java类型
    Vvoid
    Zboolean
    Bbyte
    Sshort
    Cchar
    Iint
    Jlong (64位 需要2个寄存器存储)
    Ffloat
    Ddouble (64位 需要2个寄存器存储)
    LJava类类型
    [数组类型

    4.5 Smail 对象

    smali对象java对象
    Lpackage/name/ObjectName;package.name.ObjectName
    Ljava/lang/String;java.lang.String
    L 表示对象类型
    package/name 表示包名
    ; 表示结束

    4.6 Smail 数组

    smali数组java数组
    [Iint[] 一维数组
    [[Iint[][] 二维数组
    [Ljava/lang/StringString[] 对象数组
    • 注:每一维最多255个
    • 一维数组在类型的左边加一个方括号,比如:[I 等同于Java的 int[ ] ,[F 等同于Java的 float[ ] ,每多一维就加一个方括号,最多可以设置255维。

    4.7 Smail 类字段/变量

    Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;

    smali字段java字段
    public f1:Zpublic boolean f1;
    public f2:Ipublic int f2;
    public f3:Ljava/lang/String; public String f3;

    4.7.1 赋值

    • 赋值
      • 静态static
    const-string v0, "Hello Smali"
    
    sput-object v0, Lcom/MyActivity;->name:Ljava/lang/String;
    
    
    • 1
    • 2
    • 3
    • 4

    相当于java代码 MyActivity.name = “Hello Smali”

    • 赋值
      • 非静态instance
    .local v0, act:Lcom/MyActivity;
    
    const/4 v1, 0x2
    
    iput v1, v0, Lcom/MyActivity;->name:Ljava/lang/String;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    相当于java代码 act.name = “Hello Smali”

    4.7.2 取值

    • 取值
      • 静态(static fields)
    sget-object v0, Lcom/MyActivity;->name:Ljava/lang/String;
    
    • 1

    相当于java代码 v0 = MyActivity.name;

    • 取值
      • 非静态(instance fields)
    .local v0, act:Lcom/MyActivity;
    
    iget-object v1, v0 Lcom/MyActivity;->name:Ljava/lang/String;
    
    
    • 1
    • 2
    • 3
    • 4

    相当于java代码 v1 = act.name;

    4.8 类方法/函数

    smali方法java方法
    myMethod([I)Ljava/lang/String;String myMethod(int[])

    例如:

    Lpackage/name/ObjectName;->MethodName(III)Z
    
    • 1

    第一部分:Lpackage/name/ObjectName;用于声明具体的类型,以便JVM寻找

    第二部分:MethodName(III)Z,其中 MethodName 为具体的方法名,()中的字符,表示了参数数量和类型,即3个int型参数,Z为返回值的类型,返回Boolean类型

    由于方法的参数列表没有使用逗号这样的分隔符进行划分,所以只能从左到右,根据类型定义来区分参数个数。

    通过几个例子来说明,以java.lang.String为例:

    java方法:public char charAt(int index){...}
    Davilk描述:Ljava/lang/String;->charAt(I)C
    
    java方法:public void getChars(int srcBegin,int srcEnd,char dst[],int dstBegin){...}
    Davilk描述:Ljava/lang/String;->getChars(II[CI)V
    
    java方法:public boolean equals(Object anObject){...}
    Davilk描述:Ljava/lang/String;->equals(Ljava/lang/Object)Z
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果需要调用构造方法,则MethodName为:

    例子

    String对象在Smali中为:Ljava/lang/String
    
    Class1对象的一个Boolean成员表示为:Lcom/disney/Class1;->isRunning:Z
    
    Class2对象的一个String对象成员表示为:Lcom/disney/Class2;->name:Ljava/lang/String
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 总结为
    对象类型 -> 成员名 : 成员类型
    -> 表示所属关系,类型尾部必须包括一个分号
    
    • 1
    • 2

    //Samli代码

    .method protected onCreate(Landroid/os/Bundle;)V
    
    .locals 1
    
    .parameter "savedInstanceState"
    
    .prologue
    
    .line 8
    
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
    
    .line 9
    
    const/high16 v0, 0x7f03
    
    invoke-virtual {p0, v0}, Lcom/fusijie/helloworld/MainActivity;->setContentView(I)V
    
    .line 10
    
    return-void
    
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    //Java代码

    
    protected void onCreate(Bundle savedInstanceState) {
    
    super.onCreate(savedInstanceState);
    
    setContentView(R.layout.activity_main);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.8.1 Smali函数分析

    4.8.1.1 类型

    smali中的函数和成员变量一样也分为两种:

    • direct
    • virtual
      (1) direct method 就是 private 函数.

    (2)其余的public 和 protected 函数都属于 virtual method.

    eg:
    invoke-direct,invoke-virtual,invole-static
    invole-XXX/range (参数大于等于5个时候调用的指令)
    
    • 1
    • 2
    • 3
    4.8.1.1.1 invoke-static
    • 用于调用static 函数

    • eg:
      invoke-static{},Lcom/aaa;->CheckSignature()Z

    • static后面的一对大括号{},实际就是调用该方法的实例 + 参数列表, 由于方法即不需要参数也是static, 所以{}为空.

    • eg:
      const-string v0,“NDKLIB”
      invoke-staticP{v0},Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

    • static void System.loadLibrary(String) 来加载 NDK编译的so库用的方法, 就是说这里的v0 就是参数"NDKLIB"

    4.8.1.1.2 invoke-super
    • 用于调用父类方法用的指令, 一般用于onCreate,onDestory等方法
    4.8.1.1.3 invoke-direct
    • 调用private 函数

    • eg:
      invoke-direct{p0},Landroid/app/TabActivity;->()V

    • 这里init()就是定义在TabActivity中的一个private函数

    4.8.1.1.4 invoke-virtual
    • 用于调用protectd或 public函数, 同时要注意修改smali时候不要错用invoke-direct或 invoke-static

    • eg:
      sget-object v0,Lcom/ddd;->bbb:Lcom/ccc;

      invoke-virtual{v0,v1},Lcom/ccc;->Message(Ljava/lang/Object;)V

    • v0 就是 bbb:Lcom/ccc

    • v1 就是 Ljava/lang/Object参数

    4.8.1.1.5 invoke-xxx/range
    • 当方法的参数大于等于5个时候,需要在后面加上 “/range”, range表示范围,使用方法也与以上不同

    • eg:
      invoke-direct/range{v0…v5
      },Lcom/pb/ui/TestActivity;->
      h(ILjava/lang/String,Ljava/lang/String;Landroid/content/intent;I)Z

    • 表示需要传递v0到v5 一共6个参数,大括号里的参数采用省略形式, 且需要连续

    4.8.1.1.6 Smali 中函数返回结果的操作
    • Smali中需要分开来表示调用函数和返回函数结果

    • 如果调用的函数返回非void, 还需要
      move-result(返回基本数据类型)和move-result-object(返回对象)指令:

    • eg:
      const-string v0,“Eric”
      invoke-static{v0},Lcom/pbi;->t(Ljava/lang/String;)Ljava/lang/String;
      move-result-object v2;

    • 这里 v2保存的就是调用t方法返回的字符串

    4.8.2 Smali局部变量

    • 本地寄存器 (local register, 非参寄存器)

    常用v开头数字结尾的符号表示 v0,v1,v2…

    • 参数寄存器 (parameter regisgter)

    常用p开头数字结尾的符号来表示 p1,p2,p3…

    • .register 用来标明方法中寄存器的总数,即参数寄存器和非参寄存器

    .local 标明在这个函数中最少要用到本地寄存器的个数,出现在方法第一行.

    4.8.2.1 条件判断语句(if)

    • if-gt 大于
    • if-ge 大于等于
    • if-lt 小于
    • if-le 小于等于
    javasmali含义
    if(vA==vB)if-eq vA,vB如果vA等于vB
    if(vA!=vB)if-ne vA,vB如果vA不等于vB
    if(vAif-lt vA,vB如果vA小于vB
    if(vA<=vB)if-le vA,vB如果vA小于等于vB
    if(vA>vB)if-gt vA,vB如果vA大于vB
    if(vA>=vB)if-ge vA,vB如果vA大于等于vB
    if(vA==0)if-eqz vA如果vA等于0
    if(vA!=0)if-nez vA如果vA不等于0
    if(vA<0)if-ltz vA如果vA小于0
    if(vA>0)if-gtz vA如果vA大于0
    if(vA>=0)if-gez vA如果vA大于等于0
    if(vA<=0)if-lez vA如果vA小于等于0
    private boolean isFlag.field private isFlag:z定义变量
    Package.class
    .super
    .local
    .method
    .parameter
    .prologue
    .line 12
    指定当前的类名
    所继承的父类
    定义使用局部变量
    方法
    方法参数
    方法开始
    此方法位于.java中的第12行,可以在混淆稳重去除,去除不影响运行结果
    superinvoke-super
    const/high16 v0, 0x7fo3
    invoke-direct
    调用父函数
    把0x7fo3赋值给v0
    调用函数
    returnReturn-void
    .end method
    函数返回void
    函数结束
    newnew-instance
    iput-object
    iget-object
    创建实例
    对象赋值
    调用对象

    定义一个函数的时候会首先定义这个函数里面有几个寄存器,寄存器版本不同,寄存器的数量也是不一定是一样的

    4.8.3 Smali的包信息

    • .class public Lcom/aaa;
    • .super Lcom/bbb;
    • .source “ccc.java”

    4.8.3.1 说明

    • 是com.aaa 这个package下的一个类
    • 继承自 com.bbb这个类
    • 是由 ccc.java这个类编译得到的smali文件

    4.8.4 Smali字段声明指令

    smali文件中字段的声明使用“.field”指令,字段有静态字段与实例字段两种:

    静态字段:

    # static fields
    .field <访问权限> static [修饰关键字] <字段名>:<字段类型>
    
    
    • 1
    • 2
    • 3

    实例字段:

    # instance fields  
    .field <访问权限> [修饰关键字] <字段名>:<字段类型>  
    
    • 1
    • 2

    Java代码:

    
    //实例字段
    private byte byteType=0;
    private short shortType=0;
    private int intType=0;
    private long longType=8L;
    private final int[] intArray = {0,1,2,3,4};
    
    //静态字段
    private static float floatType=0F;
    private static double doubleType=6D;
    private static boolean booleanType=Boolean.TRUE;
    private static char charType='a';
    private static final String stringObject = "ABC";
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Smali代码:

    # static fields
    .field private static booleanType:Z = false
    .field private static charType:C = '\u0000'
    .field private static doubleType:D = 0.0
    .field private static floatType:F = 0.0f
    .field private static final stringObject:Ljava/lang/String; = "ABC"
    
    # instance fields
    .field private byteType:B
    .field private final intArray:[I
    .field private intType:I
    .field private longType:J
    .field private shortType:S
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.8.5 Smali数据定义指令、字段操作指令

    Smali数据定义指令

    指令描述
    const/4 vA,#+B将数值符号扩展为32后赋值给寄存器vA
    const-wide/16 vAA,#+BBBB将数值符号扩展为64位后赋值个寄存器对vAA
    const-string vAA,string@BBBB通过字符串索引高走字符串赋值给寄存器vAA
    const-class vAA,type@BBBB通过类型索引获取一个类的引用赋值给寄存器vAA

    Smali字段操作指令-实例字段

    指令描述
    iget vX,pY,filed_id取值,读取pY寄存器中的对象中的filed_id字段值赋值给vX寄存器
    iput vX,pY,filed_id赋值,设置pY寄存器中的对象中filed_id字段的值为vX寄存器的值
    iget-wide vX,pY,filed_id64位,解释见 iget
    iput-wide vX,pY,filed_id64位,解释见 iput
    iget-object vX,pY,filed_id解释见 iget
    iput-object vX,pY,filed_id解释见 iput
    iget-bype、iget-short、iget-long、iget-float、iget-double、iget-boolean、iget-char
    iput-bype、iput-short、iput-long、iput-float、iput-double、iput-boolean、iput-char

    Smali字段操作指令-静态字段

    指令描述
    sget vX,pY,filed_id取值,读取pY寄存器中的对象中的filed_id字段值赋值给vX寄存器
    sput vX,pY,filed_id赋值,设置pY寄存器中的对象中filed_id字段的值为vX寄存器的值
    sget-wide vX,pY,filed_id64位,解释见 sget
    sput-wide vX,pY,filed_id64位,解释见 sput
    sget-object vX,pY,filed_id解释见 sget
    sput-object vX,pY,filed_id解释见 sput
    sget-bype、sget-short、sget-long、sget-float、sget-double、sget-boolean、sget-char
    sput-bype、sput-short、sput-long、sput-float、sput-double、sput-boolean、sput-char

    Java代码:

    //实例字段
    private byte byteType=0;
    private short shortType=0;
    private int intType=0;
    private long longType=8L;
    private final int[] intArray = {0,1,2,3,4};
    
    //静态字段
    private static float floatType=0F;
    private static double doubleType=6D;
    private static boolean booleanType=Boolean.TRUE;
    private static char charType='a';
    private static final String stringObject = "ABC";
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Smali代码:

    # direct methods 静态字段赋值
    .method static constructor ()V
        .registers 2 #.registers指令表示有2个寄存器可用
    
        .prologue #.prologue 方法开始
        .line 10 #行号
        const/4 v0, 0x0 #
        sput v0, Lcom/erlin/smali/SmaliParse;->floatType:F
    
        .line 11
        const-wide/16 v0, 0x0
        sput-wide v0, Lcom/erlin/smali/SmaliParse;->doubleType:D
    
        .line 12
        sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean; #取Boolean对象实例,赋值给v0
        invoke-virtual {v0}, Ljava/lang/Boolean;->booleanValue()Z 
        move-result v0 #将Boolean.TRUE值赋于v0寄存器
        sput-boolean v0, Lcom/erlin/smali/SmaliParse;->booleanType:Z #将v0寄存器的值赋于booleanType字段
    
        .line 13
        const/16 v0, 0x61
        sput-char v0, Lcom/erlin/smali/SmaliParse;->charType:C
        return-void
    .end method
    
    # direct methods 实例字段赋值
    .method public constructor ()V
        .registers 3 #.registers指令表示有3个寄存器可用
    
        .prologue
        const/4 v0, 0x0 #将0赋值给v0
    
        .line 3
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        .line 4
        iput-byte v0, p0, Lcom/erlin/smali/SmaliParse;->byteType:B #p0代表this,将v0的值赋值给byteType字段
    
        .line 5
        iput-short v0, p0, Lcom/erlin/smali/SmaliParse;->shortType:S
    
        .line 6
        iput v0, p0, Lcom/erlin/smali/SmaliParse;->intType:I
    
        .line 7
        const-wide/16 v0, 0x0
        iput-wide v0, p0, Lcom/erlin/smali/SmaliParse;->longType:J
    
        .line 8
        const/4 v0, 0x5 #数组长度赋值给v0寄存器
        new-array v0, v0, [I #创建指定类型[I即int数组,长度为v0即5,并将数组引用赋值于v0寄存器
        fill-array-data v0, :array_18 #用指定标记array_18处的数据填充数组
        iput-object v0, p0, Lcom/erlin/smali/SmaliParse;->intArray:[I #为数组赋值
        return-void 
    
        nop #空 指令
    
        :array_18
        .array-data 4
            0x0
            0x1
            0x2
            0x3
            0x4
        .end array-data
    .end method
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    4.8.6 Smali空指令

    指令描述
    nop空操作指令,通常用于代码对齐,不进行实际操作,值为00

    Smali数组操作指令

    数组操作指令包括读取数组长度、新建数组、数组赋值、数组元素取值与赋值等操作。

    指令描述
    array-length vA,vB获取给定vB寄存器中数组的长度并将值赋给vA寄存器
    new-array vA,vB,type@CCCC构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器
    new-array/jumbo vAAAA,vBBBB,type@CCCCCCCC指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大
    filled-new-array {vC,vD,vE,vF,vG},type@BBBB构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还制订了参数的个数,vC~vG是使用到的参数寄存器序列
    filled-new-array/range {vCCCC, … ,vNNNN},type@BBBB指定功能与上一条指令相同,只是参数寄存器使用range字节码后缀指定了取值范围,vC是第一个参数寄存器, N=A+C-1。
    filled-new-array/jumbo {vCCCC, … ,vNNNN},type@BBBBBBBB指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大.
    arrayop vAA,vBB,vCC对vBB寄存器指定的数组元素进入取值与赋值。vCC寄存器指定数组元素索引,vAA寄存器用来寄放读取的或需要设置的数组元素的值。读取元素使用 aget类指令,元素赋值使用aput指令,元素赋值使用aput类指令,根据数组中存储的类型指令后面会紧跟不同的指令后缀,指令列表有aget、 aget-wide、aget-object、aget-boolean、aget-byte、aget-char、aget-short、aput、 aput-wide、aput-boolean、aput-byte、aput-char、aput-short。

    java代码:

    public void array() {
        int[] intArray = {10, -1, 9};
        int len = intArray.length;
    
        String[] stringArray = new String[len];
        stringArray[0] = "A";
        stringArray[1] = "B";
        stringArray[2] = "C";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Smali代码:

    .method public array()V
        .registers 6 #.registers 声明6个寄存器
    
        .prologue
        .line 5
        const/4 v3, 0x3 #将0x3寄存给v3寄存器
        new-array v0, v3, [I #创建[I类型长度为v3寄存器数组,引用赋值给v0寄存器
        fill-array-data v0, :array_1a #用array_1a标记处数据,赋值于v0寄存器
    
        .line 6
        .local v0, "intArray":[I #创建指定类型数组,并用v0寄存器中的值填充数据,赋于寄存器v0
        array-length v1, v0 #获取v0寄存器长度,赋值给v1寄存器
    
        .line 8
        .local v1, "len":I
        new-array v2, v1, [Ljava/lang/String;
    
        .line 9
        .local v2, "stringArray":[Ljava/lang/String;
        const/4 v3, 0x0
        const-string v4, "A"
        aput-object v4, v2, v3 #v4寄存器值,赋值给v2寄存器数组,数组索引为v3
    
        .line 10
        const/4 v3, 0x1
        const-string v4, "B"
        aput-object v4, v2, v3
    
        .line 11
        const/4 v3, 0x2
        const-string v4, "C"
        aput-object v4, v2, v3
    
        .line 12
        return-void
    
        .line 5
        nop
    
        :array_1a
        .array-data 4
            0xa
            -0x1
            0x9
        .end array-data
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4.8.8 Smali类指令,Smali方法指令,Smali返回指令

    Smali类指令

    类指令描述
    .class <访问权限> [修饰关键字] L<完整类名>;表示类
    .super L<父类完整类名>;父类
    .source “Java类名”java文件名
    注解指令
    .annotation[注解属性] <注解类名>
    value = {值列表}
    .end annotation注解结束
    接口指令
    .implements<接口名>接口名

    案例一:Java类

    //java
    package com.erlin.smali;
    public class SmaliParse {//基类Object
        //类
    }
    //Smali
    .class public Lcom/erlin/smali/SmaliParse;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    案例二:Java final类

    //Java
    package com.erlin.smali;
    public final class SmaliParse {//基类Object
        //类
    }
    
    //Smali
    .class public final Lcom/erlin/smali/SmaliParse;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    案例三:Java Interface类

    //Java
    package com.erlin.smali;
    public interface Interface {
        void interfaceMethod();
    }
    
    //Smali
    .class public interface abstract Lcom/erlin/smali/Interface;
    .super Ljava/lang/Object;
    .source "Interface.java"
    
    
    # virtual methods
    .method public abstract interfaceMethod()V
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    案例四:Java Interface类实现

    //Java
    package com.erlin.smali;
    public class InterfaceImpl implements Interface{
        @Override
        public void interfaceMethod() {
    
        }
    }
    
    //Smali
    .class public Lcom/erlin/smali/InterfaceImpl;
    .super Ljava/lang/Object;
    .source "InterfaceImpl.java"
    
    # interfaces
    .implements Lcom/erlin/smali/Interface;
    
    
    # direct methods
    .method public constructor ()V
        .registers 1
    
        .prologue
        .line 3
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    
    # virtual methods
    .method public interfaceMethod()V
        .registers 1
    
        .prologue
        .line 7
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    案例五:抽象类

    //Java
    package com.erlin.smali;
    public abstract class  AbstractClass {
        abstract void abstractMethod();
    
        public void method(){
    
        }
    }
    
    //Smali
    .class public abstract Lcom/erlin/smali/AbstractClass;
    .super Ljava/lang/Object;
    .source "AbstractClass.java"
    
    
    # direct methods
    .method public constructor ()V
        .registers 1
    
        .prologue
        .line 3
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    # virtual methods
    .method abstract abstractMethod()V
    .end method
    
    .method public method()V
        .registers 1
    
        .prologue
        .line 8
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    案例六:内部类、内部接口、内部抽象类

    SmaliParse.java

    //Java
    package com.erlin.smali;
    public final class SmaliParse {
        //内部类
        public class InnerClass{
            public void method(){}
        }
        //内部接口
        public interface InnerInterface{
            void interfaceMethod();
        }
        //内部抽象类
        public abstract class InnerAbstractClass{
            abstract void interfaceMethod();
            public void method(){}
        }
        //内部类继承
        public class InnerClassExtends extends InnerClass{
            public void method(){}
        }
        //内部接口实现
        class InnerInterfaceImpl implements InnerInterface{
            public void method(){}
            @Override
            public void interfaceMethod() {
    
            }
        }
        //内部抽象类继承
        class InnerAbstractClassExtends extends InnerAbstractClass{
            public void method(){}
            @Override
            void interfaceMethod() {
    
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    SmaliParse.Smali文件

    .class public final Lcom/erlin/smali/SmaliParse;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/MemberClasses;
        value = {
            Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;,
            Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;,
            Lcom/erlin/smali/SmaliParse$InnerClassExtends;,
            Lcom/erlin/smali/SmaliParse$InnerAbstractClass;,
            Lcom/erlin/smali/SmaliParse$InnerInterface1;,
            Lcom/erlin/smali/SmaliParse$InnerInterface;,
            Lcom/erlin/smali/SmaliParse$InnerClass;
        }
    .end annotation
    
    
    # direct methods
    .method public constructor ()V
        .registers 1
    
        .prologue
        .line 3
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    SmaliParse$InnerClass.smali文件

    
    .class public Lcom/erlin/smali/SmaliParse$InnerClass;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x1
        name = "InnerClass"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
    
    
    # direct methods
    .method public constructor (Lcom/erlin/smali/SmaliParse;)V
        .registers 2
        .param p1, "this$0"    # Lcom/erlin/smali/SmaliParse;
    
        .prologue
        .line 4
        iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerClass;->this$0:Lcom/erlin/smali/SmaliParse;
    
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    
    # virtual methods
    .method public method()V
        .registers 1
    
        .prologue
        .line 5
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    SmaliParse$InnerInterface.smali

    .class public interface abstract Lcom/erlin/smali/SmaliParse$InnerInterface;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x609
        name = "InnerInterface"
    .end annotation
    
    
    # virtual methods
    .method public abstract interfaceMethod()V
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    SmaliParse$InnerAbstractClass.smali

    .class public abstract Lcom/erlin/smali/SmaliParse$InnerAbstractClass;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x401
        name = "InnerAbstractClass"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
    
    
    # direct methods
    .method public constructor (Lcom/erlin/smali/SmaliParse;)V
        .registers 2
        .param p1, "this$0"    # Lcom/erlin/smali/SmaliParse;
    
        .prologue
        .line 15
        iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerAbstractClass;->this$0:Lcom/erlin/smali/SmaliParse;
    
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    
    # virtual methods
    .method abstract interfaceMethod()V
    .end method
    
    .method public method()V
        .registers 1
    
        .prologue
        .line 17
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    SmaliParse$InnerInterfaceImpl.smali

    .class Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;
    .super Ljava/lang/Object;
    .source "SmaliParse.java"
    
    # interfaces
    .implements Lcom/erlin/smali/SmaliParse$InnerInterface;
    .implements Lcom/erlin/smali/SmaliParse$InnerInterface1;
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x0
        name = "InnerInterfaceImpl"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
    
    
    # direct methods
    .method constructor (Lcom/erlin/smali/SmaliParse;)V
        .registers 2
        .param p1, "this$0"    # Lcom/erlin/smali/SmaliParse;
    
        .prologue
        .line 24
        iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;->this$0:Lcom/erlin/smali/SmaliParse;
    
        invoke-direct {p0}, Ljava/lang/Object;->()V
    
        return-void
    .end method
    
    
    # virtual methods
    .method public interfaceMethod()V
        .registers 1
    
        .prologue
        .line 29
        return-void
    .end method
    
    .method public interfaceMethod1()V
        .registers 1
    
        .prologue
        .line 34
        return-void
    .end method
    
    .method public method()V
        .registers 1
    
        .prologue
        .line 25
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    SmaliParse$InnerClassExtends.smali

    .class public Lcom/erlin/smali/SmaliParse$InnerClassExtends;
    .super Lcom/erlin/smali/SmaliParse$InnerClass;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x1
        name = "InnerClassExtends"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
    
    
    # direct methods
    .method public constructor (Lcom/erlin/smali/SmaliParse;)V
        .registers 2
        .param p1, "this$0"    # Lcom/erlin/smali/SmaliParse;
    
        .prologue
        .line 20
        iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerClassExtends;->this$0:Lcom/erlin/smali/SmaliParse;
    
        invoke-direct {p0, p1}, Lcom/erlin/smali/SmaliParse$InnerClass;->(Lcom/erlin/smali/SmaliParse;)V
    
        return-void
    .end method
    
    
    # virtual methods
    .method public method()V
        .registers 1
    
        .prologue
        .line 21
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    SmaliParse$InnerAbstractClassExtends.smali

    
    .class Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;
    .super Lcom/erlin/smali/SmaliParse$InnerAbstractClass;
    .source "SmaliParse.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/erlin/smali/SmaliParse;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x0
        name = "InnerAbstractClassExtends"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
    
    
    # direct methods
    .method constructor (Lcom/erlin/smali/SmaliParse;)V
        .registers 2
        .param p1, "this$0"    # Lcom/erlin/smali/SmaliParse;
    
        .prologue
        .line 37
        iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;->this$0:Lcom/erlin/smali/SmaliParse;
    
        invoke-direct {p0, p1}, Lcom/erlin/smali/SmaliParse$InnerAbstractClass;->(Lcom/erlin/smali/SmaliParse;)V
    
        return-void
    .end method
    
    
    # virtual methods
    .method interfaceMethod()V
        .registers 1
    
        .prologue
        .line 42
        return-void
    .end method
    
    .method public method()V
        .registers 1
    
        .prologue
        .line 38
        return-void
    .end method
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • Smali方法指令-静态方法
    指令描述
    .method <访问权限> static [修饰关键字] methodName()<类型>
    .registers count方法内使用寄存器数量
    .prologue方法开始
    return-void方法返回数据类型
    .end method方法结束

    案例一:

    //Java
    public static void methodStaticSmali(){
        //静态方法
    }
    
    //Smali
    .method public static methodStaticSmali()V
        .registers 0
    
        .prologue
        return-void
    .end method
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    案例二:

    //Java
    public final static void methodStaticFinalSmali() {
        //静态方法
    }
    
    //Smail
    .method public static final methodStaticFinalSmali()V
        .registers 0
    
        .prologue
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • Smali返回指令
    指令描述
    return-void返回Void类型
    return vAA返回非32位对象类型值,返回值为8位寄存器vAA
    return-wide vAA返回非64位对象类型值,返回值为8位寄存器对vAA
    return-object vAA返回对象类型,返回值为8位寄存器对vAA

    案例一:

    // Java
    public void methodSmali() {
    }
    
    //Smali
    .method public methodSmali()V
        .registers 1
    
        .prologue
        .line 6
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    案例二:

    //Java
    public int methodSmaliInt(){
        return Integer.MAX_VALUE;
    }
    
    //Smali
    .method public methodSmaliInt()I
        .registers 2
    
        .prologue
        .line 9
        const v0, 0x7fffffff
    
        return v0
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    案例三:

    //Java
    public long methodSmaliLong(){
        return Long.MAX_VALUE;
    }
    
    //Smali
    .method public methodSmaliLong()J
        .registers 3
    
        .prologue
        .line 13
        const-wide v0, 0x7fffffffffffffffL
    
        return-wide v0
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    案例四:

    //Java
    public String methodSmaliString(){
        return "String";
    }
    
    //Smali
    .method public methodSmaliString()Ljava/lang/String;
        .registers 2
    
        .prologue
        .line 17
        const-string v0, "String"
    
        return-object v0
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.8.8.1 方法操作指令

    方法调用指令负责调用类实例的方法,基础指令为invoke。

    指令描述
    invoke-virtual{parameters}, methodtocall虚方法调用,调用的方法运行时确认实际调用,和实例引用的实际对象有关,动态确认的,一般是带有修饰符protected或public的方法.
    invoke-super {parameter},methodtocall直接调用父类的虚方法,编译时,静态确认的。
    invoke-direct { parameters }, methodtocall没有被覆盖方法的调用,即不用动态根据实例所引用的调用,编译时,静态确认的,一般是private或方法;
    invoke-static {parameters}, methodtocall是类静态方法的调用,编译时,静态确定的
    invoke-interface {parameters},methodtocall调用接口方法,调用的方法运行时确认实际调用,即会在运行时才确定一个实现此接口的对象

    案例一:

    //Java
    public void invokeMethod(){
        BaseClassImpl baseClassImpl = new BaseClassImpl();
        baseClassImpl.baseFinalMethod();
        super.baseFinalMethod();
        baseClassImpl.staticMethod();
        ((Interface)baseClassImpl).interfaceMethod();
        baseClassImpl.method();
    }
    //Smali
    .method public invokeMethod()V
        .registers 2
    
        .prologue
        .line 17
        new-instance v0, Lcom/erlin/smali/BaseClassImpl;
    
        invoke-direct {v0}, Lcom/erlin/smali/BaseClassImpl;->()V
    
        .line 18
        .local v0, "baseClassImpl":Lcom/erlin/smali/BaseClassImpl;
        invoke-virtual {v0}, Lcom/erlin/smali/BaseClassImpl;->baseFinalMethod()V
    
        .line 19
        invoke-super {p0}, Lcom/erlin/smali/BaseClass;->baseFinalMethod()V
    
        .line 20
        invoke-static {}, Lcom/erlin/smali/BaseClassImpl;->staticMethod()V
    
        .line 21
        invoke-interface {v0}, Lcom/erlin/smali/Interface;->interfaceMethod()V
    
        .line 22
        invoke-virtual {v0}, Lcom/erlin/smali/BaseClassImpl;->method()V
    
        .line 23
        return-void
    .end method
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    4.8.9 实例操作指令

    指令描述
    instance-of vA, vB, type@CCCC用于判断vB寄存器中对象引用是否可以转换成指定的类型,如果可以转换vA寄存器值为1,否则vA寄存器值为0
    例:if(innerClassExtends instanceof InnerClass){
    }
    check-cast vAA, type@BBBB将vAA寄存器中的对象引用转换成指定的类型,如果不能转换则抛出ClassCatException异常。如果type@BBBB指定的是基本类型,那么对非基本类型的类型vAA来说,运行将会失败。
    new-instance vAA,type@CCCC用于构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器。

    案例一:

    //Java
    public void instanceOperationMethod(){
        InnerClass innerClass = new InnerClass();
        InnerClassExtends innerClassExtends = (InnerClassExtends)innerClass;
    
        if(innerClass instanceof InnerClassExtends){
    
        }
    }
    //Smali
    # virtual methods
    .method public instanceOperationMethod()V
        .registers 4
    
        .prologue
        .line 41
        new-instance v0, Lcom/erlin/smali/SmaliParse$InnerClass;
    
        invoke-direct {v0, p0}, Lcom/erlin/smali/SmaliParse$InnerClass;->(Lcom/erlin/smali/SmaliParse;)V
    
        .local v0, "innerClass":Lcom/erlin/smali/SmaliParse$InnerClass;
        move-object v1, v0
    
        .line 42
        check-cast v1, Lcom/erlin/smali/SmaliParse$InnerClassExtends;
    
        .line 44
        .local v1, "innerClassExtends":Lcom/erlin/smali/SmaliParse$InnerClassExtends;
        instance-of v2, v0, Lcom/erlin/smali/SmaliParse$InnerClassExtends;
    
        if-eqz v2, :cond_c
    
        .line 47
        :cond_c
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    4.8.11 Smali数据运算指令

    Smali算数运算:加、减、乘、除、模(取余)

    指令描述
    add-type vAA, vBB, vCC加:type 类型后缀包括 int、long、float、double,vAA=(vBB+vCC)
    sub-type vAA, vBB, vCC减:type 类型后缀包括 int、long、float、double,vAA=(vBB-vCC)
    mul-type vAA, vBB, vCC乘:type 类型后缀包括 int、long、float、double,vAA=(vBB*vCC)
    div-type vAA, vBB, vCC除:type 类型后缀包括 int、long、float、double,vAA=(vBB/vCC)
    rem-type vAA, vBB, vCC模:type 类型后缀包括 int、long、float、double,vAA=(vBB%vCC)

    Java代码:

    public void number(){
        int a = 3;
        int b = 7;
    
        int add = a+b;
        int sub = b-a;
        int mul = a*b;
        int div = b/a;
        int rem = a%b;
    
        a++;
        b--;
    
        a+=b;
        b+=a;
    
        a*=b;
        b*=a;
    
        a/=b;
        b/=a;
    
        a%=b;
        b%=a;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Smali代码:

    .method public number()V
        .registers 8
    
        .prologue
        .line 5
        const/4 v0, 0x3
    
        .line 6
        .local v0, "a":I
        const/4 v2, 0x7
    
        .line 8
        .local v2, "b":I
        add-int v1, v0, v2 #v1 = v0+v2
    
        .line 9
        .local v1, "add":I
        sub-int v6, v2, v0 #v6=v2-v0
    
        .line 10
        .local v6, "sub":I
        mul-int v4, v0, v2 #v4=v0*v2
    
        .line 11
        .local v4, "mul":I
        div-int v3, v2, v0 #v3=v2/v0
    
        .line 12
        .local v3, "div":I
        rem-int v5, v0, v2 #v5=v0%v2
    
        .line 14
        .local v5, "rem":I
        add-int/lit8 v0, v0, 0x1 #v0=v0+0x1即 ++ 运算符
    
        .line 15
        add-int/lit8 v2, v2, -0x1 #v2=v2-0x1即 -- 运算符
    
        .line 17
        add-int/lit8 v0, v0, 0x6 #v0=v0+0x6
    
        .line 18
        add-int/lit8 v2, v2, 0xa #v2=v2+0xa
    
        .line 20
        mul-int/lit8 v0, v0, 0x10
    
        .line 21
        mul-int/lit16 v2, v2, 0xa0
    
        .line 23
        div-int/2addr v0, v2 #v0=v0/v2
    
        .line 24
        div-int/2addr v2, v0
    
        .line 26
        rem-int/2addr v0, v2 #v0=v0%v2
    
        .line 27
        rem-int/2addr v2, v0
    
        .line 28
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    Smali位运算符:&、|、^、<<、>>

    指令描述
    and-type vAA, vBB, vCCand:type类型后缀包括 int、long、float、double,vAA=(vBB and vCC)
    or-type vAA, vBB, vCCor:type类型后缀包括 int、long、float、double,vAA=(vBB or vCC)
    xor-type vAA, vBB, vCCxor:type类型后缀包括 int、long、float、double,vAA=(vBB xor vCC)
    shl-type vAA, vBB, vCC有符号左移:type类型后缀包括 int、long、float、double,vAA=(vBB << vCC)
    shr-type vAA, vBB, vCC有符号右移:type类型后缀包括 int、long、float、double,vAA=(vBB >> vCC)
    ushr-type vAA, vBB, vCC无符号右移:type类型后缀包括 int、long、float、double,vAA=(vBB >> vCC)

    Java代码:

    public void number(){
        int a = 3;
        int b = 7;
    
        int c = (a&b);
        c = (a|b);
        c = (a^b);
        c=(a<>b);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Smali代码:

    .method public number()V
        .registers 4
    
        .prologue
        .line 5
        const/4 v0, 0x3
    
        .line 6
        .local v0, "a":I
        const/4 v1, 0x7
    
        .line 8
        .local v1, "b":I
        and-int v2, v0, v1
    
        .line 9
        .local v2, "c":I
        or-int v2, v0, v1
    
        .line 10
        xor-int v2, v0, v1
    
        .line 11
        shl-int v2, v0, v1
    
        .line 12
        shr-int v2, v0, v1
    
        .line 13
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    4.8.12 goto跳转指令

    无条件跳转

    指令描述
    goto +AA无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为8位
    goto/16 +AAAA无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为16位
    goto/32 +AAAAAAAA无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为32位

    PS:代码参见 for/whlie 循环

    4.8.13 if跳转指令

    if-test vA, vB, +CCCC:

    指令描述
    if-ne vA, vB, +CCCC如果vA!=vB,则跳转到CCCC位置
    if-eq vA, vB, +CCCC如果vA==vB,则跳转到CCCC位置
    if-lt vA, vB, +CCCC如果vA < vB,则跳转到CCCC位置
    if-le vA, vB, +CCCC如果vA <= vB,则跳转到CCCC位置
    if-gt vA, vB, +CCCC如果vA > vB,则跳转到CCCC位置
    if-ge vA, vB, :CCCC如果vA >= vB,则跳转到CCCC位置

    Java代码:

    public void ifSmali(){
        int a = 8;
        int b = 8;
        if(a == b){
            a+=a;
        }else if(a!=b){
            b+=b;
        }else if(ab){
            b+=a;
        }else if(a>=b){
            a+=1;
        }else if(a<=b){
            b+=1;
        }else{
            a+=2;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Smali代码:

    .method public ifSmali()V
        .registers 3
    
        .prologue
        .line 19
        const/16 v0, 0x8
    
        .line 20
        .local v0, "a":I
        const/16 v1, 0x8
    
        .line 21
        .local v1, "b":I
        if-ne v0, v1, :cond_8
    
        .line 22
        add-int/2addr v0, v0
    
        .line 36
        :goto_7
        return-void
    
        .line 23
        :cond_8
        if-eq v0, v1, :cond_c
    
        .line 24
        add-int/2addr v1, v1
    
        goto :goto_7
    
        .line 25
        :cond_c
        if-ge v0, v1, :cond_10
    
        .line 26
        add-int/2addr v0, v1
    
        goto :goto_7
    
        .line 27
        :cond_10
        if-le v0, v1, :cond_14
    
        .line 28
        add-int/2addr v1, v0
    
        goto :goto_7
    
        .line 29
        :cond_14
        if-lt v0, v1, :cond_19
    
        .line 30
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_7
    
        .line 31
        :cond_19
        if-gt v0, v1, :cond_1e
    
        .line 32
        add-int/lit8 v1, v1, 0x1
    
        goto :goto_7
    
        .line 34
        :cond_1e
        add-int/lit8 v0, v0, 0x2
    
        goto :goto_7
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    if-testz vAA, +BBBB

    指令描述
    if-eqz vAA,+BBBB如果vAA==0,则跳转到BBBB
    if-nez vAA,+BBBB如果vAA!=0,则跳转到BBBB
    if-ltz vAA,+BBBB如果vAA<0,则跳转到BBBB
    if-lez vAA,+BBBB如果vAA<=0,则跳转到BBBB
    if-gtz vAA,+BBBB如果vAA>0,则跳转到BBBB
    if-gez vAA,+BBBB如果vAA>=0,则跳转到BBBB

    Java代码

    public void ifSmali(){
        int a = 0;
        boolean b = false;
        if(b){
            a++;
        }else if(!b){
            b=!b;
        }else if(a<0){
            a++;
        }else if(a>0){
            a++;
        }else if(a>=0){
            a+=1;
        }else if(a<=0){
            a++;
        }else{
            a+=2;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Smali代码

    .method public ifSmali()V
        .registers 3
    
        .prologue
        .line 39
        const/4 v0, 0x0
    
        .line 40
        .local v0, "a":I
        const/4 v1, 0x0
    
        .line 41
        .local v1, "b":Z
        if-eqz v1, :cond_7
    
        .line 42
        add-int/lit8 v0, v0, 0x1
    
        .line 56
        :goto_6
        return-void
    
        .line 43
        :cond_7
        if-nez v1, :cond_f
    
        .line 44
        if-nez v1, :cond_d
    
        const/4 v1, 0x1
    
        :goto_c
        goto :goto_6
    
        :cond_d
        const/4 v1, 0x0
    
        goto :goto_c
    
        .line 45
        :cond_f
        if-gez v0, :cond_14
    
        .line 46
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_6
    
        .line 47
        :cond_14
        if-lez v0, :cond_19
    
        .line 48
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_6
    
        .line 49
        :cond_19
        if-ltz v0, :cond_1e
    
        .line 50
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_6
    
        .line 51
        :cond_1e
        if-gtz v0, :cond_23
    
        .line 52
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_6
    
        .line 54
        :cond_23
        add-int/lit8 v0, v0, 0x2
    
        goto :goto_6
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    4.8.13 switch跳转指令

    指令描述
    sparse-switch vAA, +BBBBBBBB分支跳转指令:vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个sparse-switch-payload格式的偏移表,表中的值是无规律的偏移量。

    Smali偏移表-整形顺序结构:

    packed-switch p1, :pswitch_data_c #偏移表pswitch_data_c
    add-int/lit8 p1, p1, 0x1 #如果 switch 表没有命中case,则顺序执行代码,即default
    
    :pswitch_6
    add-int/lit8 p1, p1, 0x1
     
    :pswitch_9
    add-int/lit8 p1, p1, -0x1
    
    :pswitch_data_c #偏移表位置
    .packed-switch 0x0 #指定头偏移为0x0 
        :pswitch_6 #case 0
        :pswitch_9 #case 1
    .end packed-switch
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Smali偏移表-整形非顺序结构:

    
    sparse-switch p1, :sswitch_data_c
    add-int/lit8 p1, p1, 0x1 #如果 switch 表没有命中case,则顺序执行代码,即default
    
    :sswitch_6
    add-int/lit8 p1, p1, 0x1
    
    :sswitch_9
    add-int/lit8 p1, p1, -0x1
    
    :sswitch_data_c
    .sparse-switch
        0x50 -> :sswitch_6 #case 80
        0x3f1 -> :sswitch_9 #case 1009
    .end sparse-switch
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Java代码:

    public void switchSmali(int value) {
        switch (value) {
            case 0:
                value++;
                break;
            case 1:
                value--;
                break;
            default:
                ++value;
                break;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Smali顺序结构代码:

    .method public switchSmali(I)V
        .registers 2
        .param p1, "value"    # I
    
        .prologue
        .line 5
        packed-switch p1, :pswitch_data_c
    
        .line 13
        add-int/lit8 p1, p1, 0x1
    
        .line 16
        :goto_5
        return-void
    
        .line 7
        :pswitch_6
        add-int/lit8 p1, p1, 0x1
    
        .line 8
        goto :goto_5
    
        .line 10
        :pswitch_9
        add-int/lit8 p1, p1, -0x1
    
        .line 11
        goto :goto_5
    
        .line 5
        :pswitch_data_c
        .packed-switch 0x0
            :pswitch_6
            :pswitch_9
        .end packed-switch
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    Java代码

    
    public void switchSmali(int value) {
        switch (value) {
            case 80:
                value++;
                break;
            case 1009:
                value--;
                break;
            default:
                ++value;
                break;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Smali非顺序结构代码:

    
    .method public switchSmali(I)V
        .registers 2
        .param p1, "value"    # I
    
        .prologue
        .line 7
        sparse-switch p1, :sswitch_data_c
    
        .line 15
        add-int/lit8 p1, p1, 0x1
    
        .line 18
        :goto_5
        return-void
    
        .line 9
        :sswitch_6
        add-int/lit8 p1, p1, 0x1
    
        .line 10
        goto :goto_5
    
        .line 12
        :sswitch_9
        add-int/lit8 p1, p1, -0x1
    
        .line 13
        goto :goto_5
    
        .line 7
        :sswitch_data_c
        .sparse-switch
            0x50 -> :sswitch_6
            0x3f1 -> :sswitch_9
        .end sparse-switch
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4.8.14 for/whlie 循环

    for/whlie循环最终表现的Smali指令形式是goto指令,参见 八、goto跳转指令

    Smali循环基础代码:

    :goto_1 #goto标签
    if-ge vAA, vBB, :+CCCCCCCC #vAA寄存器>=vBB寄存器,跳至+CCCCCCCC即循环体外
    
    add-int/lit8 vAA, vAA, 0x1 #条件递增或递减
    
    goto :goto_1 #goto跳转到goto_1标签
    
    :+CCCCCCCC
    #for循环之外的代码
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    for循环代码:

    //Java代码
    public void forSmali(){
        for(int i=0;i<100;i++){
        }
    }
    //Smail代码
    .method public forSmali()V
        .registers 3
    
        .prologue
        .line 66
        const/4 v0, 0x0
    
        .local v0, "i":I
        :goto_1
        const/16 v1, 0x64
    
        if-ge v0, v1, :cond_8
    
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_1
    
        .line 70
        :cond_8
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    while循环代码:

    //Java
    public void whileSmali(){
        int i = 0;
        while (i<100){
            i++;
        }
    }
    //Smali
    .method public whileSmali()V
        .registers 3
    
        .prologue
        .line 73
        const/4 v0, 0x0
    
        .line 74
        .local v0, "i":I
        :goto_1
        const/16 v1, 0x64
    
        if-ge v0, v1, :cond_8
    
        .line 75
        add-int/lit8 v0, v0, 0x1
    
        goto :goto_1
    
        .line 77
        :cond_8
        return-void
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    4.8.15 try/catch

    指令描述
    :try_start_标号try的开始
    :try_end_标号try的结束
    .catch <异常类型> {< try_start_标号> … < try_end_标号>} < catch_标号>.catch指令:catch指令指明异常类型,指明try块的开始和结束,如果异常捕获成功,则会跳转到catch_标号处,如果捕获不成功,则顺序执行代码

    try/catch Smali基础代码:

    :try_start_0
    const-string v0, "a"
    
    invoke-static {v0}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
    :try_end_5
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_5} :catch_6
    
    :goto_5
    return-void
    
    :catch_6
    move-exception v0
    
    goto :goto_5
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    try/catch代码

    
    //Java
    public void tryCatchSmali() {
        try {
            Integer.valueOf("a");
        } catch (Exception e) {
    
        }
    }
    //Smali
    .method public tryCatchSmali()V
        .registers 2
    
        .prologue
        .line 81
        :try_start_0
        const-string v0, "a"
    
        invoke-static {v0}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
        :try_end_5
        .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_5} :catch_6
    
        .line 85
        :goto_5
        return-void
    
        .line 82
        :catch_6
        move-exception v0
    
        goto :goto_5
    .end method
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    参考链接

    https://www.jianshu.com/p/2766b76da201

    https://www.cnblogs.com/lee0oo0/p/3728271.html

    https://blog.csdn.net/pwelyn/article/details/50487404/

    https://blog.csdn.net/qq_36252044/article/details/86636885


    我自横刀向天笑,去留肝胆两昆仑


  • 相关阅读:
    第一篇博客:HTML:background的使用
    SpringCloud Netflix-Eureka使用
    执法记录仪如何防抖
    Springboot+vue的人事管理系统(有报告),Javaee项目,springboot vue前后端分离项目。
    使用hugo+github搭建免费个人博客
    【网络安全带你练爬虫-100练】第21练:批量获取文件夹中文件名
    【MySQL进阶】多表连接的原理
    linux 系统安装 or-tools 并在c++ 项目中使用
    正则表达式符号
    Spring很常用的@Conditional注解的使用场景和源码解析
  • 原文地址:https://blog.csdn.net/Ananas_Orangey/article/details/126219924