特点
Smali汇编指令特点:
参数操作从目标到源的顺序(类似x86汇编)
根据字节码的类型和大小,添加后缀消除歧义
64位常规字节码添加-wide
特殊字节码添加具体类型
基于寄存器操作,不存在传统汇编的栈操作,没有pop,push
每个寄存器均为32位,64位数据类型用连续两个寄存器存储表示
基本类型
V void (只能用于返回值类型)
Z boolean
B byte
S short
C char
I int
J long
F float
D Double
数据类型
对象类型
表示方法:L包名+类名;(L;作为起始结束符)
eg:
java.lang.String
Ljava/lang/String;
com.example.applicationandjni.MainActivity
Lcom/example/applicationandjni/MainActivity;
数组表示,类型前面加[
int[] --> [I
Int[][] --> [[I
String[] --> Ljava/lang/String;
方法的表示形式:
Lpackage/name/ObjectName;——>methodName(III)Z 详解如下:
Lpackage/name/ObjectName 表示类型
methodName 表示方法名
III 表示参数(这里表示为3个整型参数)
字段的表示形式:
Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;表示: 包名,字段名和各字段类型
寄存器
有两种方式指定一个方法中有多少寄存器是可用的:
.registers 指令指定了方法中寄存器的总数
.locals 指令表明了方法中非参寄存器的总数,出现在方法中的第一
方法的传参:
当一个方法被调用的时候,方法的参数被置于最后N个寄存器中;
例如,一个方法有2个参数,5个寄存器(v0~v4)
那么,参数将置于最后2个寄存器(v3和v4)
非静态方法中的第一个参数总是调用该方法的对象;一般都为p0
说明:对于静态方法除了没有隐含的this参数外,其他都一样
常用命令法V和P
v表示本地寄存器,p表示参数寄存器
eg:一个方法有两个局部变量,三个参数
v0 v0第一个本地寄存器
v1 v1第二个本地寄存器
v2 p0 (this)
v3 p1 第一个参数
v4 p2 第二个参数
v5 p3 第三个参数
V命名法和P命名法的比较:使用P命名是为了防止以后如果在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点
再次强调:Long和Double类型是64位的,需要2个寄存器
例如:对于非静态方法
LMyObject——>myMethod(IJZ)V;
有4个参数:LMyObject,int,long,bool; 需要5个寄存器来存储参数;
P0 this
P1 I (int)
P2,P3 J (long)不能分开用,因为JAVA解释执行,没有这种
P4 Z(bool)
smali文件
头部
.class public Lcom/example/applicationandjni/MyApplication;
.super Landroid/app/Application;
.source "MyApplication.java"
.field
成员变量(静态,非静态)
.method
成员方法
其他
通过读dex确定的smali文件结构。
字段声明表示
public static aa:F
作用域 变量名:变量类型
方法声明表示:
public pri_method(ILjava/lang/String;)Ljava/lang/String;
作用域 方法名(参数类型)返回值类型
public 、protected声明
invoke-virtual(因为继承,有重载)
private声明
invoke-direct
Static声明
invoke-static
调用父类方法
invoke-super
所有smali汇编调用的方法没有默认返回值比如x86/64的eaxrax,必须要调用一个move-result-object/其他类型 vx
Demo
下面分析一个汇编demo,先变成class,再变成dex,将dex,用baksmali解包
像那些R$的都是一些资源文件。跟资源文件耦合。
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.registers 6
.param p1, "savedInstanceState" # Landroid/os/Bundle;p0传的是this
.prologue
.line 51
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 52
const/high16 v0, 0x7f030000
invoke-virtual {p0, v0}, Lcom/example/testtype/MainActivity;->setContentView(I)V
.line 54
const/4 v0, 0x1
const-string v1, "1"
invoke-virtual {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pub_method(ILjava/lang/String;)V
.line 55
const/4 v0, 0x2
const-string v1, "2"
invoke-virtual {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pro_method(ILjava/lang/String;)I
.line 56
const/4 v0, 0x3
const-string v1, "3"
invoke-direct {p0, v0, v1}, Lcom/example/testtype/MainActivity;->pri_method(ILjava/lang/String;)Ljava/lang/String;
.line 58
const/4 v0, 0x4
const-string v1, "4"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pub_static_method(ILjava/lang/String;)V
.line 59
const/4 v0, 0x5
const-string v1, "5"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pro_static_method(ILjava/lang/String;)I
.line 60
const/4 v0, 0x6
const-string v1, "6"
invoke-static {v0, v1}, Lcom/example/testtype/MainActivity;->pri_static_method(ILjava/lang/String;)Ljava/lang/String;
.line 62
const-wide/16 v0, 0xa#long
iput-wide v0, p0, Lcom/example/testtype/MainActivity;->a:J #看起来用了v0,实际上是v0v1,因为是long
.line 63
const/16 v0, 0x14
iput v0, p0, Lcom/example/testtype/MainActivity;->b:I
.line 64
const/high16 v0, 0x41f00000 # 30.0f
sput v0, Lcom/example/testtype/MainActivity;->aa:F
.line 65
const-wide/high16 v0, 0x4044000000000000L # 40.0
sput-wide v0, Lcom/example/testtype/MainActivity;->bb:D
.line 67
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;#java特性,字符串不可变,将2个字符串相加先newstringbuild,然后拼接起来,然后tostring
iget-wide v2, p0, Lcom/example/testtype/MainActivity;->a:J
invoke-static {v2, v3}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;#java/lang/String类的valueOf方法传入一个Jlong型,返回字符串型。
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V#两个参数第一个参数相当于this是个对象,第二个参数是含参的构造函数,就是new一个对象,先new对象,上面的函数,再调用他的构造函数
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;//掉stringbuilder转成String
move-result-object v1#生成strign给v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 68
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
iget v2, p0, Lcom/example/testtype/MainActivity;->b:I
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 69
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
sget v2, Lcom/example/testtype/MainActivity;->aa:F
invoke-static {v2}, Ljava/lang/String;->valueOf(F)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 70
const-string v0, "MF"
new-instance v1, Ljava/lang/StringBuilder;
sget-wide v2, Lcom/example/testtype/MainActivity;->bb:D
invoke-static {v2, v3}, Ljava/lang/String;->valueOf(D)Ljava/lang/String;
move-result-object v2
invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 71
return-void
.end method
.method protected pro_method(ILjava/lang/String;)I
.registers 7
.param p1, "n" # I
.param p2, "tag" # Ljava/lang/String;
.prologue
.line 21
mul-int/lit8 v0, p1, 0x2
.line 22
.local v0, "m":I
const-string v1, "MF"
new-instance v2, Ljava/lang/StringBuilder;
invoke-static {p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v3
invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
const-string v3, ": "
invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v2
invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 23
return v0
.end method
.method public pub_method(ILjava/lang/String;)V
.registers 7
.param p1, "n" # I
.param p2, "tag" # Ljava/lang/String;
.prologue
.line 16
mul-int/lit8 v0, p1, 0x2
.line 17
.local v0, "m":I
const-string v1, "MF"
new-instance v2, Ljava/lang/StringBuilder;
invoke-static {p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v3
invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
const-string v3, ": "
invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v2
invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 18
return-void
.end method
第二个pro_method逆向写伪代码如下
package com.example.testtype
class Mainactivity extends Activity{
protected int pro_method(int n,String tag)
{
int v0=n*0x2;
string v1="MF";
String v3=String.valueOf(tag);
SrtringBuilder v2=new StringBuilder(v3);
v3=":";
v2=v2.append(v3);
v2=v2.append.(v0);
String v2=v2.toString();
log.i(v1,v2);
return v0;
//其实这些代码再java里就是
int m=n*0x02;
Log.i("MF",tag+":"+m);
return m;
}
}
之所以要逆smali代码,因为是如果是大数组,jeb反编译回是空,不是正常的。只能看smali汇编。