当我们发现某应用有个很牛逼功能的时候,还在为如何实现和拿不到源码而烦恼吗?
当我们写的app需要考虑安全性的时候,还在为明明用了混淆和第三方加固,但别人还是能破解而烦恼吗?
当我们发现api在某些手机上被弃用,而其他应用或系统应用又能实现该功能的时候,还在为相同的api自己却不能用而烦恼吗?

前车之鉴:当我们用一些工具去打开反编译后的代码,看着一团麻的指令和一些你从未见过的关键字、代码格式风格,赖不住性子就潦草的关掉了。其实是我们没有找对方法来学习它。

接下来介绍一下smali:

1、Dalvik字节码

Dalvik是google专门为Android操作系统设计的一个虚拟机,经过深度的优化。虽然Android上的程序是使用java来开发的,但是Dalvik和标准的java虚拟机JVM还是两回事。Dalvik VM是基于寄存器的,而JVM是基于栈的;Dalvik有专属的文件执行格式dex(dalvik executable),而JVM则执行的是java字节码。Dalvik VM比JVM速度更快,占用空间更少。

2、Smali定义

Smali是Davlik的寄存器语言,语法上和汇编语言类似。 Davlik是基于寄存器的,就是说smali里的所有操作都必须经过寄存器来进行。apk文件通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件。

3、Smali基本数据类型

语法 类型
V void
Z boolean
B byte
S short
C char
I int
j long(64 bits)
f float
D double(64 bits)

注:
1、变量存放在寄存器中,寄存器为32位,支持任何类型,其中long,double是64位,使用两个相邻的寄存器。
2、V 只能用于返回值类型。

4、引用类型(数组和对象)

