smali 反汇编语言语法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了smali 反汇编语言语法相关的知识,希望对你有一定的参考价值。


前言:

各位同学大家好 最近在学习逆向的知识点, 所以现在就总结写 在学些这篇文章之前我默认 你已经看过我之前出的安卓反编译的基础知识了 如果那个还不会 麻烦可以前面去查阅

如果不会基础的同学可以看 ​​安卓反编译教程​​ 这篇文章

效果图

smali


smali

理论知识

Smali文件

Smali是将android字节码用可阅读的字符串形式 表现出来的一种语言,可以称之为Android字节码的 反汇编语言,即Smali语言是Dalvik的反汇编语言。

作用:

APK文件>dex文件>smali文件>修改代码

结构:

头文件 – 字段 – 方法 和Java类似

Smali数据类型

¨ B----byte
¨ C----char
¨ D----double
¨ F----float
¨ I----int
¨ J----long
¨ S----short
¨ V----void
¨ Z----boolean
¨ [XXX-----array
¨ Lxxx/yyy----object
数组的表示方式是:在基本类型前加上前中括号“[”,例如 [I、[F;
对象的表示则以L作为开头,格式是LpackageName/objectName;
类的表示:LpackageName/objectName;
内部类的表示: LpackageName/objectName$subObjectName;

Smali字段

字段定义:

field public/private [static] [final] varName:<Type>

举例说明(smali -> java):

.field public static HELLO:Ljava/lang/String;
public static String HELLO = "hello";
field private button:Landroid/widget/Button;
private Button button;
field public number:I
public int number =5;

Smali方法

方法定义:

Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type

举例说明( smali -> java 注意:参数与参数之间没有任何分隔符 ):

hello ()V
void hello()
hello (III)Z
boolean hello(int, int, int)
hello (Z[I[ILjava/lang/String;J)Ljava/lang/String;
String hello (boolean, int[], int[], String, long)

Smali方法(smali转java)

smali 代码 示例

.method private static getCount(II)V 
.registers 2
.param p0, "x"
.param p1, "y"
.prologue
.line 28
return-void
.end method

java 代码示例

private static void getCount(int x,int y)

Smali基本语法

field 定义变量
method 方法
parameter 方法参数
prologue 方法开始
line 12 此方法位于第12行
const/high16 v0, 0x7fo3 把0x7fo3赋值给v0
return-void 函数返回void
end method 函数结束
new-instance 创建实例
iput-object 对象赋值
iget-object 调用对象
invoke-static 调用静态函数
invoke-super 调用父函数
invoke-direct 调用函数

Smali跳转语句

"if-eq vA, vB, :cond_\\**" 如果vA等于vB则跳转到:cond_**
"if-ne vA, vB, :cond_\\**" 如果vA不等于vB则跳转到:cond_**
"if-lt vA, vB, :cond_\\**" 如果vA小于vB则跳转到:cond_**
"if-ge vA, vB, :cond_\\**" 如果vA大于等于vB则跳转到:cond_**
"if-gt vA, vB, :cond_\\**" 如果vA大于vB则跳转到:cond_**
"if-le vA, vB, :cond_\\**" 如果vA小于等于vB则跳转到:cond_**
"if-eqz vA, :cond_\\**" 如果vA等于0则跳转到:cond_**
"if-nez vA, :cond_\\**" 如果vA不等于0则跳转到:cond_**
"if-ltz vA, :cond_\\**" 如果vA小于0则跳转到:cond_**
"if-gez vA, :cond_\\**" 如果vA大于等于0则跳转到:cond_**
"if-gtz vA, :cond_\\**" 如果vA大于0则跳转到:cond_**
"if-lez vA, :cond_\\**" 如果vA小于等于0则跳转到:cond_**

Smali函数调用

函数类型:

  1. direct - private函数
  2. virtual - public和protected函数

寄存器:

  1. 本地寄存器用v开头数字结尾的符号来表示,如v0、v1、v2、…
  2. 参数寄存器则使用p开头数字结尾的符号来表示,如p0、p1、p2、…
调用函数:
1. invoke-static
2. invoke-super
3. invoke-direct
4. invoke-virtual

Smali函数调用:invoke-static

invoke-static:
作用:用于调用static函数。
例如:
const-string v0, "NDKLIB"
invoke-static v0, Ljava/lang/System;-
>loadLibrary(Ljava/lang/String;)V
static void System.loadLibrary(String)

Smali函数调用:invoke-super

invoke-direct:
作用:用于调用private函数。
例如:
invoke-direct p0, Landroid/app/TabActivity;-
><init>()V
init()就是定义在TabActivity中的一个private函数

Smali函数调用:invoke-virtual

invoke-virtual:
作用:用于调用protected或public函数。
例如:
sget-object v0, Lcom/dddd;->bbb:Lcom/ccc;
invoke-virtual v0, v1, Lcom/ccc;-
>Messages(Ljava/lang/Object;)V
v0是bbb:Lcom/ccc
v1是传递给Messages方法的Ljava/lang/Object参数

Smali函数返回结果

move-result(返回基本数据类型)
move-result-object(返回对象)
const-string v0, ”Tom"
invoke-static v0, Lcmb/pbi;-
>hi(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2

最后总结

smali语法比较枯燥和难以阅读 同学们一定要耐心去阅读可以自己写一些demo 对照java代码去阅读 smali代码 这样去学习能使我们更快掌握samli的语法 然后才能让我们在实战用修改smali 里面代码逻辑 达到修改和注入的目的 最后希望我都文章能帮助到各位网友的工作和学习 如果你觉得文章还不错麻烦给我三连 关注点赞和转发 谢谢


Smali语法

看阿里巴巴的《深入探索Android热修复》,里面的代码看不懂,一查才知道是Smali语法,百度了语法,转载如下

转载自smali 语言语法

1.smali

apk文件通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件。
smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的。基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行。

2.基本数据类型

B—byte
C—char
D—double
F—float
I—int
S—short
V—void
J—long
Z—boolean

注意J、Z两个不是对应类型的首字母;
在dalvik字节码中,寄存器都是32位的,能够支持任何类型,Long和Double类型是64位的,需要2个寄存器;
V 只能用于返回值类型;

3.数组和对象是引用类型

数组的表示方式是在基本类型前加上前中括号“[”,例如int数组和float数组分别表示为:[I、[F;
对象类型以L作为开头来表示,格式是Lpackage/ClassName;(用分号表示对象结束是必须的),示例:
String对象在smali中为:Ljava/lang/String;
Class1对象的一个boolean成员表示为:Lcom/disney/Class1;->isRunning:Z
Class1对象的一个String对象成员表示为:Lcom/disney/Class1;->name:Ljava/lang/String;
可以总结为格式为对象类型->成员名:成员类型,->表示所属关系,类型尾部必须包括一个分号。
内部类表示为:Lpackage/ClassName$innerObjectName;,也就是在内部类前加“$”符号。

4.函数

格式: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;

5.语法

#标记,构造函数的返回类型为V,名字为<init>

# static fields        定义静态变量的标记
# instance fields      定义实例变量的标记
# direct methods       定义静态方法的标记??
# virtual methods      定义非静态方法的标记??
 .class public Lcom/disney/WMW/WMWActivity;
 .super Lcom/disney/common/BaseActivity;
 .source "WMWActivity.java"
 .implements Lcom/burstly/lib/ui/IBurstlyAdListener;

上面这几行代码表示类名,父类名,源文件名,实现了接口。

.annotation
 内部类
.end annotation

6.局部变量

本地寄存器(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。

7.成员变量和指令

# 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;

8.函数调用

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(),函数GlobalPurchaseHandler 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参数。

9.获取函数调用结果

在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实例。

10.函数体

.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代码的。

11.条件语法

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的流程。

以上是关于smali 反汇编语言语法的主要内容,如果未能解决你的问题,请参考以下文章

smali 反汇编语言语法

Smali代码语法

android反编译-smali语法

smali语法

SMali啥意思?

Android逆向基础知识Smali