【逆向工程】Android逆向Smali语法(一)

admin 2025年6月11日19:24:26评论11 views字数 4760阅读15分52秒阅读模式

【逆向工程】Android逆向Smali语法(一)

最近RCS-TEAM倚天实验室加入了几位安全方向的大神,其中就有Android逆向工程工程师。今天要跟大家分享的就是Android逆向技术。

0x1Android 移动安全与逆向介绍

Android 移动安全逆向方面,逆向首先要看懂代码,Android4.4之前一直使用的是 Dalivk虚拟机,而Smali是用于Dalivk的反汇编程序的实现

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

0x2Android 移动安全与逆向之Smali基础语法总结

1.Smali文件结构

一个Smali文件对应的是一个Java的类,更准确的说是一个.class文件,如果有内部类,需要写成ClassName$InnerClassA,ClassName$InnerClassB...这样的形式

2.基本类型

类型关键字/标识符 对应Java中的类型说明
V void,只能用于返回类型
Z boolean
B byte
S short
C char
I int
J long(64 bits)
F float
D double (64 bits)

0x3Smali 指令集

指令集 : smali指令大全
Dalvik 指令在调用格式上模仿了C语言的调用约定.Dalvik 指令的语法与助词符有如下特点:

  • 参数采用从目标( destination )到源( source )的方式

  • 根据字节码的大小与类型不同,一些字节码添加了名称后缀以消除歧义 > > * 32 位常规类型的字节码未添加任何后缀。> > * 64 位常规类型的字节码添加-wide后缀 > > * 特殊类型的字节码根据具体类型添加后缀。它们可以是-boolean、-byte、-char、-short、-int、-long、-float、-double、-object、-string、-class、-void 之一

  • 根据字节码的布局与选项不同,一些字节码添加了字节码后缀以消除歧义。这些后缀通过在字节码主名称后添加斜杠“ / ”来分隔开

  • 在指令集的描述中,宽度值中每个字母表示宽度为 4 位

例如这条指令 move-wide/from16 vAA , vBBBB

  • move 为基础字节码( base opcode )。标识这是基本操作

  • wide 为名称后缀( name suffix )。标识指令操作的数据宽度( 64 位)

  • from16 为字节码后缀(opcode suffix )。标识源为一个 16 位的寄存器引用变量。

  • vAA 为目的寄存器。它始终在源的前面,取值范围为 vo-v255 。

  • vBBBB 为源寄存器。取值范围为 vo-v65535 。

Dalvik 指令集中大多数指令用到了寄存器作为目的操作数或源操作数,其中 A/B/C/ D/E/F/G/H 代表一个 4 位的数值,可用来表示 0 一15的数值或 vo 一 v15 的寄存器,而 AA / BB / CC / DD / EE / FF / GG / HH 代表一个 8 位的数值,可用来表示 0 一 255 的数位或 v0 一 v255 的寄存器, AAAA/BBBB / CCCC / DDDD / EEEE / FFFF / GGGG / HHHH 代表一个 8 位的数值,可用来表示 0 一 65535 的数值或 vo 一 v65535 的寄存器。

0x4Smali 空指令

nop 值为00,用来代码对齐,无用处

0x5Smali 数据操作指令

数据操作指令为move,move指令的原型为move destination,source 或 move destination , move 指令根据字节码的大小与类型不同,后面会跟上不同的后缀.

  • move vA , vB 将 vB 寄存器的值赋给 vA 寄存器,源寄存器与目的寄存器都为 4 位.

  • move vA , vB 将 vB 寄存器的值赋给 vA 寄存器,源寄存器与目的寄存器都为 4 位.

  • move / from 16 vAA , vBBBB 将 vBBBB 寄存器的值赋给 vAA寄存器,源寄存器为16 位,目的寄存器为 8 位.

  • move / 16 vAAAA , vBBBB 将 vBBBB 寄存器的值赋给 vAAAA 寄存器,源寄存器与目的寄存器都为 16 位.

  • move-wide vA , vB 为 4 位的寄存器对赋值.源寄存器与目的寄存器都为 4 位.

  • move-wide/from16 vAA , vBBBB 与 move-wide/16 vAAAA , vBBBB 实现与move-wide相同

  • move-object vA , vB 为对象赋值.源寄存器与目的寄存器都为4位.

  • move-object/from16 vAA , vBBBB 为对象赋值,源寄存器为 16位,目的寄存器为8位.

  • move-object/16 vAAAA,vBBBB 为对象赋值源寄存器与目的寄存器都为 16 位.

  • move-result vAA 将上一个 invoke 类型指令操作的单字非对象结果赋给 vAA 寄存器.

  • move-result-wide vAA 将上一个invoke类型指令操作的双字非对象结果赋给 vAA 寄存器

  • move-result-object vAA 将上一个 invoke 类型指令操作的对象结果赋给 vAA 寄存器.

  • move-excecption vAA 保存一个运行时发生的异常到 vAA 寄存器.这条指令必须是异常发生时的异常处理器的一条指令.否则的话,指令无效.

0x6Smali 返回指令

返回指令指的是函数结尾时运行的最后一条指令.它的基础字节码为retum,共有以下四条返回指令.

  • return-void表示函数从一个void方法返回.

  • return vAA表示函数返回一个32位非对象类型的值,返回值寄存器为8位的寄存器vAA.

  • return-wide vAA表示函数返回一个64位非对象类型的值.返回值为8位的寄存器对vAA.

  • return-object vAA表示函数返回一个对象类型的值.返回值为8位的寄存器vAA.

