android反编译-smali文件语法

原始类型

寄存器与变量

java中变量都是存放在内存中的,android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型,其中/Longdouble64位的,需要使用两个寄存器保存。

寄存器采用vp来命名

v表示本地寄存器

p表示参数寄存器,关系如下

如果一个方法有两个本地变量,有三个参数

v0 第一个本地寄存器

v1 第二个本地寄存器

v2 p0 (this)

v3 p1 第一个参数

v4 p2 第二个参数

v5 p3 第三个参数

当然,如果是静态方法的话就只有5个寄存器了,不需要存this了。

.registers
指定方法中寄存器的总数

.locals
指定表明方法中不是参数寄存器的总数,放在方法的第一行。

名词解释

A

add-int/lit8
用法:

const/16 v30, 0x0
invoke-virtual/range {v17 .. v17}, Ljava/lang/StringBuffer;->length()I
move-result v31
add-int/lit8 v31, v31, -0x1
invoke-virtual/range {v29 .. v31}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v16

定义v31 = 0
v17是某个字符串变量的长度,最终赋给v31
v31将自身-1,再赋给v31,像v31 = v31 - 1 或 v31 = v31 --
v29是一个字符串
截取v29的字符串,最终赋给v16,像这样 v16 = v29.substring(0, v17字符串长度 -1)

aput-object

aput-object v4, v2, v3

v4加入v2的数组中,索引是v3

S

sput-object
将一个对象引用值赋给一个变量
用法:

const-string/jumbo v0, "bec58193ad7a9f2bc143acdb060ecec6"
sput-object v0, Lcom/wangzhi/mallLib/MaMaHelp/base/utils/HttpRequest;->myKey:Ljava/lang/String;

myKey是类的静态变量,一般在构造函数前定义,像这样:

.field public static myKey:Ljava/lang/String;

上面语句最终结果是给myKey静态变量赋值

基本语法

.field private isFlag:z  定义变量

.method  方法

.parameter  方法参数

.prologue  方法开始

.line 12  此方法位于第12行

invoke-super  调用父函数

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

const/4
表示4bit数字,最大15
用法:

const/4 vA, 0xB

const/16
定义一个16位的常量
用法:

const/16 vAA, 0xBBBB

0xBBBB是16进制数字,表示10进制的48059,0x开头的表示16进制
表示16bit数字

const vAA, 0xBBBBBBBB 表示32bit数字

const-string/jumbo
支持的字符串引用数更大,如果dex内字符串数量超过65536,则需要使用 const-string/jumbo

const-string/jumbo vAA, string@BBBBBBBB

invoke-direct  
调用函数

invoke-virtual

如果invoke-virtual出现

invoke-virtual {v0, v1, v2, v3}, Ljavax/crypto/Cipher;->init(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V

这种多了个参数v3的情况是因为long 和 double 类型都是64位的,必须使用两个寄存器来存储。

new-array
定义数组

new-array v1, v1, [B

array-length vA,vB获取vB寄存器中数组的长度并赋值给vA寄存器

array-length v2, v1 //获取v1数组长度,赋值给v2

return-void  函数返回void

.end method  函数结束

new-instance  创建实例

iput-object  对象赋值

iget-object  调用对象

check-cast v0, Landroid/widget/Button; :强制类型转换 mBtn = (Button) findViewById(R.id.btn);

move-result
返回基本数据类型v1
用法:

move-result v1

move-result-object
返回对象

from16
字节码后缀(opcode suffix),标示源(vBBBB)为一个16的寄存器引用变量

//保存到的寄存器,变量所属的实例所在寄存器,某个类某个类型的变量
iget-object v0, p0(this), Lxx/xx/Xx;->memberInstanceVariable:type 

iget-object的作用是:iget-object vx,vy,field_id,Reads an object reference instance field into vx. The instance is referenced by vy。翻译过来就是vx = vy.field_id,那么上面这句话的意思就是 v1 = this.b 这个b是javax.crypto.spec.SecretKeySpec的一个对象(可以想想到,在这个类中会有这么一句话SecretKeySpec b;)

invoke-static  调用静态函数

方法和字段

方法签名

methodName(III)Lpackage/name/ObjectName;

如果做过ndk开发的对于这样的签名应该很熟悉的,就是这样来标识一个方法的。

上面methodName标识方法名,III表示三个整形参数,Lpackage/name/ObjectName;表示返回值的类型。

方法

Lpackage/name/ObjectName;——>methodName(III)Z
package.name.ObjectName中的 function boolean methondName(int a, int b, int c) 类似这样子

字段

Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;
即表示: 包名,字段名和各字段类型

逻辑判断

if-eqz
if equels zero 缩写,判断是否等于0
用法:

//如果vA等于0则跳转到:cond_**
if-eqz vA, :cond_**"

运算

java 与 smali 源码对比

java

public class smaliTest {
       public static void main(String[] args){
           System.out.println("hello smali");
       }
   }

smali

.class LsmaliTest;
.super Ljava/lang/Object;
.source "smaliTest.java"

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

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

    return-void
.end method

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

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

    const-string v1, "hello smali"

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

    .line 6
    return-void
.end method

requests.get() 获取返回的html内容

res = requests.get(url)
print res.text

move-object/from16
移动对象引用,从vy到vx。vy可以处理64K寄存器地址,vx可以处理256寄存器地址。
用法:

move-object/from16 v0, v26

将v26的对象赋给v0

invoke-static/range

英译中

registers
寄存器

特殊字符

L结尾的类名
像这样Ljava/lang/StringBuffer,这里的L表示java/lang/StringBuffer接口

[开头
表示数组
像这样[Ljava.lang.Object;,表示该对象返回数组

将logcat代码植入smali文件

const-string v5, "iwillseeyou"
invoke-static {v5, v0}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I

v5是tag,v0是要打印的string,v5的变量名称要看.locals 5是多少,如果是4,那只能最多4个缓存器,那v5要改成v4

参考:
http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html