7. Smali基础语法总结
最近在学习Android 移动安全逆向方面,逆向首先要看懂代码,Android4.4之前一直使用的是 Dalivk虚拟机,而Smali是用于Dalivk的反汇编程序的实现。
Smali 支持注解,调试信息,行数信息等基本Java的基本特性,可以说是很接近Java编译再JVM上的中间语言,一般用来做Android程序的逆向工程。
1.Smali文件结构
一个Smali文件对应的是一个Java的类,更准确的说是一个.class文件,如果有内部类,需要写成ClassName$InnerClassA,ClassName$InnerClassB...这样的形式
2.基本类型
3.对象
Object类型,即引用类型的对象,在引用时,使用L开头,后面紧接着的是完整的包名,比如:java.lang.String,对应的Smali语法则是 Ljava/lang/String
4.数组
一维数组在类型的左边加一个方括号,比如:[I 等同于Java的 int[ ] ,[F 等同于Java的 float[ ] ,每多一维就加一个方括号,最多可以设置255维。
5.方法声明及调用
官方Wiki中给出的Smali引用方法的模板如下:
Lpackage/name/ObjectName;->MethodName(III)Z
第一部分: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
如果需要调用构造方法,则MethodName为:<init>
例子:
String对象在Smali中为:Ljava/lang/String
Class1对象的一个Boolean成员表示为:Lcom/disney/Class1;->isRunning:Z
Class2对象的一个String对象成员表示为:Lcom/disney/Class2;->name:Ljava/lang/String
可以总结为:对象类型 -> 成员名 : 成员类型
-> 表示所属关系,类型尾部必须包括一个分号。
6.寄存器声明及使用
在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
Float这种需要占用两个寄存器的参数类型,举例来看:
如果一个Java方法声明如下:
myMethod(int p1, float p2, boolean p3)
那么对应的Smali则为:
method LMyObject;->myMethod(IJZ)V
此时,寄存器的对应情况如下:
那么最少需要的寄存器个数则为:5
如果方法体内含有常量、变量等定义,则需要根据情况增加寄存器个数,数量只要满足需求,保证需要获取的值不被后面的赋值冲掉即可,方法有:存入类中的字段中(存入后,寄存器可被重新赋值),或者长期占用一个寄存器
7.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为需要的参数,根据顺序一一对应
smali中的函数调用也分为direct和virtual两种类型,direct method就是private函数,public和protected函数都属于virtual method。在调用函数时,有invoke-direct,invoke
virtual,invoke-static、invoke-super以及invoke-interface等几种不同的指令。还有invoke-XXX/range 指令的,这是参数多于4个的时候调用的指令,比较少见。
invoke-static:就是调用static函数的,示例:
invoke-static {}, Lcom/disney/Class1;->fun()Z
上句invoke-static后面有一对大括号“{}”,内部是调用该方法的实例和参数列表,由于这是static方法也不需要参数,所以{}内为空。
invoke-super:调用父类方法,在onCreate、onDestroy等方法都能看到。
invoke-direct:调用private函数,示例:
invoke-direct {p0}, Lcom/disney/Class1;->getGlobalIapHandler()Lcom/disney/config/GlobalPurchaseHandler;
上句即this->getGlobalIapHandler(),函数getGlobalIapHandler()是定义在Class1中的一个private函数。
invoke-virtual:用于调用protected或public函数,示例:
sget-object v0, Lcom/disney/Class1;->shareHandler:Landroid/os/Handler;
invoke-virtual {v0, v3}, Landroid/os/Handler;->removeCallbacksAndMessages(Ljava/lang/Object;)V
上句v0是shareHandler android/os/Handler,v3是传递给removeCallbackAndMessage方法的Ljava/lang/Object参数。
如何获取函数调用结果:
在smali里调用函数和返回函数结果需要分开来完成,在调用的函数返回非void后,用move-result(返回基本数据类型)和move-result-object(返回对象)指令获取返回结果。
示例:
const/ v2, 0x0
invoke-virtual {p0, v2}, Lcom/disney/Class1;->getPreferences(I)Landroid/content/SharedPreferences;
move-result-object v1
上句v1保存的就是调用this.getPreferences(int)方法返回的SharedPreferences实例。
- 判断操作:
判断操作用来比较一个寄存器中的值,是否与目标寄存器中的值相等或不等,对应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<vB)
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==)
if-nez vA, :cond_** 如果vA不等于0则跳转到:cond_**相当于if (VA!=)
if-ltz vA, :cond_** 如果vA小于0则跳转到:cond_**相当于if (VA<)
if-lez vA, :cond_** 如果vA小于等于0则跳转到:cond_**相当于if (VA<=)
if-gtz vA, :cond_** 如果vA大于0则跳转到:cond_**相当于if (VA>)
if-gez vA, :cond_** 如果vA大于等于0则跳转到:cond_**相当于if (VA>=)
- 属性操作:
属性操作的分为:取值(get)和 赋值(put)
目标类型分为:数组(array)、实例(instance)和静态(static)三种,对应的缩写前缀就是a、i、s
长度类型分为:默认(什么都不写)、wide(宽,64位)、object(对象)、boolean、byte、char、short(后面几种就不解释了,和Java一致)
指令格式:[指令名] [源寄存器], [目标字段所在对象寄存器], [字段指针],示例代码如下,操作是为int型的类成员变量mIntA赋值为:
const/ v0, 0x64 iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I
下面列出用于实例字段的指令,其中i都可以换成a或者s,分别用于操作数组字段或者静态字段
- 其他指令:
除以上介绍的几种基本的Dalvik指令外,Dalvik还支持值类型转换(如:int转float,double转float等)、基本运算(数学运算、逻辑运算、自增)两种指令集,这里只列举一些常用的指令,其他的可以参考上面提到的Google官方文档
参考链接:
https://blog.csdn.net/qq_32113133/article/details/85163277
7. Smali基础语法总结的更多相关文章
- Smali语言基础语法
1.Smali语言基础语法-数据类型与描述符 smali中有两类数据类型:基本类型和引用类型.引用类型是指数组和对象,其它都是基础类型. 基本类型以及每种类型的描述符: Java类型 类型描述符 说明 ...
- (2.1)Smali系列学习之基础语法
一.什么是Smali?Smali,Baksmali分别是指安卓系统里的Java虚拟机(Dalvik)所使用的一种dex格式文件的汇编器,反汇编器.其语法是一种宽松式的Jasmin/dedexer语法, ...
- 安卓逆向(一)--Smali基础
安卓逆向(一)--Smali基础 标签(空格分隔): 安卓逆向 APK的组成 文件夹 作用 asset文件夹 资源目录1:asset和res都是资源目录但有所区别,见下面说明 lib文件夹 so库存放 ...
- 【转】安卓逆向(一)--Smali基础
转载自吾爱破解安卓逆向入门教程 APK的组成 文件夹 作用 asset文件夹 资源目录1:asset和res都是资源目录但有所区别,见下面说明 lib文件夹 so库存放位置,一般由NDK编译得到,常见 ...
- Swift与C#的基础语法比较
背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...
- iOS-----正则表达式的基础语法
正则表达式简单语法总结 一.什么是正则表达式 从概念上来说,正则表达式也是一门小巧而精炼的语言,它可以用来简化检索特定的字符串,替换特定字符等功能,有许多开发语言工具,都内嵌支持正则表达式.那么一个正 ...
- python之最强王者(2)——python基础语法
背景介绍:由于本人一直做java开发,也是从txt开始写hello,world,使用javac命令编译,一直到使用myeclipse,其中的道理和辛酸都懂(请容许我擦干眼角的泪水),所以对于pytho ...
- emmet 系列(1)基础语法
emmet 系列(1)基础语法 emmet 是一个能显著提升开发html和css开发效率的web开发者工具 emmet基本上目前已知的编辑器都有相应的插件,各个编辑器的emmet插件的下载地址:点我下 ...
- Scala基础语法 (一)
如果你之前是一名 Java 程序员,并了解 Java 语言的基础知识,那么你能很快学会 Scala 的基础语法. Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的. 我 ...
随机推荐
- java多线程:线程体往外抛出异常的处理机制实践
1当线程的线程体内部无捕获异常,将异常抛出线程体外,不同情况下,程序处理机制 测试类 package com.ehking.bankchannel.domesticremit.facade.impl; ...
- FastAdmin 一键 CRUD 生成时方法不存在的问题分析
FastAdmin 一键 CRUD 生成时方法不存在的问题分析 有群友反馈 使用 一键 CRUD 生成时不成功. 我试了以下命令 php think crud -t test -u 1 是成功的. 再 ...
- Ambari的资源池管理
操作: YARN→Config→Advanced→Schedule capacity-scheduler=null yarn.scheduler.capacity.default.minimum-us ...
- 避免Android内存泄露
摘自:http://blog.csdn.net/xyz_lmn/article/details/7108011 Android的应用被限制为最多占用16m的内存,至少在T-Mobile G1上是这样的 ...
- 为IIS Host ASP.NET Web Api添加Owin Middleware
将OWIN App部署在IIS上 要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可.它提供了所有Owin配置,Middlew ...
- Flex布局(转载)
网页布局(layout)是 CSS 的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂 ...
- Oracle 12.1.0.2 对JSON的支持
Oracle 12.1.0.2版本有一个新功能就是可以存储.查询.索引JSON数据格式,而且也实现了使用SQL语句来解析JSON,非常方便.JSON数据在数据库中以VARCHAR2, CLOB或者BL ...
- java代码做repeat次运算,从键盘输入几个数,比最值
总结:今天这个题目有点灵活,因为它不但要求输出结果,还要进行几次相同的输入,不退出循环 import java.util.Scanner; //从键盘一次输入更多的数,然后把每一次的数进行---可比较 ...
- 网络编程Socket之wireshark使用
这里只对wireshark进行简单的使用介绍.里面的报表,IO图形分析等以后再谈.... 这里不提供下载地址了,不是什么稀有资源,我使用的wireshark是在百度软件中心下载的. 第一步:选择需要 ...
- Python print format() 格式化内置函数
Python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能. 基本语法是通过 {} 和 : 来代替以前的 % . format 函数可以接受不限个参数 ...