Smali是什么?

简介

Smali支持注解、调试信息、行数信息等基本Java的基本特性,可以说是很接近Java编译在JVM上的中间语言了,一般用来做Android程序的逆向工程

由于Smali是用于Dalvik和Art(Android虚拟机)的反汇编程序实现

APK文件>dex文件>smali文件>修改代码

所以smali语言是Dalvik的反汇编语言

B---byte

C---char

D---double

F---float

I---int

J---long

S---short

V---void

Z---boolean

[XXX---array

Lxxx/yyy---object

这里解析下最后两项,数组的表示方式是:在基本类型前加上前中括号“[”,例如int数组和float数组分别表示为:[I、[F;对象的表示则以L作为开头,格式是LpackageName/objectName;(注意必须有个分号跟在最后),例如String对象在smali中为:Ljava/lang/String;,其中java/lang对应java.lang包,String就是定义在该包中的一个对象。

或许有人问,既然类是用LpackageName/objectName;来表示,那类里面的内部类又如何在smali中引用呢?答案是:LpackageName/objectName$subObjectName;。也就是在内部类前加“$”符号

二、函数的定义

函数的定义一般为:

Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type

参数与参数之间没有任何分隔符:

1. foo ()V

>>>>void foo()。

2. foo (III)Z

>>>>boolean foo(int, int, int)。

3. foo (Z[I[ILjava/lang/String;J)Ljava/lang/String;

>>>>String foo (boolean, int[], int[], String, long)

Smali 格式结构

.class [修饰关键字] .super .source

1 .class public Lcom/disney/WMW/WMWActivity;#是com.disney.WMW这个package下的一个类

2 .super Lcom/disney/common/BaseActivity;#继承自com.disney.common.BaseActivity

3 .source "WMWActivity.java"#这是一个由WMWActivity.java编译得到的smali文件4

5 # interfaces接口信息6 .implements Lcom/burstly/lib/ui/IBurstlyAdListener;#这个WMWActivity实现了一个com.burstly.lib.ui这个package下(一个广告SDK)的IBurstyAdListener接口。

7

8 # annotations内部类9 .annotation system Ldalvik/annotation/MemberClasses;10 value = {#有两个成员内部类11 Lcom/disney/WMW/WMWActivity$MessageHandler;,

12 Lcom/disney/WMW/WMWActivity$FinishActivityArgs;13 }14 .end annotation15

由此可以的出源java文件

class WMWActivity extends BaseActivity implementsIBurstlyAdListener{//... 继承 接口

classMessageHandler {//...

}classFinishActivityArgs{//...

}

}

# static fields静态域

.field private static final PREFS_INSTALLATION_ID:Ljava/lang/String; = "installationId"# instance fields实例域

.fieldprivate _activityPackageName:Ljava/lang/String;

static fields和instance fields均为成员变量

instance field 是对象的变量,每一个这个类的对象都会有一个该instance field

#static fields

.field static [修饰关键字] :

baksmali 在生成 Smali 文件时,会在静态字段声明的起始处添加“static fields”注释,Smali 文件中的注释与 Dalvik 语法一样,也是以井号“#”开头。“.field”指令后面跟着的是访问权限,可以是 public、private、protected 之一。修饰关键字描述了字段的其它属性,如synthetic。指令的最后是字段名与字段类型,使用冒号“:”分隔,语法上与 Dalvik 也是一样的。实例字段的声明与静态字段类似,只是少了 static 关键字,它的格式如下。

#instance fields

.field [修饰关键字] :

比如以下的实例字段声明。

1 #instance fields2 .field private btn:Landroid/widget/Button;

第 1 行的“instance fields”是 baksmali 生成的注释,第 2 行表示一个私有字段 btn,它的类型为“Landroid/widget/Button;”。如果一个类中含有方法,那么类中必然会有相关方法的反汇编代码,Smali 文件中方法的声明使用“.method”指令。方法有直接方法与虚方法两种。直接方法的声明格式如下。

#direct methods

.method [修饰关键字]

<.locals>[.parameter]

[.prologue]

[.line].end method

举例:

# direct methods private函数

.methodstatic constructor ()V

.locals3#在这个函数中最少要用到的本地寄存器的个数

.prologue//...

return-void.end method

.methodpublic constructor ()V

.locals3.prologue//...

return-void.end method

“direct methods”是 baksmali 添加的注释,访问权限和修饰关键字与字段的描述相同,方法原型描述了方法的名称、参数与返回值。“.locals ”指定了使用的局部变量的个数。“.parameter”指定了方法的参数,与 Dalvik 语法中使用“.parameters”指定参数个数不同,每个“.parameter”指令表明使用一个参数,比如方法中有使用到 3 个参数,那么就会出现3 条“.parameter”指令。“.prologue”指定了代码的开始处,混淆过的代码可能去掉了该指令。“.line”指定了该处指令在源代码中的行号,同样的,混淆过的代码可能去除了行号信息。

虚方法的声明与直接方法相同,只是起始处的注释为“virtual methods”。如果一个类实现了接口,会在 smali 文件中使用“.implements”指令指出。相应的格式声明如下。

#interfaces

.implements

“#interfaces”是 baksmali 添加的接口注释,“.implements”是接口关键字,后面的接口名是 DexClassDef 结构中 interfacesOff 字段指定的内容。如果一个类使用了注解,会在 smali 文件中使用“.annotation”指令指出。注解的格式声明如下。

#annotations

.annotation [注解属性][注解字段=值]

.endannotation

注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,“.annotation”指令会直接定义在 smali 文件中,如果是方法或字段,“.annotation”指令则会包含在方法或字段定义中。例如下面的代码。

#instance fields

.fieldpublic sayWhat:Ljava/lang/String;

.annotation runtime LMyAnnoField;

info="Hellomyfriend".end annotation

.end field

实例字段 sayWhat 为 String 类型,它使用了 MyAnnoField 注解,注解字段 info 值为“Hellomyfriend”。将其转换为 Java 代码为:

@MyAnnoField(info="Hellomyfriend")public String sayWhat;

。。。。。。。。。。。。。。。。。。。

虚方法的声明与直接方法相同,只是起始处的注释为“virtual methods”。如果一个类实现了接口,会在 smali 文件中使用“.implements”指令指出。

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

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

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

寄存器声明及使用

.method privatetest(I)V

.registers4# 声明总共需要使用4个寄存器const-string v0, "LOG" # 将v0寄存器赋值为字符串常量"LOG"move v1, p1 # 将int型参数的值赋给v1寄存器return-void.end method

结合Dalvik常用的指令进行操作,即可实现一些需要的功能

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

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

如果一个Java方法声明如下:

myMethod(int p1, float p2, boolean p3)

那么对应的Smali则为:

method LMyObject;->myMethod(IJZ)V

此时,寄存器的对应情况如下:

寄存器名称     对应的引用

p0     this

p1     int型的p1参数

p2, p3     float型的p2参数

p4     boolean型的p3参数

那么最少需要的寄存器个数则为:5

如果方法体内含有常量、变量等定义,则需要根据情况增加寄存器个数,数量只要满足需求,保证需要获取的值不被后面的赋值冲掉即可,方法有:存入类中的字段中(存入后,寄存器可被重新赋值),或者长期占用一个寄存器

Dalvik指令集

如果需要使用Smali编写程序,还需要掌握常用的Dalvik虚拟机指令,其合集称为Dalvik指令集。这些指令有点类似x86汇编的指令,但指令更多,使用也非常简单方便。最详尽的介绍,可以参考Android官方的Dalvik相关文档:https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions

一般的指令格式为:[op]-[type](可选)/[位宽,默认4位] [目标寄存器],[源寄存器](可选),比如:move v1,v2,move-wide/from16 v1,v2

这里也列举一些常用的指令,并结合Smali进行说明:

移位操作:

此类操作常用于赋值

- 返回操作:

用于返回值,对应Java中的return语句

- 常量操作:

用于声明常量,比如字符串常量(仅声明,String a = “abc”这种语句包含声明和赋值)

- 调用操作:

用于调用方法,基本格式:invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB,其中,BBBB代表方法引用(参见上面介绍的方法定义及调用),vC~G为需要的参数,根据顺序一一对应

- 判断操作:

判断操作用来比较一个寄存器中的值,是否与目标寄存器中的值相等或不等,对应Java中的if语句,格式为:if-[test] v1,v2, [condition],其衍生操作还有专门与0进行比较的if-[test]z v1, [condition],其中[condition]为符合判断结果后的跳转条件,需要提前定义好。判断操作也通常和goto配合使用,用来实现循环或者if-else语句

if-eq vA, VB, cond_** 如果vA等于vB则跳转到cond_**。相当于if (vA==vB)

if-ne vA, VB, cond_** 如果vA不等于vB则跳转到cond_**。相当于if (vA!=vB)

if-lt vA, VB, cond_** 如果vA小于vB则跳转到cond_**。相当于if (vA

if-le vA, VB, cond_** 如果vA小于等于vB则跳转到cond_**。相当于if (vA<=vB)

if-gt vA, VB, cond_** 如果vA大于vB则跳转到cond_**。相当于if (vA>vB)

if-ge vA, VB, cond_** 如果vA大于等于vB则跳转到cond_**。相当于if (vA>=vB)

if-eqz vA, :cond_** 如果vA等于0则跳转到:cond_** 相当于if (VA==0)

if-nez vA, :cond_** 如果vA不等于0则跳转到:cond_**相当于if (VA!=0)

if-ltz vA, :cond_** 如果vA小于0则跳转到:cond_**相当于if (VA<0)

if-lez vA, :cond_** 如果vA小于等于0则跳转到:cond_**相当于if (VA<=0)

if-gtz vA, :cond_** 如果vA大于0则跳转到:cond_**相当于if (VA>0)

if-gez vA, :cond_** 如果vA大于等于0则跳转到:cond_**相当于if (VA>=0)

需要注意的是,在Java中编写的if语句,往往在对应的Smali中,会变成相反的判断逻辑,如下面所示:

1 private voidtest() {2 int a = 0;3 int b = 1;4 String result;5 if (a >b) {6 result = "a great than b";7 } else{8 result = "a less than or equals b";9 }10 }

上面的Java代码逻辑很简单——一个很简单的if语句,为了在Smali中看的更清楚,我只做了字符串赋值操作。下面是对应的Smali代码:

1 .method privatetest()V2 .registers 4

3

4 .line 24

5 const/4 v0, 0x0

6

7 .line 25

8 .local v0, "a":I9 const/4 v1, 0x1

10

11 .line 27

12 .local v1, "b":I13 if-le v0, v1, :cond_714

15 .line 28

16 const-string v2, "a great than b"

17

18 .line 28

19 .local v2, "result":Ljava/lang/String;20 goto:goto_921

22 .line 30

23 .end local v2 # "result":Ljava/lang/String;24 :cond_725 const-string v2, "a less than or equals b"

26

27 .line 32

28 .restart local v2 # "result":Ljava/lang/String;29 :goto_930 return-void

31 .end method

仔细观察可以发现:

if判断

属性操作:

属性操作的分为:取值(get)和赋值(put)

目标类型分为:数组(array)、实例(instance)和静态(static)三种,对应的缩写前缀就是a、i、s

长度类型分为:默认(什么都不写)、wide(宽,64位)、object(对象)、boolean、byte、char、short(后面几种就不解释了,和Java一致)

指令格式:[指令名] [源寄存器], [目标字段所在对象寄存器], [字段指针],示例代码如下,操作是为int型的类成员变量mIntA赋值为100:

1 const/16 v0, 0x64

2

3 iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I

下面列出用于实例字段的指令,其中i都可以换成a或者s,分别用于操作数组字段或者静态字段

举例:

以下Java代码是进行的是最基本的类成员变量的赋值、取值操作

privateString mStringA;private intmIntA;privateActivity mActivityA;public voidfieldTest() {

mStringA= "Put String to mStringA";

mIntA= 100;

mActivityA= this;int len =mStringA.length();

}

对应的Smali代码如下:

# instance fields

.fieldprivate mActivityA:Landroid/app/Activity;

.fieldprivatemIntA:I

.fieldprivate mStringA:Ljava/lang/String;

# virtual methods

.methodpublicfieldTest()V

.registers2.line55

const-string v0, "Put String to mStringA"iput-object v0, p0, Lcom/coderyuan/smali/MainActivity;->mStringA:Ljava/lang/String;

.line56

const/16 v0, 0x64iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I

.line57iput-object p0, p0, Lcom/coderyuan/smali/MainActivity;->mActivityA:Landroid/app/Activity;

.line59iget-object v0, p0, Lcom/coderyuan/smali/MainActivity;->mStringA:Ljava/lang/String;

invoke-virtual {v0}, Ljava/lang/String;->length()I

move-result v0

.line60.local v0,"len":Ireturn-void.end method

根据Java和Smali代码的对比,值得注意的是,Smali获取类成员变量的方法,比较接近函数调用,只不过没有函数调用时的参数

其他指令:

参考:https://blog.csdn.net/yuanguozhengjust/article/details/80493963

https://www.52pojie.cn/thread-687375-1-2.html

java smali代码 解读_Smali代码语法相关推荐

  1. java smali互相转_Smali浅析及dex,java互转

    今天在看热修复时,文中多次提到smali文件,想简单了解一下Smali是什么. Smali文件是什么? Android程序员用Java语言开发APP,编译工具会将Java源文件(.java)编译成Da ...

  2. nsga2代码解读python_代码资料

    faster RCNN TensorFlow版本: 龙鹏:[技术综述]万字长文详解Faster RCNN源代码(一) buptscdc:tensorflow 版faster rcnn代码理解(1) l ...

  3. Tensoflow-SSD代码解读(github-balancap代码)

    1)先验框计算 对于一个大小 为m*n 的特征图,共有 mn 个单元,每个单元设置的先验框数目记为 k ,那么每个单元共需要 (c+4)k 个预测值,所有的单元共需要 (c+4)kmn 个预测值,由于 ...

  4. DAMO-YOLO全流程代码解读

    一.数据集相关代码解读 创建dataloader(damo/dataset/build.py) 在damo/apis/detector_trainer.py的158行,及174-203行中,DAMO- ...

  5. MPC多旋翼控制 - 线性MPC代码解读(mav_control_rw项目)

    MPC无人机控制 - mav_control_rw项目 - 线性MPC代码解读 大型工程的代码还是得记录一下,不然每次都得回头看.紧接上篇趁热打铁一下 MPC多旋翼控制 - mav_control_r ...

  6. Jsoup代码解读之四-parser(上)

    转载自  Jsoup代码解读之四-parser(上) 作为Java世界最好的HTML 解析库,Jsoup的parser实现非常具有代表性.这部分也是Jsoup最复杂的部分,需要一些数据结构.状态机乃至 ...

  7. Jsoup代码解读之五-parser(中)

    转载自    Jsoup代码解读之五-parser(中) 上一篇文章讲到了状态机和词法分析的基本知识,这一节我们来分析Jsoup是如何进行词法分析的. 代码结构 先介绍以下parser包里的主要类: ...

  8. Jsoup代码解读之六-parser(下)

    转载自   Jsoup代码解读之六-parser(下) 最近生活上有点忙,女儿老是半夜不睡,精神状态也不是很好.工作上的事情也谈不上顺心,有很多想法但是没有几个被认可,有些事情也不是说代码写得好就行的 ...

  9. 200行代码解读TDEngine背后的定时器

    作者 | beyondma来源 | CSDN博客 导读:最近几周,本文作者几篇有关陶建辉老师最新的创业项目-TdEngine代码解读文章出人意料地引起了巨大的反响,原以为C语言已经是昨日黄花,不过从读 ...

  10. Java编码技巧之高效代码50例

    来自:高德技术 导读:世界上只有两种物质:高效率和低效率:世界上只有两种人:高效率的人和低效率的人.--萧伯纳 同理,世界上只有两种代码:高效代码和低效代码:世界上只有两种人:编写高效代码的人和编写低 ...

最新文章

  1. Excel在.Net 环境下Web方式下驻留内存问题的解决
  2. C# SqlBulkCopy数据批量入库
  3. pip升级之后出现:/usr/bin/pip: No such file or directory
  4. 在用户线程/主线程中推荐MsgWaitForMultipleObjects代替WaitForSingleObject和WaitForMultipleObjects()函数
  5. 通过软件测试周期说明不同测试的使用情况!
  6. 小米手机首发开箱图赏
  7. 【实习之T100开发】T100 基础架构、命名原则
  8. apimanager-wso2-OKD-deploy
  9. idou老师带你认识Istio13:Istio实现基础认证策略
  10. python 步数_用python如何修改微信和支付宝每天走路的步数
  11. 计算机辅助设计基础试题,CAD基础知识自测题
  12. html颜色代码 糖果色,75平米糖果色跃层家 绚丽色彩散发迷人魅力
  13. linux 打印网卡与IP对应列表
  14. Git更换关联的远端分支
  15. 经典算法研究系列:七、深入浅出遗传算法
  16. 网页百度各种广告屏蔽
  17. 论从容自信---张含韵和涛声依旧有感
  18. html5怎么设置表单居中显示图片,如何将html5中的图片设置居中?图片居中的代码!...
  19. 计算机pc的桌面操作系统,电脑桌面操作系统介绍
  20. 实战web漏洞挖掘小技巧

热门文章

  1. 普中科技51单片机直流电机控制风扇调速
  2. 小米升鸿蒙系统,小米11升级鸿蒙系统
  3. python博弈论代码_科学网—两篇关于社交网络和博弈论的论文及源代码分享 - 陈俊东的博文...
  4. Sdk4J.jar安装到本地maven仓库
  5. USB接口芯片的选型参考(转贴)
  6. 推荐一款绘画软件krita,开源正版免费,适合ps用户
  7. WOW战斗逻辑系统分析
  8. 绕过TrustedInstaller权限
  9. 加密公司如何获得硅谷传奇风投a16z的青睐
  10. 您尝试安装的Adobe Flash Player版本不是最新版本解决办法