目录

  • 1. smali 数据类型
  • 2. smali 对象(引用类型的对象)
  • 3. smali 数组
  • 4. smali 方法的表现形式
  • 5. smali 字段的表现形式
  • 6. smali 寄存器指令
  • 7. smali 指令
    • 7.1 空指令:
    • 7.2 数据操作指令(此类操作常用于赋值):
    • 7.3 返回操作指令:
    • 7.4 数据定义指令:
    • 7.5 方法调用指令:
    • 7.6 比较指令:
    • 7.7 跳转指令:
    • 7.8 字段操作指令:
    • 7.9 数据运算指令:
    • 7.10 数据转换指令
    • 7.11 锁与异常操作指令
    • 7.12 实例操作指令

Android代码在 Dalvik虚拟机 运行
 
baksmali 是安卓系统中Dalvik中所用的汇编器 和 反汇编器
 
dex文件 反汇编后得到 smali文件
 
smali代码拥有自己特定的格式语法
 
smali目前在Google code是一个开源项目,被广泛的用于广告注入、汉化、破解等方面

1. smali 数据类型

java 数据类型 Type descriptor 字节码类型描述符
int I
float F
double D
boolean Z
char C
byte B
short S
long J
void V

2. smali 对象(引用类型的对象)

java 对象类型 Type descriptor 字节码类型描述符
package.name.Object Lpackage/name/Object;
  L表示 对象类型,这是一个对象
  xxx.yyy.zzz 变成 xxx/yyy/zzz 格式的目录层级结构
  ; 表示对象名称结束

String字符串本身是个对象

3. smali 数组

