如何反编译一个android程序三

前面涉及的技术,其实还没有让我们触及到Android的内部原理,为了更好的掌握Android的运行机制,我们必须深入一些。
先看一张图:
Android系统架构
那么很清楚,Dalvik虚拟机是必须了解的。

3.1 Dalvik虚拟机的特点

概述

  • 体积小,内存占用小
  • DEX文件格式,体积更小,速度更快
  • 常量池32位索引
  • 寄存器架构,拥有指令系统
  • 生命周期管理、堆栈管理、线程管理、安全和异常管理、垃圾回收
  • Android系统进程对应Dalvik虚拟机

Dalvik虚拟机与Java虚拟机区别

大体来说,两者的区别在:字节码,体积,架构。这个不细说,上代码。

public class Hello{
    public int foo(int a, int b){
        return (a+b)*(a-b);
    }
    public static void main(String[] argc){
        Hello hello = new Hello();
        System.out.println(hello.foo(5,3));
    }
}

以上内容存为Hello.java。执行:

javac Hello.java

生成Hello.class文件。执行:

rem dx命令文件和后面用到的dexdump.exe都在android-sdk\build-tools中,原书说是在android-sdk\platform-tools下,自己看吧
dx --dex --output=Hello.dex Hello.class

生成Hello.dex文件。执行:

javap -c -classpath . Hello > java.log

java.log中可以看到如下代码:

  public int foo(int, int);
    Code:
       0: iload_1
       1: iload_2
       2: iadd
       3: iload_1
       4: iload_2
       5: isub
       6: imul
       7: ireturn

使用dexdump,执行以下命令:

dexdump.exe -d Hello.dex > dalvik.log

dalvik.log中有如下代码:

Hello.foo:(II)I
0000: add-int v0, v3, v4
0002: sub-int v1, v3, v4
0004: mul-int/2addr v0, v1
0005: return v0

从上面代码可以清楚看到,java虚拟机的栈架构与dalvik虚拟机的寄存器架构之间的差异。

Dalvik虚拟机如何执行程序

android程序启动流程
上图参考自<<内核剖析>>一书。

Dalvik虚拟机JIT

  • method方式:以函数或方法为单位进行编译
  • trace方式:以trace为单位进行编译

3.2 Dalvik汇编语言

1.Dalvik指令格式

位描述约定:
  • 每16位用空格分开
  • 每个字母表示四位,从高字节开始,排列到低字节,用竖线”|”分割
  • A-Z单个大写字母作为四位操作码,op表示八位操作码
  • “∅”表示所有位均为0
指令格式标识约定:
  • 三个字符,前两位数字,后一位字母
  • 第一个数字表示指令由多少个16位的字组成
  • 第二个数字表示最多使用多少个寄存器,特殊标记’r’
  • 第三个字母为类型码,表示指令用到的额外数据的类型。末尾如果多出一个字母,s表示静态链接,i表示内联处理。
    这里写图片描述
语法约定:
  • 每条指令从操作码开始,后跟参数,参数个数不定,参数之间采用逗号分开。
  • 每条指令的参数从指令第一部分开始,op位于低八位,高八位可以是一个八位参数也可以是两个四位参数,还可以为空,如果指令超过16位,则后面部分依次作为参数。
  • 如果参数采用”vX”的方式表示,表明它是一个寄存器,如v0,v1等。用v不用r,避免与芯片寄存器产生冲突。
  • “#+X”表示常量数字
  • “+X”表示相对指令的地址偏移
  • “kind@X”常量池索引值

2.DEX文件反汇编工具

主流反汇编工具BakSmali与Dedexer。可以在以下地址下载:
https://bitbucket.org/JesusFreke/smali/downloads
https://sourceforge.net/projects/dedexer/files/
下载后,分别运行一下命令:

 java -jar baksmali.jar -o baksmaliout Hello.dex
 java -jar ddx.jar -d ddxout Hello.dex

得到的文件分别是baksmaliout/Hello.dex与ddxout/Hello.ddx,可以比较下差异。后面将采用Smali语法格式。

这里说一下,在第一篇中曾经提到dex2jar工具,其中有许多好用的工具,好好研究。
这里写图片描述

3.Dalvik寄存器

寄存器都是32位,虚拟寄存器范围v0~v65535。

4.两种寄存器表示方法—v命名法与p命名法

p命名法方便判断寄存器是局部变量寄存器还是参数寄存器。

5.Dalvik字节码的类型、方法与字段

  1. 类型
    这里写图片描述
  2. 方法
    格式:
Lpackage/name/ObjectName;->MethodName(III)Z

举个具体例子:

 method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

转成java应该是:

 String method(int, int[][], int, String, Object[])
  1. 字段
    格式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String

3.3 Dalvik指令集

1.指令特点

  • 目标destination到源source
  • 名称后缀:-wide,-boolean,-byte,-char,-short,-int,-long,-float,-double,-object,-string,-class,-void
  • 字节码后缀:/
  • 每个字母4位

2.空操作指令

助记符nop,值00

3.数据操作指令

 //原型: move destination, source

move vA, vB
move/from16 vAA, vBBBB
move/16 vAAAA, vBBBB
move-wide vA, vB
move-wide/from16 vAA, vBBBB
move-object vA, vB
move-object /from16 vAA, vBBBB
move-object/16 vAAAA, vBBBB
move-result vAA
move-result-wide vAA
move-result-object vAA
move-exception vAA

4.返回指令

//基础字节码:return

return-void
return vAA
return-wide vAA
return-object vAA

5.数据定义指令

//基础字节码:const

const/4 vA, #+B
const/16 vAA, #+BBBB

6.锁指令

monitor-enter vAA
monitor-exit vAA

7.实例操作指令

 check-cast vAA, type@BBBB

8.数组操作指令

array-length vA, vB

9.异常指令

throw vAA

10.跳转指令

goto +AA
if-test vA, vB, +CCCC

11.比较指令

cmpkind vAA, vBB, vCC

12.字段操作指令

iinstanceop vA, vB, field@CCCC
sstaticop vAA, field@BBBB

13.方法调用指令

invoke-kind{vC,vD,vE,vF,vG}, meth@BBBB
invoke-kind/range{vCCCC .. vNNNN}, meth@BBBB

14.数据转换指令

unop vA,vB

15.数据运算指令

binop vAA, vBB, vCC

3.4 Dalvik指令集练习

编写smali文件

.class public LHelloWorld;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
.registers 4
.parameter
.prologue

nop
nop
nop
nop
const/16 v0, 0x8
const/4 v1, 0x5
const/4 v2, 0x3

move v1,v2
new-array v0,v0,[I
array-length v1,v0

new-instance v1,Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
if-nez v0, :cond_0 
    goto :goto_0
    :cond_0

int-to-float v2,v2
add-float v2,v2,v2
cmpl-float v0, v2,v2

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

:goto_0

return-void
.end method

以上代码存为HelloWorld.smali文件

编译smali文件

执行命令(注意,此系列博文都会尽量使用前文已经获取的工具,此处就是dex2jar中的工具,以后不再说明了):

 d2j-smali.bat -o classes.dex HelloWorld.smali

生成classes.dex文件,压缩成HelloWorld.zip。

测试运行

运行Android模拟器执行以下命令:

adb push HelloWorld.zip /data/local
adb shell dalvikvm -cp /data/local/HelloWorld.zip HelloWorld

得到输出结果:Hello World!!!!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值