0x7Smali 数据定义指令

数据定义指令用来定义程序中用到的常量、字符串、类等数据.它的基础字节码为const.
#+X 表示它是一个常量数字,+X 表示它是一个相对指令的地址偏移,kind@X 表示它是一个常量池索引值。

  • const/4 vA,#+B 将数值符号扩展为32位后赋给寄存器vA

  • const/16 vAA,#+BBBB将数值符号扩展为32位后赋给寄存器vAA.

  • const vAA,#+BBBBBBBB 将数值赋给寄存器vAA.

  • const/high16 vAA,#+BBBB0000 将数值右边零扩展为32位后赋给寄存器vAA

  • const-wide/16 vAA,#+BBBB 将数值符号扩展为64位后赋给寄存器对vAA

  • const-wide/32 vAA.#+BBBBBBBB 将数值符号扩展为64位后赋给寄存器对vAA

  • const-wide vAA,#+BBBBBBBBBBBBBBBB 将数值赋给寄存器对vAA.

  • const-wide/high16 vAA,#+BBBB000000000000 将数值右边零扩展为64位后赋给寄存器对vAA

  • const-string vAA,string@BBBB 通过字符串索引构造一个字符串并赋给寄存器vAA.

  • const-string/jumbo vAA,string@BBBBBBBB 通过字符串索引(较大)构造一个字符串并赋给寄存器vAA.

  • const-class vAA,type@BBBB 通过类型索引获取一个类引用并赋给寄存器vAA

  • const-class/jumbo vAAAA,type@BBBBBBBB 通过给定的类型索引获取一个类引用并赋给寄存器vAAAA.这条指令占用两个字节,值为ox00ff(Android4.0中新增的指令)

0x8Smali 锁指令

锁指令多用在多线程程序中对同一对象的操作.Dalvik指令集中有两条锁指令.

  • monitor-enter vAA 为指定的对象获取锁.

  • monitor-exit vAA 释放指定的对象的锁.

0x9Smali 实例操作指令

与实例相关的操作包括实例的类型转换、检查及新建等

  • check-cast vAA,type@BBBB 将vAA寄存器中的对象引用转换成指定的类型,如果失败会抛出ClassCastException异常.如果类型B指定的是基本类型,对于非基本类型的A来说,运行时始终会失败.

  • instance-of vA,vB,type@CCCC 判断vB寄存器中的对象引用是否可以转换成指定的类型,如果可以vA寄存器赋值为1,否则vA寄存器赋值为0.

  • new-instance vAA,type@BBBB 构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器,类型符type指定的类型不能是数组类

  • check-cast/jumbo vAAAA,type@BBBBBBBB 指令功能与check-cast vAA,type@BBBB相同,只是寄存器值与指令的索引取值范围更大(Android4.0中新增的指令)

  • instance-of/jumbo vAAAA,vBBBB,type@CCCCCCCC 指令功能与 instance-of vA,vB,type@CCCC”相同,只是寄存器值与指令的索引取值范围更大(Android4.0中新增的指令)

  • new-instance/jumbo vAAAA,type@BBBBBBBB 指令功能与new-instance vAA,type@BBBB 相同,只是寄存器值与指令的索引取值范围更大(Android4.0中新增的指令).

0x10Smali 数组操作指令

数组操作包括读取数组长度、新建数组、数组赋值、数组元素取值与赋值等操作。

  • array-length vA,vB 获取给定vB寄存器中数组的长度并将值赋给vA寄存器,数组长度指的是数组的条目个数。

  • new-array vA,vB,type@CCCC 构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器。

  • new-array/jumbo vAAAA,vBBBB,type@CCCCCCCC 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大(Android4.0中新增的指令)

  • filled-new-array {vC,vD,vE,vF,vG},type@BBBB 构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还制订了参数的个数,vC~vG是使用到的参数寄存器序列

  • filled-new-array/range {vCCCC, … ,vNNNN},type@BBBB 指定功能与上一条指令相同,只是参数寄存器使用range字节码后缀指定了取值范围,vC是第一个参数寄存器, N=A+C-1。

  • filled-new-array/jumbo {vCCCC, … ,vNNNN},type@BBBBBBBB 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大(Android4.0中新增的指令) fill-array-data vAA, +BBBBBBBB 用指定的数据来填充数组,vAA寄存器为数组引用,引用必须为基础类型的数组,在指令后面会紧跟一个数据表

  • arrayop vAA,vBB,vCC 对vBB寄存器指定的数组元素进入取值与赋值。vCC寄存器指定数组元素索引,vAA寄存器用来寄放读取的或需要设置的数组元素的值。读取元素使用 aget类指令,元素赋值使用aput指令,根据数组中存储的类型指令后面会紧跟不同的指令后缀,指令列表有aget、 aget-wide、aget-object、aget-boolean、aget-byte、aget-char、aget-short、aput、 aput-wide、aput-boolean、aput-byte、aput-char、aput-short。

~点赞加关注学习更多安全知识~

原文始发于微信公众号(小白嘿课):【逆向工程】Android逆向Smali语法(一)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月11日19:24:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【逆向工程】Android逆向Smali语法(一)https://cn-sec.com/archives/884572.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息