java 数据类型 Type descriptor 字节码类型描述符
int [ ] [ I
object [ ] [ ] [ [ Ljava/lang/Object

二维数组:
在java中:

在smali中:

#声明了三个不同类型的二维数组
.field private double_int:[[I.field private double_obj:[[Ljava/lang/Object;.field private double_string:[[Ljava/lang/String;





4. smali 方法的表现形式

方法在smali中以.method 指令声明

# direct methods
.method <访问权限> [关键字] 方法名(参数)返回值类型
.locals 指定局部变量的个数
.param  方法的参数
.line  代码在原文件中的行号
.end  结尾

Lcom/example/hello/MainActivity;->methodName(IZD)Z

  • Lcom/example/hello/MainActivity;:用于声明具体的类型,以便JVM寻找
  • methodName:表示方法名称
  • IZD:连写的,没有分隔符,表示该方法需要三个参数,分别为int、boolean、double
  • Z:最后括号后的Z,表示这个函数的返回对象类型是boolean型,如果是V,表示返回值为空
  • (如果需要调用构造方法,则MethodName为:<init>)

5. smali 字段的表现形式

java 中字段的表现形式 smali 中字段的表现形式
private objectType fieldName; .field fieldName:objectType
# instance fields   实例字段
.field <访问权限> [修饰关键字] <字段名> : 类型# static field  静态字段.field <访问权限> static [修饰关键字] <字段名> : 类型

例如:字段的声明对比如下:
在java中:

smali中:

文件格式:
无论是 普通类、抽象类、接口类、内部类,反编译是,都会用单独的smali文件存放。
java中:

smali中:

.class <访问权限> [修饰关键字] <类名称>
.super <父类>
.source <源文件名称>

每个smali文件开头都是如下三行:

.class public Lcom/example/hello/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.java"
  • 第一行:.class 指令 指定当前的类名称。此处是public
  • 第二行:.super 指令 指定当前类的父类
  • 第三行:.source 指令指定当前的源文件名称

6. smali 寄存器指令

在Dalvil虚拟机字节码中,寄存器有两种命名方式:

  • v 命名法(v0、v1、v2……)
  • p 命名法(p0、p1、p2……)
v 命名法 p 命名法 寄存器含义
v0 v0 第一个局部变量寄存器
v1 v1 第二个局部变量寄存器
…… …… 中间的局部变量寄存器依次递增且名称相同
vM-N p0 第一个参数寄存器
…… …… 中间的参数寄存器分别依次递增
vM-1 pN-1 第N局部变量寄存器

比较v命名法与p命名法:

v 命名法 p 命名法
以 .registers开头 以 .limit开头
以 v2 作为this的引用 以 p0 作为this的引用
以M-N命名N 个参数的寄存器 用 p 命名法

v 指向寄存器
p 一般是某个java原有的代码有参数,或者指向this的或者直接变量

Dalvil参数传递规则:如果一个函数使用了M个寄存器、拥有N个参数,则参数使用最后N个寄存器,局部变量从v0开始一直递增到前M-N个(被传入的“隐藏”的对象引用this)

7. smali 指令

7.1 空指令:
指令助记符 指令功能描述
nop 代码对齐,无操作
7.2 数据操作指令(此类操作常用于赋值):

指令基本格式:[op]-[type](可选)/[位宽,默认4位] [目标寄存器],[源寄存器](可选)

指令助记符 指令功能描述
move v0,v1 将v1寄存器的数据赋值给v0寄存器,非对象类型
move-object v0,v1 将v1寄存器的数据赋值给v0寄存器,对象类型
move-wide v0,v1 将寄存器对v1中的值移入到v0寄存器对中
move-result v1 将这个指令的上一条指令计算结果,移入到v1寄存器中(需要配合invoke-static、invoke-virtual等指令使用)
move-result-object v1 将上条计算结果的对象指针移入v1寄存器(多用于函数的返回值)
move-result-wide v1 将上条计算结果(双字)的对象指针移入v1寄存器
move-exception v1 将异常移入v1寄存器,用于捕获try-catch语句中的异常
7.3 返回操作指令:
指令助记符 指令功能描述
return-void 返回void
return v1 返回v1寄存器中的值
return-object v1 返回v1寄存器中的对象指针
return-void 返回void
7.4 数据定义指令:
  • const:数据定义 指令
  • /number:表示赋值到寄存器的数据的长度
  • vA:寄存器
  • #+B……:表示数据
指令助记符 指令功能描述
const/4 vA,#+B 将4位宽度的立即数 带符号 扩展到32位,赋值到vA寄存器
const/16 vA,#+BBBB 将16位宽度的立即数 带符号 扩展到32位,赋值到vA寄存器
const vA,#+BBBBBBBB 将32位宽度的立即数 赋值到vA寄存器
const wide/16 vA,#+BBBB 将16位宽度的立即数 带符号 扩展64位,赋值到vA寄存器
const wide/32 vA,#+BBBB 将32位宽度的立即数 带符号 扩展到64位,赋值到vA寄存器
const wide vA,#+BBBBBB 将64位宽度的立即数 ,赋值到vA寄存器
const-string vA,string@aaaa 将字符串常量的引用 赋值给vA
const/high16 vA+BBBB0000 将16位宽度的立即数 右扩展扩展到32位,赋值给vA寄存器
const-class vA,type@AAA 将一个类class 的引用赋值给vA寄存器

const/4和const/16的区别:

  • const/4 表示半个字节,也就是4位。-23~23-1 -8~7

  • const/16 表示两个字节,16位。-215~215-1 -32768~32767

局部变量定义:

.local v0,“a”:I:将v0的值赋值给 变量a

7.5 方法调用指令:

调用方法的基本格式:invoke-kind{vA,vB,vC,vD},meth@BBBB

  • invoke:调用方法 指令
  • -xxxx:调用的方法 的类型
  • vA~vD:为需要的参数,根据顺序一一对应
  • BBBB:代表方法引用
指令助记符 指令功能描述
invoke-virtual 调用实例的虚方法,通常成员对象实例的方法都有该指令调用(用于调用一般的,非private、非static、非final、非构造函数的方法,它的第一个参数往往会传p0,也就是this指针)
invode-super 调用父类的虚拟方法(用于调用父类中的方法,其他和invoke-virtual保持一致)
invoke-direct 调用直接方法,通常私有方法都以该指令调用(用于调用private修饰的方法,或者构造方法)
invoke-static 调用静态方法(比如一些工具类)
invoke-interface 用于调用interface中的方法
invoke-kind / range {vB-vN},method@BBB 参数列表是连续的寄存器列表
7.6 比较指令:

cmp:比较两个寄存器中值的大小,并将结果存储在目标寄存器中。
基本格式为:cmp 目标寄存器 vB vC

指令助记符 指令功能描述
cmpl vA,vB,vC(less than) 比较 vB,vC 较小值。如果vB=vC ,则vA=0 ;如果 vC较小 ,则vA存储正数。vB小 ,则vA存储负数
cmpg vA,vB,vC(greater than) 比较 vB,vC 较大值。如果vB=vC ,则vA=0 ;如果 vC较大 ,则vA存储正数。vB大 ,则vA存储负数
指令助记符 指令功能描述
cmpl-float vA,vB,vC 比较浮点型和长整型的数据。
cmpg-float vA,vB,vC 比较浮点型和长整型的数据。
cmpl-double vA,vB,vC 比较double型的数据
cmpg-double vA,vB,vC 比较double型的数据
cmpg-long vA,vB,vC 比较long型的数据
7.7 跳转指令:
指令助记符 指令功能描述
if-test vA,vB,+CCC 条件跳转指令,比较两个寄存器vA和vB的值,然后进行条件跳转
if-eq v1,v2,:cond_0 如果v1 = v2,则进入分支cond_0
if-ne v1,v2,:cond_0 如果v1 != v2,则进入分支cond_0
if-gt v1,v2,:cond_0 如果v1 > v2,则进入分支cond_0
if-ge v1,v2,:cond_0 如果v1 >= v2,则进入分支cond_0
if-lt v1,v2,:cond_0 如果v1 < v2,则进入分支cond_0
if-le v1,v2,:cond_0 如果v1 <= v2,则进入分支cond_0
   
就与0比较:
if-testz vA,+cccc 条件跳转指令,比较寄存器vA与0的值,满足后跳转
if-eqz v1,:cond_0 如果寄存器v1的值 ==0,则跳转到cond_0
if-gtz v1,:cond_0 如果寄存器v1的值 >0,则跳转到cond_0
if-gez v1,:cond_0 如果寄存器v1的值 >=0,则跳转到cond_0
if-ltz v1,:cond_0 如果寄存器v1的值 <0,则跳转到cond_0
if-lez v1,:cond_0 如果寄存器v1的值 <=0,则跳转到cond_0
   
其他跳转:
goto +cccc 无条件跳转到指定位置,偏移量为8位 宽度,且不为0
goto/16 +cccc 无条件跳转到指定位置,偏移量为16位 宽度,且不为0
goto/32 +cccc 无条件跳转到指定位置,偏移量为32位 宽度,且不为0
   
packed-switch vA,+bbbbbb 根据+bbbbbb给定的跳转偏移列表进行匹配vA寄存器的值,跳转到指定指令。其中,偏移量的匹配值是 有规律递增的
sparse-switch vA,+bbbbbb 根据+bbbbbb给定的跳转偏移列表进行匹配vA寄存器的值,跳转到指定指令。其中,偏移量的匹配值是 无规律的

作业1:

在java中:

 # 实际中不这样写,需要用一个函数,这里只说逻辑private int age = 20;private String  identity;
if  (age>18){identity = "成年";}else{identity = "未成年";}

在smali中:

.field private age:I
.field private identity:Ljava/lang/String;
const/4 v0,0x14
const/4 v1,0x12if-le v0,v1,:cond_0     #这里与原java代码是反着判断的
const-string v4,"成年"cond_0:
const-string v3,"未成年"
7.8 字段操作指令:

基本格式:iinstance-op vA,vB,field @CCCC

  • vA寄存器存放读的结果或写的数据
  • vB字段的引用
  • field是字段值的引用
  • type是类型后缀,如char、byte、short、
指令助记符 指令功能描述
普通字段操作:
iget 取值,用于操作int这种的值类型
iget-wide 取值,用于操作wide型字段
iget-object 取值,用于操作对象引用
iget-boolean 取值,用于操作布尔类型
iget-byte 取值,用于操作字节类型
iget-char 取值,用于操作字符类型
iget-short 取值,用于操作short类型
iput 赋值,用于操作int这种的值类型
iput-wide 赋值,用于操作wide型字段
iput-object 赋值,用于操作对象引用
iput-boolean 赋值,用于操作布尔类型
iput-byte 赋值,用于操作字节类型
iput-char 赋值,用于操作字符类型
iput-short 赋值,用于操作short类型

以上的 i 都可以换成 a 或者 s,分别用于操作 数组字段 或者 静态字段

作业2:

在java中:

    private String name1 = "zhangsan";private String name2 = "lisi";private int age1 = 20;private Object names[]= {name1,name2,"wangwu"};

在smali中:

# instance fields
.field private name1:Ljava/lang/String;
.field private name2:Ljava/lang/String;
.field private age1:I
.field private names:[Ljava/lang/Object;# direct methods
.method public constructor <init>()V.locals 9#调用了一个方法invoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()V#上面是声明了,这里需要为声明的对象赋值const-string v0, "zhangsan"iput-object v0, p0, Lcom/example/hello/Regist;->name1:Ljava/lang/String;const-string v1, "lisi"iput-object v1, p0, Lcom/example/hello/Regist;->name2:Ljava/lang/String;const/4 v2,0x14# 用来放数组长度const/4 v6,0x3# 声明一个新数组,寄存器位置为v5,长度为v6new-array v5, v6, [Ljava/lang/Object;const/4 v7,0x0aput-object v0, v5, v7    # 将v0的数据放入v5中,下标位置为v7const/4 v8,0x1aput-object v1, v5, v8    # 将v1的数据放入v5中,下标位置为v8const/4 v9,0x2const-string v4,"wangwu"aput-object v4, v5, v9    # 将v4的数据放入v5中,下标位置为v9# 将v5中的数据放入对象names中iput-object v5, p0, Lcom/example/hello/MainActivity;->names:[Ljava/lang/Object;return-void.end method

作业3:

循环:

private int a=2;
private int aa;
public void test(){
for(int i=0;i<4;i++){}
aa=a;
}

.class public Lcom/example/hello/Regist;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "Regist.java"# instance fields
.field private a:I
.field private aa:I# direct methods
.method public constructor <init>()Vinvoke-direct {p0}, Landroidx/appcompat/app/AppCompatActivity;-><init>()Vconst/16 v0, 0x2iput v0, p0, Lcom/example/hello/Regist;->a:I.end method# virtual methods
.method public test()V#准备一个0const/4 v1, 0x0#准备一个i.local v2, "i":I#开始循环:goto_0    # 准备一个4const/4 v1, 0x4#判断i>=4if-ge v2, v1, :cond_0#这里中间是循环体中的内容# i自增add-int/lit8 v2, v2, 0x1#再跳转到循环goto :goto_0.end local v2    # "i":I#判断不成功,跳出循环:cond_0iget v0, p0, Lcom/example/hello/LoginSuccess;->a:I   # 取出a的值iput v0, p0, Lcom/example/hello/LoginSuccess;->aa:I   # 赋值给aareturn-void
.end method
7.9 数据运算指令:

基本格式:bin-op vA,vB,vC(对寄存器vB和vC进行binop算数运算,结果复制到vA寄存器)

指令助记符 指令功能描述
算数运算:
add-type 加法(type有:int、long、float、double)
sub-type 减法
mul-type 乘法
div-type 除法
rem-type 取模
逻辑运算与位运算:
and-type2 逻辑与(type2只有:int、long)
or-type2 逻辑或
xor-type2 逻辑非
shl-type2 有符号数左移
shr-type2 有符号数右移
ushr-type2 无符号数右移
 
binop/lit8 vA,vB,#+cccc 将寄存器vB的值与常量cccc进行算数运算,结果赋值给vA
binop/lit16 vA,vB,#+cccc
binop/2addr vA,vB 将vA寄存器与vB寄存器的值进行binop运算,值赋值给vA
7.10 数据转换指令
指令助记符 指令功能描述
unop vA,vB 数据类型转换
neg-type vx,vy 计算 vx =- vy(type-后可以接类型int、long、float、double)
not-type vx,vy
type1-to-type2 转换类型
int-to-type
int-to-char
int-to-short
例如:
double-to-int v0,v1
7.11 锁与异常操作指令
指令助记符 指令功能描述
锁:(多用在多线程程序中,对同一对象操作)
monitor-enter vA 为指定的对象获取锁
monitor-exit vA 释放指定对象的锁
异常:
throw 抛出一个指定类型的异常
7.12 实例操作指令
指令助记符 指令功能描述
new-instance vA,type@BB 构造一个指定类型的实例,并把引用值给寄存器
instance-of vA,vB,type@CC 判断vB寄存器的引用对象是否可以转为指定类型,是vA就复制1,否vA复制0
check-cast vA,type@BB 把寄存器引用对象转为指定类型,不行就抛出异常

**指令学习英文文档**:http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

(三)smali 入门相关推荐

  1. python 三分钟入门_Cython 三分钟入门教程

    作者:perrygeo 译者:赖勇浩(http://laiyonghao.com) 原文:http://www.perrygeo.net/wordpress/?p=116 我最喜欢的是Python,它 ...

  2. scrapy 的三个入门应用场景

    说明: 本文参照了官网的 dmoz 爬虫例子. 不过这个例子有些年头了,而 dmoz.org 的网页结构已经不同以前.所以我对xpath也相应地进行了修改. 概要: 本文提出了scrapy 的三个入门 ...

  3. 米筐量化不支持c语言_AQ答疑:三分钟入门量化投资

    答疑丨量化投资三分钟入门(一) 量化投资在国外的发展已经有很长时间的历史,虽然国内市场目前仍处于初起阶段,但是因其投资业绩稳定,市场规模和份额不断扩大,得到了越来越多投资人的认可,各个大型券商也在发展 ...

  4. 学习平面设计的三个入门步骤

    学习平面设计的三个入门步骤 设计的学习可能有很多不同的路,由于这是有设计的多元化学问构造决议的,不论你以前是做什么的`,不论你曾经如何如何,在进入设计范畴之后,你以前的阅历都将影响你,你都将面临应战与 ...

  5. 三分钟入门大数据之用户画像标签的分类

    哈喽,大家好,我是汉斯老师.近几年来,互联网行业由于较高的薪资收入,受到许多人的追捧.很多年轻的学子,或是其他行业的有志青年,都想要投身到这个行业中来.然而一方面受到"互联网寒冬" ...

  6. 三天入门Python---基本语法(第一天)

    序言 本文作为三天入门Python的第一篇,先来个序言: 为什么写这样的文章,Python作为当下一个热门流行的语言,以及其在深度学习框架中的广泛应用,已经严重影响到了我的学习与工作,尤其是一个想要入 ...

  7. 【算法笔记题解】《算法笔记知识点记录》第三章——入门模拟1——简单模拟

    如果喜欢大家还希望给个收藏点赞呀0.0 相关知识点大家没基础的还是要看一下的,链接: <算法笔记知识点记录>第三章--入门模拟 由于放原题的话文章实在太长,所以题多的话我只放思路和题解,大 ...

  8. (三)webpack入门——webpack功能集合的demo

    ErduYang 自律的人生才自由 博客园 首页 新随笔 联系 订阅 管理 随笔 - 37文章 - 0评论 - 8 (三)webpack入门--webpack功能集合的demo 此篇文章来源于http ...

  9. 计量经济学学习与Stata应用笔记(三)Stata入门实例

    计量经济学学习与Stata应用笔记(三)Stata入门实例 使用的版本为stata15. 电力行业规模报酬的经典研究 本例为Nerlove(1963)对电力行业规模的经典研究. 导入数据 Excel的 ...

  10. 三分钟入门大数据之什么是用户画像?

    哈喽,大家好,我是汉斯老师.近几年来,互联网行业由于较高的薪资收入,受到许多人的追捧.很多年轻的学子,或是其他行业的有志青年,都想要投身到这个行业中来.然而一方面受到"互联网寒冬" ...

最新文章

  1. SendEmail使用TLS发送邮件
  2. 为什么企业光纤比家用光纤贵那么多,一般至少10倍以上?—Vecloud微云
  3. ubuntu21.04安装微信3.2.1(deepin-wine方式)
  4. oracle 运营维护_oracle运维(持续更新)
  5. redis2.2.8版本的安装详情
  6. python爬取qq音乐评论_爬虫:QQ音乐评论
  7. python---之阿partial
  8. springsecurity 登录失败_145-Spring Security
  9. mysql环境变量配置还是不行_mysql环境变量配置与Error 1045的解决方案
  10. Http请求get、post工具类
  11. 安卓原生系统_你没有用过的安卓系统:原生安卓桌面体验
  12. pox控制器学习笔记
  13. Windows域/域树/域林的简单区别
  14. 写好英语科技论文的诀窍: 主动迎合读者期望,预先回答专家可能质疑--周耀旗教授...
  15. 通过Bottledwater同步PostgreSQL中的数据变化到Kafka消息队列
  16. Gentoo安装教程(Systemd+Gnome)
  17. 电脑结构和CPU、内存、硬盘三者之间的关系
  18. 本科大学计算机专业排名2015,2015年美国大学本科计算机专业排名
  19. 浅谈Dubbox原理
  20. 股市小幽默-炒股第一天

热门文章

  1. 计算机任务栏隐藏恢复,电脑看不到任务栏怎么办 电脑任务栏不见了如何恢复...
  2. 简单管理Android手机程序的小程序
  3. 公司要一个网站,是选模板建站还是定制化建站?
  4. java jconsole_jconsole与jvisualvm
  5. asp毕业设计—— 基于asp+access的网上购物系统设计与实现(毕业论文+程序源码)——网上购物系统
  6. verilog Booth算法乘法器的实现(有无符号)
  7. 2021年武大计算机学院研究生,武汉大学
  8. 【postgresql 数据库运维文档】
  9. 小米 信号测试软件,如何测试出本地的联通、电信、移动信号网络的强弱?
  10. python傅里叶变换相位谱图_图像傅里叶变换的幅度谱、相位谱以及双谱重构原图像...