工欲善其事必先利其器,所以想做好一件事情,务必准备一个好的工具。
这里推荐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