Smali语言入门

    工欲善其事必先利其器,所以想做好一件事情,务必准备一个好的工具。

    这里推荐Java2Smali这个UI工具,CSDN里面搜得到。

    首先 了解一下什么是Smali,相信玩过逆向的朋友,使用ApkTool反编译AP后打开Src目录里面全部都是.smali文件。

    这个时候还需要一个工具叫Smali2Java这个工具,他可以直接将smali解释成Java。所以整个过程中我们都没怎么留意它,这边之所以提及它是应为如果能够使用静态分析的方式直接修改smali文件,就可以省去反编译又回编译的繁琐过程,有时候工具也不是万能的,他也会崩溃,效果也会差强人意,多说无益,自己体会就知道了。

    这边直接使用J2S2J v13 这个是吾爱破解上面的发布的一个Smali Java互转GUI工具,有了这个你的学习将事半功倍。

先上段代码

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

经过转换

.class public LTest;
.super Ljava/lang/Object;
.source "Test.java"

# direct methods
.method public constructor <init>()V
    .registers 1


    .prologue
    .line 1
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V


    return-void
.end method


.method public static main([Ljava/lang/String;)V
    .registers 3


    .prologue
    .line 3
    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;


    const-string v1, "Hello World!"


    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V


    .line 4
    return-void
.end method


首先 申明文件名 类名 以及 他的父类

.class public LTest;
.super Ljava/lang/Object;
.source "Test.java"

这个当然是构造函数了

# direct methods
.method public constructor <init>()V
    .registers 1


    .prologue
    .line 1
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V


    return-void
.end method

关于 direct methods 和 virtual methonds 

invoke-virtual 或 invoke-virtual/range 调用实例的虚方法
invoke-super 或 invoke-super/range 调用实例的父类方法
invoke-direct 或 invoke-direct/range 调用实例的直接方法

也就是说direct是该Java文件中的方法

而virtual则是其父类中的override方法

而super则是其父类中的protected方法(没有被重写)

https://www.cnblogs.com/larrylawrence/p/3985464.html

关于init 和client的区别 就是static的区别了 

http://www.cnblogs.com/diyunpeng/archive/2010/07/11/1775200.html

这里的V是Void的意思 这里有一些基本的参数类型

1、原始类型
V void (只能用于返回值类型) 
Z boolean
B byte
S short
C char
I int
J long(64位)
F float
D double(64位)

https://blog.csdn.net/hp910315/article/details/51823236

关于 registers  prologue

.locals 局部变量个数 
.parameter 参数个数,每条指令声明一个参数 
.prologue 代码开始 
.line 行号

https://blog.csdn.net/junjunyanyan/article/details/45726775

现在看看main函数

.method public static main([Ljava/lang/String;)V
    .registers 3

    .prologue
    .line 3
    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;

    const-string v1, "Hello World!"

    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    .line 4
    return-void
.end method

第一行 .method 申明方法 还是可以查看这里 https://blog.csdn.net/lostinai/article/details/48975661

sget-object  这是获取指令 获取out这个实例存入寄存器v1当中 可参考 https://www.cnblogs.com/linwx/p/7965893.html

1.sget-object v0, Lcom/aaa;->ID:Ljava/lang/String;
sget-object就是用来获取变量值并保存到紧接着的参数的寄存器中
本例中,它获取ID这个String类型的成员变量并放到v0这个寄存器中。

当中有一段写的特别好 那么这个p0在构造函数中也就是this的意思。

三.寄存器
  本地寄存器用v开头数字结尾的符号来表示,如v0、v1、v2、...

  参数寄存器则使用p开头数字结尾的符号来表示,如p0、p1、p2、...

注意:p0不一定是函数中的第一个参数,在非static函数中,p0代指“this”,p1表示函数的第一个参数,p2代表函数中的第二个参数…而在static函数中p0才对应第一个参数(因为Java的static方法中没有this方法。      

简单分析:
const/4 v0, 0x1
iput-boolean v0, p0, Lcom/aaa;->IsRegistered:Z
上面两句smali代码,首先使用本地v0寄存器,并将0x1存到v0中,然后第二句用iput-boolean这个指令把v0中的值存放到com.aaa.IsRegistered这个成员变量中。

相当于:this.IsRegistered=v0;

最后的输出语句即为:v0 代表 out  v1 代表 字符串“hello world” 我们可以这样理解v0代表实例 后面统一为参数。

invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

这边我们具体研究 该方法

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.getname("12",22);
    }
    public  void getname(String age ,int nice){

    }
}

编译之后生成smail代码

.class public LTest;
.super Ljava/lang/Object;
.source "Test.java"


# direct methods
.method public constructor <init>()V
    .registers 1

    .prologue
    .line 1
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

.method public static main([Ljava/lang/String;)V
    .registers 4

    .prologue
    .line 4
    new-instance v0, LTest;

    invoke-direct {v0}, LTest;-><init>()V

    .line 
    const-string v1, "12"

    const/16 v2, 0x16

    invoke-virtual {v0, v1, v2}, LTest;->getname(Ljava/lang/String;I)V

    .line 6
    return-void
.end method


# virtual methods
.method public getname(Ljava/lang/String;I)V
    .registers 3

    .prologue
    .line 9
    return-void
.end method

看下面这里  :

v0 存Test实例

v1 存字符串“12”

v2 存 22 也就是0x16

关于 invoke-virtual 和 invoke-direct 上面做过解释,可能理解有误 暂时当一个意思。

这里涉及到一些基本语法直接粘贴出来

Smali基本语法
.field private isFlag:z  定义变量

.method  方法

.parameter  方法参数

.prologue  方法开始

.line 12  此方法位于第12行

invoke-super  调用父函数

const/high16  v0, 0x7fo3  把0x7fo3赋值给v0

invoke-direct  调用函数

return-void  函数返回void

.end method  函数结束

new-instance  创建实例

iput-object  对象赋值

iget-object  调用对象

invoke-static  调用静态函数

new-instance v0, LTest;

    invoke-direct {v0}, LTest;-><init>()V

    .line 
    const-string v1, "12"

    const/16 v2, 0x16

    invoke-virtual {v0, v1, v2}, LTest;->getname(Ljava/lang/String;I)V

这个就好理解了 即:调用v0(test)的getname函数 参数为v1 v2

参数用;隔开 分别为String 和 int 类型,返回值为空。

# virtual methods
.method public getname(Ljava/lang/String;I)V
    .registers 3

    .prologue
    .line 9
    return-void
.end method

给出smail基本类型 https://blog.csdn.net/lpohvbe/article/details/7981386

 一、smali的数据类型

在smali中,数据类型和Android中的一样,只是对应的符号有变化:

B---byte
C---char
D---double
F---float
I---int
J---long
S---short
V---void
Z---boolean
[XXX---array
Lxxx/yyy---object



猜你喜欢

转载自blog.csdn.net/qq_20330595/article/details/80979939