栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android——Smali语法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android——Smali语法

安卓系统里使用的是Java虚拟机(Dalvik),Dalvik虚拟机和Jvm一样,也有自己的一套指令集,类似汇编语言。smali文件就是Dalvik的寄存器语言,被广泛地用于 APP 广告注入、汉化和破解,ROM 定制等方面。
利用Android Killer,反编译classes.dex文件,就可以得到以smali为后缀的文件。


Android开发是使用Java语言来开发的,编写的源码文件.java(MainActivity.java、Login.java)——> 编译后生成.dex文件 ——> 反编译.dex文件生成.smali文件

一、寄存器

Android 的变量都存储于寄存器中。变量分为 v 与 p 两种格式
对于dalviks字节码寄存器都是32位的,它能够表示任何类型,2个寄存器用于表示64位的类型(Long and Double)

    v 变量表示方法中非参数变量。
    p 变量表示方法中参数变量。
    如果方法是非静态方法,p0 表示 this
    如果方法是静态方法,p0 表示第一个参数
二、数据类型

基本数据类型

数组类型
[.... --- array

在基本类型前加上前中括号“[”即表示该类型的数组,如: [B 表示byte数组 [i 表示int数组

对象类型的数组为”[“加上对象类型表示符来表示,如String类型表示为:[Ljava/lang/String

对象类型
L ..../....; --- object

如果是对象类型,则以L作为开头,格式是LpackageName / objectName; packageName/表示该对象所在的包,ObjectName 是对象的名字,“;” 表示对象名称的结束。相当于 java 中的 packageName.ObjectName。

如:Ljava/lang/String; :表示 String 对象。其中 java/lang 对应 java.lang 包, String 是该包的一个对象。类对象中的内部类则使用“$”来连接

三、Smali文件关键词

Smali文件与java中的类是一一对应的,包括内部类和匿名内部类也会生成对应的smali文件



.registers 和 .locals 基本区别
指令.registers指定了在这个方法中有多少个可用的寄存器(包括存方法参数的寄存器与非参寄存器)
指令.locals指明了在这个方法中非参(non-parameter) 寄存器的数量

Smali类的格式 1. 头文件
.class <访问权限修饰符> [非权限修饰符] <类名>
.super <父类名>
.source <源文件名称>

访问权限修饰符即public,protected,private,非权限修饰符指的是final,abstract,static,两者都可以为空。

是android.support.v4.util.LogWriter这个package下的一个类(第1行)

继承自java.io.Writer这个类(第2行)

这是一个由SourceFile.java编译得到的smali文件(第3行)

2. 接口实现
#interfaces
.implements <接口名称>

其中# interfaces为注释

3. 变量定义

静态变量

#static fields
.field <访问权限> static [修饰词] <字段名>:<变量类型>
.field <访问权限> static final <常量名>:<常量类型> = 常量值


普通变量

#instance fields
.field <访问权限修饰符> [非权限修饰符] <变量名>:<变量类型>

4. 方法定义

smali中的方法以 .method/.end method 进行描述,有分两种方法,一种是直接方法,一种是虚方法

直接方法就是不能被覆写的方法,包括用static,private修饰的方法

虚方法表示可以被覆写的方法,包括public,protected修饰的方法。

两者在smali中的注释分别是直接方法(#direct methods),虚方法(#virtual methods),一般直接方法在smali文件的前半部分,虚方法在后半部分。

#direct methods/#virtual methods
.method <访问权限修饰符> [非访问权限修饰符] <方法名> (Para-Type1Para-Type2Para-Type3...)Return-Type
      <.locals>
      [.parameter]
      [.prologue]
      [.line]     #对应Java源码的一行代码
      <代码逻辑>
.end method

其中.parameter,.prologue,.line是可选的。

参数与参数之间没有任何的间隔,对象后面有分号

构造方法

.method <访问权限修饰符> [非访问权限修饰符] constructor (Para-Type1Para-Type2Para-Type3...) Return-Type


静态代码块

.method <访问权限修饰符> static constructor ()V

静态变量的初始化,也必须在clinit内执行

5. 注解
#annotations
.annotation [注解的属性] <注解类名>
    [注解字段=值]
    ...
.end annotation

其中# annotations为注释

四、方法描述
方法对应的类(全包名路径)->方法名(参数类型描述符)返回值类型描述符;

五、变量描述
变量对应的类(全包名路径)->变量名:类型描述符**;**

Dalvik对变量的描述会指明变量定义的和变量的类型

六、常见Dalvik指令集 1. 方法调用指令

invoke-xxxxx {参数}, 方法所属类(全包名路径);->方法名称(方法参数描述符)方法返回值类型描述符

xxxxx 为direct,virtual,static,super,interface其中一种

.class public LTest;	#声明类
.super Ljava/lang/Object;	#声明父类

.method public constructor (Ljava/lang/String;)v

	invoke-direct {p0}, Ljava/lang/Object;->()v	#调用父类构造方法
	invoke-virtual {p0}, LTest;->getName()Ljava/lang/String;	#调用getName方法
	
	return-void
.end method

#声明getName方法
.method public getName()Ljava/lang/String;
	
	const-String v0,"hello"	 #定义局部字符常量
	
	return-object v0	#返回常量
.end method

.class public LTest;	#声明类
.super Ljava/lang/Object;	#声明父类

.method public constructor (Ljava/lang/String;)v

	invoke-direct {p0}, Ljava/lang/Object;->()v	#调用父类构造方法
	invoke-static {}, LTest;->getName()Ljava/lang/String;	#调用getName方法
	move-result-object v0	#将返回值赋给v0
	
	return-void
.end method

#声明getName方法
.method public getName()Ljava/lang/String;
	
	const-String v0,"hello"	 #定义局部字符常量
	
	return-object v0	#返回常量
.end method

invoke-static后的{ }里不需要p0,因为静态方法的调用不需要传入this实例

.method protected onCreate(Landroid/os/Bundle)V
	.register 2
	
	invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
	
	return-void
.end method
2. 方法返回指令


3. 创建对象指令
#声明实例
new-instance +变量名,对象全包名路径;

#调用构造方法 (如果构造方法内还定义了成员变量,那么在调用之前需要提前声明,然后在invoke的时候当做参数一并传入)
invoke-direct {变量名},对象全包名路径;->(方法参数描述符)方法返回值类型描述符

4. 空操作指令

空操作指令的助记符为nop,它的值为00,通常nop指令被用来作对齐代码之用,无实际操作。

5. 数据定义指令

数据定义指令用于定义代码中使用的常量、字符串、类等数据,基础字节码是const

字符串数据

const-string 变量名,”字符串”


字节码数据

const-class 变量名,字节码对象;



数值类型数据 (默认定义最高位为符号位)

#占用一个寄存器(32位)
const/4 变量名,#十六进制数

const/16 变量名,#十六进制数

const 变量名,#十六进制数

const/high16 变量名,#十六进制数

#占用相邻两个容器(64位)
const-wide 变量名,#十六进制数

const-wide/16 变量名,#十六进制数

const-wide/32 变量名,#十六进制数

const-wide/high16 变量名,#十六进制数

注意

    const-wide只用写出一个寄存器,另一个寄存器默认为其下一个,即const-wide vx,寄存器为 vx 与 v(x+1)
    如const-wide v2,#FF763D33,其寄存器为 v2 和 v3在使用const/high16时,数值补齐32位,即十六进制8位,不足的末尾+0
    如用const/ high16给 v0 赋0xFF7F,代码为const/ high16 v0,0xFF7F0000(补满8位)只取最高16位,即将 #0xFF7F 赋给v0
6.变量操作指令

字段操作指令表示对对象字段进行赋值和取值操作,就像Java代码中的set和get方法,基本指令是iput-type,iget-type,sput-type,sget-type.type表示数据类型。


普通字段读写操作
前缀是i的iput-type和iget-type指令用于字段的读写操作


取值
iget vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作int类型(float类型)

iget-wide vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作wide型字段
iget-boolean vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作布尔类型

iget-byte vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作字节类型

iget-char vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作字符类型

iget-object vA,vB,filed_id 读取vA寄存器中的对象中的filed_id对象的引用值给vB寄存器,用于操作对象引用

iget-short vA,vB,filed_id 读取vA寄存器中的对象中的filed_id的值给vB寄存器,用于操作short类型

赋值

iput vA,vB,filed_id 把vA寄存器的值给vB寄存器中的int类型(float类型)
iput-wide vA,vB,filed_id 把vA寄存器的值给vB寄存器中的wide类型

iput-boolean vA,vB,filed_id 把vA寄存器的值给vB寄存器中的boolean类型

iput-byte vA,vB,filed_id 把vA寄存器的值给vB寄存器中的字节类型

iput-char vA,vB,filed_id 把vA寄存器的值给vB寄存器中的字符类型

iput-object vA,vB,filed_id 把vA寄存器指向的对象的引用赋值给vB寄存器中的filed_id对象

iput-short vA,vB,filed_id 把vA寄存器的值给vB寄存器中的short类型

静态字段读写操作

前缀是s的sput-type和sget-type指令用于静态字段的读写操作(操作静态变量。因此没有目标对象)

7. 跳转指令

跳转指令用于从当前地址跳转到指定的偏移处。Dalvik指令集中有三种跳转指令:无条件跳转(goto),分支跳转(switch)与条件跳转(if)


goto :goto_N 无条件跳转到指定偏移处

条件跳转指令


if-eq vA, vB, : cond_** 如果vA等于vB,则跳转到:cond_** ,Java语法表示为“if(vA == vB)”

if-ne vA, vB, :cond_** 如果vA不等于vB,则跳转到:cond_** ,Java语法表示为“if(vA != vB)”

if-le vA, vB, :cond_** 如果vA小于等于vB,则跳转到:cond_** ,Java语法表示为“if(vA <= vB)”

if-lt vA, vB, :cond_** 如果vA小于vB,则跳转到:cond_** ,Java语法表示为“if(vA < vB)”

if-ge vA, vB, :cond_** 如果vA大于等于vB,则跳转到:cond_** ,Java语法表示为“if(vA >= vB)”

if-gt vA, vB, :cond_** 如果vA大于vB,则跳转到:cond_** ,Java语法表示为“if(vA > vB)”

if-eqz vA, :cond_** 如果vA等于0,则跳转到:cond_** ,Java语法表示为“if(vA == 0)”

if-nez vA, :cond_** 如果vA不等于0,则跳转到:cond_** ,Java语法表示为“if(vA != 0)”

if-ltz vA, :cond_** 如果vA小于0,则跳转到:cond_** ,Java语法表示为“if(vA < 0)”

if-lez vA, :cond_** 如果vA小于等于0,则跳转到:cond_** ,Java语法表示为“if(vA <= 0)”

if-gtz vA, :cond_** 如果vA大于0,则跳转到:cond_** ,Java语法表示为“if(vA > 0)”

if-gez vA, :cond_** 如果vA大于等于0,则跳转到:cond_** ,Java语法表示为“if(vA >= 0)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750841.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号