语法 类型
L java类
[ 数组

[x表示一维数组,x代表基本类型,如[I代表int[],[[x代表二维数组,如[[I表示int[][]。
对象类型以L作为开头来表示,格式是Lpackage/ClassName;(用分号表示对象结束是必须的)
如:Ljava/lang/String;

String对象在smali中为:Ljava/lang/String;
Class1对象的一个boolean成员表示为:Lcom/disney/Class1;->isRunning:Z
Class1对象的一个String对象成员表示为:Lcom/disney/Class1;->name:Ljava/lang/String;
可以总结为格式为对象类型->成员名:成员类型,->表示所属关系,类型尾部必须包括一个分号。
内部类表示为:Lpackage/ClassNameinnerObjectName;,也就是在内部类前加“innerObjectName;,也就是在内部类前加“innerObjectName;,也就是在内部类前加“”符号。

5、运算符

smali 含义 符号
eq equals ==
ne not equals !=
lt less than <
gt bigger than >
le less and equals <=
ge bigger and equals >=
eqz equals zero =0
nez not equals zero !=0
ltz less than zero <0
btz bigger than zero >0
lez less equals zero <=0
gez bigger equals zero >=0

6、函数

格式:Func-Name (Para-Type1Para-Type2Para-Type3…)Return-Type
返回类型在最后,参数之间没有任何分隔符。
示例:
void fun()
fun()V

boolean fun(int, int, int)
fun(III)Z

String fun(boolean, int[], int[], String, long)
fun(Z[I[ILjava/lang/String;J)Ljava/lang/String;

7、局部变量

本地寄存器(local register,非参寄存器)用v开头数字结尾的符号来表示,如v0、v1、v2、…,
参数寄存器(parameter register)用p开头数字结尾的符号来表示,如p0、p1、p2、…,
.registers 用来标明方法中寄存器的总数,即参数寄存器和非参寄存器的总数。
.local 0,标明在这个函数中最少要用到的本地寄存器的个数,出现在方法中的第一行。在这里,由于只需要调用一个父类的onDestroy()处理,所以只需要用到p0,所以使用到的本地寄存器数为0,在植入代码后不要忘记可能要修改.local的值。
如: .local 4,则可以使用的寄存器是v0-v3

当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。
在实例函数中,p0代指“this”,p1表示函数的第一个参数,p2代表函数中的第二个参数…,
在static函数中,p1表示函数的第一个参数,p2代表函数中的第二个参数…,因为Java的static方法中没有this方法。
示例:
const/4 v0, 0x0
iput-boolean v0, p0, Lcom/disney/Class1;->isRunning:Z

上面第一句中把值0x0存到v0本地寄存器中,
第二句用iput-boolean指令把v0中的值存放到this.isRunning这个成员变量中,即this.isRunning = false; 因为在实例函数中p0代表的是“this”,Lcom/disney/Class1;是类名,对应实例是p0。

8、成员变量和指令

#static fields
.field private static final PREFS_INSTALLATION_ID java/lang/String; = “installationId”
#instance fields
.field private _activityPackageName java/lang/String;
获取和操作静态成员变量和实例成员变量有不同的指令。
读取的指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget-object等,
赋值的指令有:iput、sput、iput-boolean、sput-boolean、iput-object、sput-object等。
带“-object”表示操作的成员变量是对象类型,没有“-object”后缀的表示操作的成员变量对象是基本数据类型,特别地boolean类型则使用带“-boolean”的指令操作。

获取static fields的指令。
示例:sget-object v0, Lcom/disney/Class1;->PREFS_INSTALLATION_ID:Ljava/lang/String;
上句中sget-object指令把PREFS_INSTALLATION_ID这个String成员变量获取并放到v0寄存器中。

获取instance fields的指令与static fields的类似,需要指明对象所属的实例。
示例:iget-object v0, p0, Lcom/disney/Class1;->_view:Lcom/disney/Class2;
上句iget-object指令比sget-object多了一个参数p0,就是该变量所在类的实例,在这里就是p0即“this”。

put指令的使用和get指令是统一的。
示例:
const/4 v3, 0x0
sput-object v3, Lcom/disney/Class1;->
globalIapHandler:Lcom/disney/config/GlobalPurchaseHandler;

上句相当于Class1.globalIapHandler = null;

9、函数调用

smali中的函数调用也分为direct和virtual两种类型,direct method就是private函数,public和protected函数都属于virtual method。在调用函数时,有invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface等几种不同的指令。还有invoke-XXX/range 指令的,这是参数多于4个的时候调用的指令,比较少见。
1、invoke-static:就是调用static函数的,
示例:invoke-static {}, Lcom/disney/Class1;->fun()Z
上句invoke-static后面有一对大括号“{}”,内部是调用该方法的实例和参数列表,由于这是static方法也不需要参数,所以{}内为空。

2、invoke-super:调用父类方法,在onCreate、onDestroy等方法都能看到。
invoke-direct:调用private函数,
示例:invoke-direct {p0}, Lcom/disney/Class1;->
getGlobalIapHandler()Lcom/disney/config/GlobalPurchaseHandler;

上句即this->getGlobalIapHandler(),函数GlobalPurchaseHandler getGlobalIapHandler()是定义在Class1中的一个private函数。

3、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参数。

10、获取函数调用结果

在smali里调用函数和返回函数结果需要分开来完成,在调用的函数返回非void后,用move-result(返回基本数据类型)和move-result-object(返回对象)指令获取返回结果。
示例:
const/4 v2, 0x0
invoke-virtual {p0, v2}, Lcom/disney/Class1;->
getPreferences(I)Landroid/content/SharedPreferences;
move-result-object v1

上句v1保存的就是调用this.getPreferences(int)方法返回的SharedPreferences实例。

11、函数体

.method 和 .end method之间。
示例:
.method protected onDestroy()V
.locals 0

.prologue
.line 277
invoke-super {p0}, Lcom/disney/common/BaseActivity;->onDestroy()V

.line 279
return-void
.end method

上段是onDestroy()函数。
.line 277,标注了该代码在原Java文件中的行数,它不是必须的,去掉没有编译问题。它在出错时可以指出错误位置,jd-gui工具即是通过分析这些信息将smali代码还原成Java代码的。

12、条件语法

示例:
if-eq p1, v0, :cond_8
:cond_8
invoke-direct {p0}, Lcom/paul/test/a;->d()V

上段表示如果p1和v0相等,则执行cond_8的流程:调用com.paul.test.a的d()方法

示例:
if-ne p1, v0, :cond_b
:cond_b
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
move-result v0

上段表示不相等则执行cond_b的流程。

————个人学习总结,欢迎各路大神纠正,共同学习、共同进步!!!————

Android逆向之smali语法相关推荐

  1. [车联网安全自学篇] Android安全之Smali语法总结「必备」

    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 0x01 前言 Android4.4之前使用的是 Daliv ...

  2. Android逆向:smali编码实践(三)—— 实体类创建以及if判断

    目录 1.准备工作 2.编写smali文件 3.编译smali文件 ​ 4.检查并运行 5.遇到问题 1.准备工作 1.1下载好smali的jar这里使用smali-2.4.0.jar  (PS: 执 ...

  3. notepad++ smali语法高亮模板分享

    某论坛也有,但是太难看了, 前面介绍了一些工具可以反编译dex文件为smali文件,在Android程序逆向分析中,阅读smali代码已然是十分重要的,但各种代码编辑器都无法较好的支持smali文件的 ...

  4. Android逆向--如何调试smali代码?

    最近在重整Android逆向分析环境,一切都在从零开始,做下记录,给大家分享. 本文介绍Android逆向中smali代码的调试及环境的准备. 事先准备如下工具: Android killer:反编译 ...

  5. Android逆向之调试smali代码基础

    点击上方↑↑↑蓝字[协议分析与还原]关注我们 " 介绍Android逆向中调试smali代码的方法." 最近在重整Android逆向分析环境,一切都在从零开始,做下记录,给大家分享 ...

  6. Android逆向入门7——Smali语法学习(1)

    这一节我们一起探讨smali语法和smali在Android逆向中的应用,它是Android逆向世界中不可或缺的一部分. 简单的来说,Dex反编译的结果就是Smali,Smali和dex之间的关系,我 ...

  7. android逆向01:修改apk的资源文件,smali插桩

    前提: 有需求才有实现. android逆向能干什么?去除游戏中的广告,跳过各种支付达到付费效果,人为干预简化游戏流程直奔主题,无限增加各种付费道具,等等:当然可以对自己的apk进行逆向的逆向进行加固 ...

  8. Android逆向世界之一:smali文件

    亲测可用,如有问题请私信! 一直对android的逆向分析很感兴趣,这些年也陆陆续续反编译了一些android的项目,今天开始对这方面的知识做一下总结.先从android的apk文件开始讲起. APK ...

  9. 【转载】Android逆向开发之smali语言的学习

    Android逆向开发之smali语言的学习 该文转载自乱码三千 – 分享实用IT技术 smali和java基本数据类型对比 smali java B byte S short I int J lon ...

最新文章

  1. 计算机机房云部署,公共技能云机房建设方案及配置清单-20210405173307.pdf-原创力文档...
  2. 企业数字化转型本质上是“人”的转型和“组织”的转型
  3. 操作系统中的同步和异步
  4. 什么是区块链?什么是比特币?一文轻松看懂!
  5. 龙之谷哪个服务器最多,龙之谷哪些服务器数据互通 龙之谷数据互通详情介绍...
  6. 常用MIME类型(Flv,Mp4的mime类型设置)
  7. [转载] 七龙珠第一部——第115话 一定要找到迷般的超神水
  8. vim命令模式和底线_人生苦短!老鸟带你用Vim偷懒!
  9. 中芯国际A股最终确定发行价27.46元 发行规模超50亿
  10. 繁体中文转换为简体中文的PHP类
  11. 其实,我被 Fenng 拉黑过!
  12. 简单使用ember后的几点感想
  13. Scratch(三十三):打砖游戏
  14. python 显著性检验_Python SciPy 统计显著性检验(Statistical Significance Tests)
  15. iPhoneXs iPhoneXs Max iPhoneXr 界面适配问题
  16. java对象 内存逃逸_JVM内存逃逸
  17. SSM实现邮箱验证功能
  18. 【Mskt问题的解决办法】使用御坂翻译器2.x版本遇到的常见问题及解决办法
  19. 数据脱敏的场景与价值【总结】
  20. ThinkPHP6 API接管异常

热门文章

  1. linux 16.10,Lubuntu16.10 安装经历
  2. 1486万!鲁班软件中标临空经济区工程管理数字化平台及BIM应用管理项目
  3. Win10怎么禁用驱动程序强制签名
  4. 20170208找女朋友之路思考总结
  5. Android将图片打成圆形
  6. Dubbo详解(一)分布式服务框架的概念理解
  7. java -xmx_Java中,启动JVM时,Xms和Xmx参数是什么? - Break易站
  8. Java启动参数 XMS和XMX
  9. 年薪百万交流python群
  10. 计算机软件类ui工资多少,合肥UI设计工资一般多少